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에 작성되었습니다.