🐁
【Go言語】配列の存在チェックには len() != 0 を使う
はじめに
調べれば出てくると思いますが調べるのがめんどくさいので自分用のメモです。
バージョン
go version go1.20.3 darwin/arm64
配列の存在チェックの挙動
nil | []string{} | |
---|---|---|
==nil |
true | true |
len() = 0 |
false | true |
package main_test
import (
"testing"
)
func IsNil(slice []string) bool {
return slice == nil
}
func TestIsNil(t *testing.T) {
t.Parallel()
type args struct {
slice []string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "nil",
args: args{slice: nil},
want: true,
},
{
name: "empty",
args: args{slice: []string{}},
want: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := IsNil(tt.args.slice)
t.Log(got)
if got != tt.want {
t.Errorf("IsNil() = %v, want %v", got, tt.want)
}
})
}
}
func IsEmpty(slice []string) bool {
return len(slice) == 0
}
func TestIsEmpty(t *testing.T) {
t.Parallel()
type args struct {
slice []string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "nil",
args: args{slice: nil},
want: true,
},
{
name: "empty",
args: args{slice: []string{}},
want: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := IsEmpty(tt.args.slice); got != tt.want {
t.Errorf("IsEmpty() = %v, want %v", got, tt.want)
}
})
}
}
どういうときに困るのか
sliceをnil
チェックしているような場合、決め内で先頭の要素を取り出そうとするとpanic
が発生します。
package main
func main() {
First([]string{})
}
func First(slice []string) string {
if slice == nil {
return ""
}
return slice[0]
}
go run main.go
panic: runtime error: index out of range [0] with length 0
goroutine 1 [running]:
main.First(...)
main.go:12
main.main()
main.go:4 +0x24
exit status 2
len()
でチェックしていればpanic
は発生しません。
package main
func main() {
First([]string{})
}
func First(slice []string) string {
if len(slice) == 0 {
return ""
}
return slice[0]
}
ちなみにfor range
を実行する場合はnil
でチェックしようがlen()
でチェックしようが問題なく動作します。
package main
import "fmt"
func main() {
Print([]string{})
}
func Print(slice []string) {
if slice == nil {
fmt.Println("nil slice")
return
}
for i, v := range slice {
fmt.Printf("i: %d, v: %s\n", i, v)
}
}
go run main.go
nil
チェックした場合は何も出力される終了します。
一方、len()
でチェックした場合はempty slice
と出力されて(早期リターンし)終了します。
package main
import "fmt"
func main() {
Print([]string{})
}
func Print(slice []string) {
if len(slice) == 0 {
fmt.Println("empty slice")
return
}
for i, v := range slice {
fmt.Printf("i: %d, v: %s\n", i, v)
}
}
go run main.go
empty slice
おわりに
たまに挙動を忘れてしまうので確認のために記事として書きました。
とりあえずlen()
でチェックしておけば大丈夫ということです。
Discussion