• Home
  • About
    • Jiwon Jeong photo

      Jiwon Jeong

      끊임없이 배우며 성장하는 엔지니어

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
    • All Categories
  • Projects

Go Lang 특성

06 Dec 2021

Reading time ~3 minutes

  • 참고사이트 : https://ssipflow.github.io/go/GO-function/

Go lang 특성 정리

  • Go 언어는 값에 의한 호출 (Call by value) 만을 지원한다.
  • 함수 내에서 넘겨받은 변수값을 변경하더라도 함수 밖의 변수에는 영향을 주지 않는다.
  • 따라서 함수 밖의 변수의 값을 변경하려면 해당 값이 들어있는 주소값을 넘겨받아, 그 주소에 있는 값을 변경하여 참조에 의한 호출 (Call by reference)을 비슷하게 구현할 수 있다.

값 넘겨주기

  • Call by Rerference와 Call by Value의 차이 이해
func CallByValue(num int) {
	num++
}

func CallByReference(num *int) {
	*num++
}

func main() {
    i := 3
    
    CallByValue(i)
    fmt.Println(i)  // 3
    
    CallByReference(&i)
    fmt.Println(i)  // 4
}
  • CallByValue는 전달받은 i의 값이 함수의 인자 num에 복사된다. 그래서 main 함수의 i가 아닌 CallByValue 함수 안에서만 값이 변경된다.
  • CallByReference는 전달받은 i의 주소가 가리키는 값을 변경한다. 함수 외부의 값을 변경할 수 있다.

  • Slice와 Map 자료형은 Call by Value를 쓰는게 아닌, Call by Referecne를 사용함
func SliceAddOne(s []int) {
    for i := range s {
        s[i]++
    }
}

func MapAddOne(m map[int]int) {
    for k, _ := range m {
        m[k]++
    }
    
    /*
    for _, v := range m {
        v++
        // 이 경우 m의 주소값이 가리키는 이 변하지 않는다.
    }
    */
}

func main() {
    n := []int{1, 2, 3, 4}
    SliceAddOne(n)
    fmt.Println(n)	// [2 3 4 5]

    m := map[int]int{
        1: 1,
        2: 2,
        3: 3,
        4: 4,
        5: 5,
	}
    MapAddOne(m)
    fmt.Println(m)	// map[1:2 2:3 3:4 4:5 5:6]
}

둘 이상의 반환값

  • 일반적으로 에러값을 반환할 때 많이 사용하고, 둘 이상의 값을 반환할 때는 반환 타입을 괄호로 둘러싼다.
func WriteTo(w io.Writer, lines []strings) err { ... return err }
func WriteTo(w io.Writer, lines []strings) (int64, err) { ... return n, err }

다중 리턴

func MultiReturnSample() (msg1, msg2 string) {
    msg1 = "Hello"
    msg2 = "World"
    return
}

func main() {
    m1, m2 := MultiReturnSample()
    fmt.Println(m1, m2)	// Hello World
}

_ (언더바)의 사용

  • 둘 이상의 반환값이 있을 때, 필요없는 변수의 경우 언더바( _ )를 이용하면 된다.
_, err := WriteTo(w, lines)
  • 반복문 요소를 끄집어낼 때, 인덱스만 뽑아내기 => _를 뒤에!!

// Example 배열 요소를 순차적 방문(ragne 키워드 이용)
package main
 
import "fmt"
 
func main() {
	arr := [5]int{12, 34, 23, 56, 34}
 
	for value, _ := range arr {
		fmt.Println(value) // 0 1 2 3 4
	}
}
  • 만약 인덱스를 생략하고 원소 값만을 얻고자 한다면 => _를 앞에!
package main
 
import "fmt"
 
func main() {
	arr := [5]int{12, 34, 23, 56, 34}
 
	for _, value := range arr {
		fmt.Println(value) // 0 1 2 3 4
	}
}

에러값 주고 받기

  • GO에서는 둘 이상의 값을 반환할 수 있기 때문에 여러 반환값 중 마지막 값에 에러를 반환
  • GO는 다음과 같은 방식으로 예외를 처리하면서 에러를 반환
func Sample() (int, error) {
    if err := MyFunc(); err != nil {
        ...
        return nil, err
    }
    ...

  • 새로운 에러를 생성해야 하는 경우
    • errors.New 와 fmt.Errorf 를 이용하여 문자열 메시지를 줄 수 있다
return erros.New("stringlist.ReadFrom: line is too long")

// 다른 부가 정보를 추가한 메시지를 돌려줄 수 있다.
// 다음은 몇 번쨰 줄이 너무 긴지, 에러 메시지를 포함한다.
return fmt.Errorf("stringlist: too long line at %d", count)

가변인자 넘겨받기

  • 갯수를 모르는 상태에서 자료형이 같은 인자를 함수에 전달
func SliceParams(nums []int) {
    fmt.Println("slice parameter")
    for _, num := range nums {
        fmt.Print(num, " ")
    }
    fmt.Println()
}

func VariableParams(nums ...int) {
    fmt.Println("variable parameter")
    for _, num := range nums {
        fmt.Print(num, " ")
    }
    fmt.Println()
}

func main() {
    nums := []int{1, 2, 3, 4, 5}

    SliceParams([]int{1, 2, 3, 4, 5}) // 1 2 3 4 5
    VariableParams(1, 2, 3, 4, 5) // 1 2 3 4 5

    // 슬라이스 하나를 넘기면 그 슬라이스 하나를 담고 있는 슬라이스로 만들어 넘겨주기 때문에 점 셋을 붙여 슬라이스를 가변인자로 전달 가능 하다.
    VariableParams(nums...) // 1 2 3 4 5
}

함수 리터럴

  • 이름이 없는 순수한 함수의 값 (익명함수)
// add 함수
func add(a, b int) int {
    return a + b
}

// 함수리터럴
func (a, b int) int {
    return a + b
}
  • 이러한 리터럴은 변수에 전달하여 변수를 함수처럼 사용가능!
func Example_funcLiteralVal() {
    printHello := func() {
        fmt.Println("Hello!")
    }
    printHello()    // Hello!
}


개발일기 Share Tweet +1