개발/GO

[Golang] 함수 정의

피클s 2022. 3. 31. 10:49

이 글은 https://golangbyexample.com/function-golang-complete-guide/을 번역 및 재가공하여 작성하였습니다.

 

목차

     

    1. 기본문법

    1-1. 제약조건

    1. 함수명은 숫자로 시작할 수 없습니다.
    2. 대소문자를 구별합니다.
    3. 대문자로 시작하는 함수는 외부에서 불러올 수 있습니다.

     

    1-2. 형태

    func 함수명(파라메터) 반환값 {
        // 내용
    }

     

    2. parameter

    파라메터 뒤에는 타입을 적어야 합니다.

    func sum(a int, b int) int {
      return a + b 
    }

     

    같은 타입인 경우 생략할 수 있습니다.

    func sum(a, b int) int {
      return a + b 
    }

     

    3. return

    return값은 복수일 수 있으며 아래와 같이 받을 수 있습니다.

    여러 값을 return한다면 괄호는 필수입니다.

    func sum(a, b int) (int, error) {
        return a + b, nil
    }
    
    result, err := sum(1, 2)

     

    4. named return

    func sum(a, b int) (result int) {
        result = a + b
        return
    }

    return 할 변수명을 미리 지정하고 사용할 수 있습니다.

    이때 return은 아무런 값도 넣지않습니다.

    괄호는 필수입니다.

     

    5. function의 type

    Go언어에서는 함수 타입을 선언할 수 있습니다.typescript와 유사하군요.아래의 조건이 일치하다면 두 함수는 같은 타입입니다.

    • 같은 수의 파라메터를 가지며 같은 타입인 경우
    • 같은 수의 return값과 return값이 같은 타입인 경우
    package main
    
    import "fmt"
    
    func main() {
        areaF := getAreaFunc()
        print(3, 4, areaF)
    }
    
    type area func(int, int) int
    
    func print(x, y int, a area) {
        fmt.Printf("Area is: %d\n", a(x, y))
    }
    
    func getAreaFunc() func(int, int) int {
        return func(x, y int) int {
            return x * y
        }
    }

     

    6. value로써의 function

    함수를 변수에 담을 수 있습니다.

    JS를 보는 것 같군요.

    package main
    
    import "fmt"
    
    var max = func(a, b int) int {
        if a >= b {
            return a
        }
        return b
    }
    
    func main() {
        res := max(2, 3)
        fmt.Println(res)
    }

     

    7. closure

    클로저를 말로 설명하면 이게 무슨 개소리인가 라고 느껴질겁니다.

    함수 안의 함수가 외부 함수의 변수를 사용하는 것이 클로저입니다.

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        modulus := getModulus()
        modulus(-1)
        modulus(2)
        modulus(-5)
    }
    
    func getModulus() func(int) int {
        count := 0
        return func(x int) int {
            count = count + 1
            fmt.Printf("modulus function called %d times\n", count)
            if x < 0 {
                x = x * -1
            }
            return x
        }
    }
    modulus function called 1 times
    modulus function called 2 times
    modulus function called 3 times

    modulus를 실행할 때 count를 공유하고 있습니다! 

     

     

    8. 고차함수(Higher Order Function)

    고차함수는 함수를 다루는 함수입니다.

    함수를 파라메터로 받아들이거나 return한다면 그것이 고차함수입니다.

    package main
    
    import "fmt"
    
    func main() {
        areaF := getAreaFunc()
        print(3, 4, areaF)
    }
    
    func print(x, y int, area func(int, int) int) {
        fmt.Printf("Area is: %d\n", area(x, y))
    }
    
    func getAreaFunc() func(int, int) int {
        return func(x, y int) int {
            return x * y
        }
    }

    함수를 return하는 getAreaFunc

    함수를 파라메터로 받아들이는 print

     

    9. 즉시 실행 함수(IIF, Immediately Invoked Function)

    선언과 동시에 실행되는 함수입니다.

    package main
    
    import "fmt"
    
    func main() {
        squareOf2 := func() int {
            return 2 * 2
        }()
        fmt.Println(squareOf2)
    }

    squareOf2는 값 4를 가지고 있습니다.

     

    언제 사용될까요?

    패키지 내부 또는 외부에 함수의 논리를 노출하지 않고 싶을때 사용한다고 합니다.

     

    10. 가변 함수

    동적인 파라메터를 받아들일 수 있는 함수입니다.

    package main
    
    import "fmt"
    
    func main() {
        fmt.Println(add(1, 2))
        fmt.Println(add(1, 2, 3))
        fmt.Println(add(1, 2, 3, 4))
    }
    
    func add(numbers ...int) int {
        sum := 0
        for _, num := range numbers {
            sum += num
        }
        return sum
    }

     

    11. 메서드(method)

    function이 아니고 method입니다.

    프로그램 언어에 따라서 함수를 function 또는 method라고 부르는데 Go언어에서는 이 두 용어의 쓰임새가 다릅니다.

    method는 struct의 함수 입니다.

    객체지향 언어를 사용해보신 분은 객체의 기능에 해당한다고 생각하시면 됩니다.

    리시버에 포인터타입 사용하는 것과 일반 타입을 사용하는 것에는 큰 차이가 있습니다.

    포인터 타입을 사용하는 경우 객체의 값을 직접 수정할 수 있습니다.

    일반 타입을 사용하는 경우 객체의 값을 복사해오기 때문에 본체에 영향을 줄 수 없습니다.

     

    선언 방법은 아래와 같습니다.

    func (리시버 리시버타입) 함수명(파라메터) 반환값 {...}
    package main
    
    import "fmt"
    
    func main() {
    	awesome := people{name: "awesome guy"}
    	awesome.cook()
    }
    
    type people struct {
    	name string
    }
    
    func (p people) cook() {
    	fmt.Println("싹뚝싹뚝 보글보글")
    }