Go에서는 타입이 있는 nil
과 타입이 없는 nil
이 있다.
이전 게시글에서 interface((*struct)(nil))
은 nil
과 다르다는 것을 확인했다.
좀 더 찾아보니 슬라이스의 nil
은 취급이 조금 다르다고 한다.
빈 슬라이스를 정의하는 방법은 보통 아래처럼 3가지가 있다.
var slice1 []int
slice2 := []int{}
slice3 := make([]int, 0)
이 중 첫번째는 var slice1 []int = nil
과 동일하다.
먼저 nil
인지 아닌지 확인을 해보도록 하자.
fmt.Println(slice1 == nil, slice2 == nil, slice3 == nil)
위 코드의 결과는 true false false
이다. slice1
은 확실히 nil
이다. 그렇다면 이걸 참조하려고 하면 에러가 나지 않을까?
var slice1 []int
fmt.Println(slice1, len(slice1), cap(slice1))
slice1 = append(slice1, 10)
fmt.Println(slice1, len(slice1), cap(slice1))
// [] 0 0
// [10] 1 1
잘 작동한다. 슬라이스는 nil
이어도 이용하는데 딱히 문제가 없다. 그럼 영향이 아예 없는 걸까?
serialized1, _ := json.Marshal(slice1)
serialized1, _ := json.Marshal(slice2)
serialized1, _ := json.Marshal(slice3)
// null
// []
// []
JSON으로 직렬화 했더니 slice1
만 null
이 되었다. 이것 외에는 크게 차이가 없다. API를 다룰 때 정도만 유의하면 될 것 같다.
Uber Go Style Guide에서는 nil
슬라이스는 유효하지만 직렬화와 같은 특정 상황에서는 차이가 나타난다고 한다.
그렇다면 함수 가변인자에서는 어떨까?
func F(i ...int) {
fmt.Println(i == nil)
}
func main() {
F()
F(1)
}
// true
// false
기본적으로 값이 들어가지 않은 가변인자는 nil
로 취급된다.