아래는 클로저를 사용하여 생성기(generator)를 만든 예제입니다.

package main
import (
	"fmt"
)
func NewIntGenerator() func() int {
	var next int
	return func() int {
		next++
		return next
	}
}
func main() {
	gen := NewIntGenerator()
	fmt.Println(gen(), gen(), gen(), gen(), gen())
	fmt.Println(gen(), gen(), gen(), gen(), gen())
}
// 결과
// 1 2 3 4 5
// 6 7 8 9 10

NewIntGenerator()는 함수를 반환하는 고계함수입니다. 또한 이 함수가 반환하는 함수는 클로저입니다. 반환하는 함수 리터럴(람다함수 형태처럼 보이는 함수)이 속해 있는 스코프 안에 있는 next 변수에 접근하고 있습니다. 그러면 이 함수는 next 변수와 함께 세트로 묶입니다. 만약 NewIntGenerator()를 여러 번 호출하여 함수를 여러 개를 갖고 있으면 각각의 함수가 갖고 있는 next는 따로 분리되어 있습니다. 한마디로 gen이라는 변수안에 NewIntGenerator() 함수를 담고 있기 때문에 gen변수를 계속 호출하면 반환되는 함수 리터럴과 함께 세트로 묶여있는 next 변수의 값이 증가하게 됩니다. 만약 NewIntGenerator()()와 같이 따로 호출을 반복하면 next의 값은 1만 나오게 됩니다.


package main
import (
	"fmt"
)
func NewIntGenerator() func() int {
	var next int
	return func() int {
		next++
		return next
	}
}
func main() {
	gen := NewIntGenerator()
	gen2 := NewIntGenerator()
	fmt.Println(gen(), gen(), gen(), gen(), gen())
	fmt.Println(gen2(), gen2(), gen2(), gen2(), gen2())
	fmt.Println(gen(), gen(), gen(), gen(), gen())
}


// 결과
// 1 2 3 4 5
// 1 2 3 4 5
// 6 7 8 9 10

위 코드에서 gen과 gen2에 세트로 묶여 있는 next는 서로 다릅니다. 그렇기 때문에 gen을 호출하여 증가시킨 숫자와 gen2를 호출하여 증가시킨 숫자는 서로 다릅니다. gen, gen2 두 함수의 상태가 분리되어 있는 것입니다.


같은 방식을 이용하여 느긋한 계산법(lazy evaluation)을 구현하거나 무한한 크기의 자료구조를 만들 수도 있습니다.

+ Random Posts