golang - nil

아래 글은 golang을 공부할 목적으로 웹에서 본 글들을 정리한 것이다.

nil

타입을 가진 nil

nil은 사실 타입이 있다.

nil과 nil이 등가가 아닌 것처럼 보인다

nil이 타입 정보를 가지므로 nil==nil 이 true가 된다는 법은 없다.
true가 되기 위해서는 우변과 좌변의 “nil” 타입이 일치 해야한다는 조건이 필요하다.

package main

func main() {
        var x *int32 = nil
        var y *int64 = nil

        equals(x, y)
        return
}

func equals(x, y interface{}) {
        println(x == y)
}
> false

다음과 같은 패턴에서 equals() 내에서는 x가 interface{}로 다루고 있어서, 여기서 nil을 쓰면 좌변도 interface{} 타입 nil로 다뤄진다.
타입이 일치하지 않기 때문에 이 결과도 false 이다.

package main

func main() {
        var x *int32 = nil

        isnil(x)
        return
}

func isnil(x interface{}) {
        println(x == nil)
}
> false

nil은 캐스트 할 수 있다

타입이 있다는 것을 실감할 수 있는 사실에서 nil은 캐스팅 할 수 있다. 앞의 코드에서 false가 된 경우도 등가식 nil을 캐스팅해 주면 true을 돌려준다.

package main

func main() {
        var x *int32 = nil

        isnil(x)
        return
}

func isnil(x interface{}) {
        println(x == (*int32)(nil))
}
> true

즉 객체를 interface{} 로 다루고 있는 경우 등가 연산만으로는 nil인 것을 확실히 알 수 없다.

확실하세 “nil”을 검출하기

nil을 검출하려면 reflect.Value의 IsNil()을 병용해야 한다.
다만 reflect.ValueOf(nil)의 경우는 ZeroValue가 반환되므로 IsNil()을 부를 수 없다. 그래서 x가 nil인지 조사를 먼저 해야 한다.
reflect.ValueOf()는 interface{} 타입을 인수로서 요구한다. 따라서 (interface{})(nil)의 경우 ZeroValue가 반환된다.

간단하게 쓰면 다음과 같다. 참고로 x가 struct 등이라면 IsNil()이 panic 이므로 실제로는 주의해야 한다.

func isnil(x interface{}) {
        println( (x == nil) || reflect.ValueOf(x).IsNil() )
}

타입이라고 생각하는 행동을 하는 nil

이같이 nil은 타입 정보를 갖지만 nil이 타입 그 자체처럼 행동하고 있는 것처럼 보이는 경우가 있다. 이것이 타입 스위치 구문을 사용할 경우에서 다음과 같이 case에 타입과 함께 nil을 포함할 수 있다.
이때 nil의 경우에는 interface 타입 nil(즉 interface{}(nil)의 경우에만 들어간다.

package main

func main() {
        var x *int32 = nil

        typeswitch(x)
        return
}

func typeswitch(hoge interface{}) {
        switch hoge.(type) {
        case nil:
                println("hoge is nil")
        case *int32:
                println("hoge is *int32")
        case *int64:
                println("hoge is *int64")
        default:
                println("unknown")
        }
        return
}
> hoge is *int32

“hoge is nil”을 출력하려면 main()에서 선언한 x를 interface{} 타입으로 해야 한다. 이는 Language Specification “Type switches”에서도 쉽게 설명 하고 있다.


이 글은 2018-11-11에 작성되었습니다.