Go에서 nil
인데 nil
이 아닌 경우가 있다.
인터페이스 구현체의 포인터를 정의한 뒤 nil로 초기화 하고 그 인터페이스 타입으로 리턴한 걸 받으면 된다.
말로 하면 뭔소린지 잘 이해가 안가니 코드로 하면...
type Interface interface {
Sample()
}
먼저 위처럼 인터페이스를 하나 정의한다. 이 인터페이스는 Sample()
이라는 메소드를 가지고 있다.
type Structure struct{}
func (*Structure) Sample() {}
그리고 구조체를 하나 정의한 뒤 위의 인터페이스(Interface
)를 구현한다.
func Test() Interface {
var s *Structure = nil
return s
}
이제 Interface
타입을 리턴하는 함수 Test()
를 만들고, 그 안에서 Structure
포인터 객체를 리턴한다.
이때 반환하는 객체는 nil
로 초기화 되어 있다.
t := Test()
fmt.Println(t)
fmt.Println(t == nil)
// <nil>
// false
테스트 해보기 위해 위와 같은 코드를 짰다.
첫번째 print에서는 <nil>
이 나왔는데, 두번째 print에서는 false
가 나왔다.
분명 nil
끼리 비교했을텐데 다르다고 나온다.
t := Test()
fmt.Printf("%#v\n", t)
fmt.Printf("%#v\n", nil)
// (*main.Structure)(nil)
// <nil>
보다 자세한 비교를 위해 출력 방식을 바꿔보았더니 추가적인 확인이 가능했다. 둘은 엄밀히는 다른 nil
이었던 것이다.
t
는 타입은 지정이 되어 있었으나 그 값이 nil
인 것이고, 비교하려던 nil
은 그냥 전부 nil
인 것이다.
마치 자바스크립트의 null
과 undefined
같은 관계였던 것이다.
var i Interface
fmt.Printf("%#v\n", i)
fmt.Println(i == nil)
// <nil>
// true
참고로 위처럼 그냥 인터페이스 객체 만들면 제로값은 nil
이 된다.
그렇다면 이게 nil
인지 아닌지를 코드 상에서 어떻게 파악하는가?
reflect
를 이용하면 된다.
fmt.Println(reflect.ValueOf(t).IsNil()) // true
이러면 제대로 확인이 가능하긴 하다.
좋네요 이거 땜에 구조체를 value로 받은 다음 인터페이스 변환해서 쓰기로 했어요