Programming Language/go

Go 언어 프로그래밍 - 함수 고급편

김크리 2021. 7. 21. 23:02

『Tucker의 Go 언어 프로그래밍』 스터디 요약 노트입니다.


가변 인수 함수

...키워드 사용 하여 배열인자로 받아 올 수 있다.

package main

import (
	"fmt"
)

func sum(nums ...int) int {
	sum := 0
	fmt.Printf("nums type : %T\n", nums)
	for _, v := range nums {
		sum += v
	}
	return sum
}

func main() {
	fmt.Println(sum(1, 2, 3, 4, 5))
	fmt.Println(sum(10, 20))
	fmt.Println(sum())
}
//fmt.Println 함수를 참고해보자(아래)
//빈 인터페이스(interface{})를 가변인자로 받는다.
//이전 수업시간에 빈인터페이스는 모든 타입을 받는다는 것을 배웠다.
//가변인자와 빈 인터페이스로 고급 함수사용법을 알 수 있다.
func Print(a ...interface{})(n int, err error) {
	return Fprintln(os.Stdout, a...)
}

defer 지연 실행

defer 명령문

  • 함수 종료 전에 실행을 보장한다.
  • 주로 OS 자원을 반납할때 사용한다.
  • 프로그램에서 파일 작업을 시작할 때, OS에 File Handler(OS 자원 중 하나) 를 요청한다. 
  • 작업이 완료하고 이 File Handler 요청한 것을 반드시 반환해야한다.
  • defer 는 FIFO 구조이다.(Stack)

함수 타입 변수

함수 타입 변수란 함수를 값으로 갖는 변수

어떻게 함수를 값으로 갖을 수 있을까?

  • 함수의 시작위치 = 함수의 주소

즉, 함수도 숫자로 표현 가능하다. 숫자이기 때문에 변수처럼 값으로 가질 수 있다.

함수 타입은 함수 시그니쳐로 표현할 수 있다.

//함수
func add(a, b int) int{
	return a+b
}
//함수 시그니쳐
func(int, int) int
package main

import (
	"fmt"
)

func add(a, b int) int {
	return a + b
}
func mul(a, b int) int {
	return a * b
}

//func(int, int) int 타입의 함수를 반환하는 함수
func getOperator(op string) func(int, int) int {
	if op == "+" {
		return add
	} else if op == "*" {
		return mul
	} else {
		return nil
	}
}
func main() {
	//함수 타입의 변수 생성
	var operator func(int, int) int
	operator = getOperator("+")

	var result = operator(3, 4)
	fmt.Println(result)
}

함수 리터럴(람다)

일반 함수는 상태(State)를 가질 수 없지만 함수 리터럴은 내부 상태를 가질 수 있다.(First Class)

함수 리터럴에서 외부 함수의 상태를 가져오는 것(캡쳐)는 값 복사가 아닌 레퍼런스 복사이다. 즉, 포인터가 복사되는 것이다.

package main

import (
	"fmt"
)

type OpFn func(int, int) int

//함수 리터럴 사용
func getOperator(op string) OpFn {
	if op == "+" {
		return func(a, b int) int {
			return a + b
		}
	} else if op == "*" {
		return func(a, b int) int {
			return a * b
		}
	} else {
		return nil
	}
}
func main() {
	//함수 타입의 변수 생성
	var operator OpFn
	operator = getOperator("+")

	var result = operator(3, 4)
	fmt.Println(result)
}
package main

import (
	"fmt"
)

func main() {
	i := 0
	//함수 리터럴
	f := func() {
    	//변수 상태를 가져온다 = 외부 변수의 상태를 가져와(캡쳐) 사용할 수 있다.
		i += 10
	}
	i++
    //함수 리터럴로 선언한 함수 호출
	f()
	//11 출력
	fmt.Println(i)
}

의존성 주입

외부에서 로직을 주입하는 것을 의존성 주입이라고 한다.

package main

import (
	"fmt"
	"os"
)

type Writer func(string)

func writeHello(writer Writer) {
	writer("Hello world2")
}

func main() {
	f, err := os.Create("test.txt")
	if err != nil {
		fmt.Println("Faled to create a file")
		return
	}
	defer f.Close()

	writeHello(func(msg string) {
		fmt.Fprintln(f, msg)
	})
}

 

 

 

참고

Tucker의 Go언어 프로그래밍 - Go가 온당

https://www.youtube.com/c/TuckerProgramming/videos