업무에 사용하는 Go 언어 7 – nil

Go 언어 nil에 대해 다루어보도록 하겠습니다.
nil에 대한 개념은 매우 혼동될 수 있으므로 주의 깊게 살펴보시길 바랍니다.

업무에 사용하는 Go 언어 썸네일

약간의 여담

필자는 시리즈 초반에 nil에 대해 다루어보려고 했다.
zero value와 nil을 가질 수 있는 자료구조를 어느 정도 다루지 않고 설명하기 힘들어서 이렇게 따로 설명하게 되었다.

Go 언어 nil

nilnull이나 undefined과 비슷하지만 약간 특이합니다.
특정 타입의 변수가 “값이 초기화되지 않은 상태” 표현할 때 사용됩니다.
이는 주로 포인터, 슬라이스, 맵, 채널, 함수, 인터페이스 등의 참조 타입에 적용됩니다.

참조 타입에 사용된다는 개념이 매우 중요합니다.
참조 타입에 해당하는 자료구조는 메모리에 어떠한 초기화를 거치지 않고 사용할 수 없습니다.

이전 글에서 다룬 map을 다음과 같이 사용해봅시다.

Go
package main

func main() {
	var m map[string]int
	m["test"] = 1
}

직접 실행해보시면 assignment to entry in nil map이라는 문구와 함께 프로그램이 종료될 것입니다.
이렇게 참조 타입에 해당하는 자료구조는 꼭 초기화가 된 상태에서 사용되어야 합니다.

이러한 상황을 panic이라고 한다.
실제로 에러가 발생하면 panic이라는 내장 함수가 실행된다.

초기화를 하는 방법으로는 리터럴을 이용한 초기화를 통해 선언을 하거나 make 내장함수를 사용하여 선언하면 된다.

nil 타입

nil이라고 해서 모두 같은 nil이 아닙니다.
nil은 값의 개념보다는 상태의 개념이며, 타입을 가집니다.
다음 코드를 실행시켜 봅시다.

Go
package main

func main() {
	var m map[string]int
	var s []int

	print(m == s)
}

mismatched types map[string]int and []int이라는 문구와 함께 프로그램이 실행되지 않을 것입니다.
변수 m, s 모두 nil 상태이지만 타입은 변수의 타입을 따라가는 것이 핵심입니다.

다음 코드를 통해 여러 가지 nil에 대해 확인해보세요.

Go
package main

import "fmt"

func main() {
    // 포인터 변수
    var p *int
    fmt.Println(p) // <nil>

    // 슬라이스 변수
    var s []int
    fmt.Println(s) // []

    // 맵 변수
    var m map[string]int
    fmt.Println(m) // map[]

    // 채널 변수
    var ch chan int
    fmt.Println(ch) // <nil>

    // 함수 변수
    var f func()
    fmt.Println(f) // <nil>

    // 인터페이스 변수
    var i interface{}
    fmt.Println(i) // <nil>
}

정리

  • nil은 단순히 값을 의미하는 것이 아니라 초기화되지 않은 상태를 의미한다.
  • nil이라고 모두 같은 nil이 아니다.
  • nil 상태를 가질 수 있는 자료 구조는 참조 타입이므로 꼭 초기화를 한 후 사용할 수 있다.

다음 글에 알아볼 내용

Go 언어 make 내장함수