这两种声明方式有重要的区别:
-
users := []User{}
:
- 创建了一个空的切片,已经初始化
- 长度(len)为 0,容量(cap)为 0
- 可以直接使用 append 操作
- 不是 nil 切片
- 内存已分配
func main() {
users := []User{}
fmt.Println(users == nil) // false
fmt.Println(len(users)) // 0
fmt.Println(cap(users)) // 0
// 可以直接使用
users = append(users, User{Name: "张三"})
}
-
users := []User
:
- 只是声明了一个切片变量,但没有初始化
- 是一个 nil 切片
- 长度(len)为 0,容量(cap)为 0
- 可以使用 append 操作
- 没有分配内存
func main() {
var users []User // 等同于 users := []User
fmt.Println(users == nil) // true
fmt.Println(len(users)) // 0
fmt.Println(cap(users)) // 0
// 同样可以使用
users = append(users, User{Name: "张三"})
}
实际应用中的区别:
- JSON 序列化时:
type Response struct {
Users []User `json:"users"`
}
// nil 切片
resp1 := Response{Users: []User}
jsonData1, _ := json.Marshal(resp1)
fmt.Println(string(jsonData1)) // {"users":null}
// 空切片
resp2 := Response{Users: []User{}}
jsonData2, _ := json.Marshal(resp2)
fmt.Println(string(jsonData2)) // {"users":[]}
- 函数返回值:
// 返回 nil 切片
func getUsers1() []User {
var users []User
return users
}
// 返回空切片
func getUsers2() []User {
users := []User{}
return users
}
// 使用示例
users1 := getUsers1()
fmt.Println(users1 == nil) // true
users2 := getUsers2()
fmt.Println(users2 == nil) // false
- 在 if 判断中:
// nil 切片
var users1 []User
if users1 == nil {
fmt.Println("users1 is nil") // 会打印
}
// 空切片
users2 := []User{}
if users2 == nil {
fmt.Println("users2 is nil") // 不会打印
}
使用建议:
- 如果你的代码需要区分 nil 和空切片,选择合适的声明方式:
// 当你需要明确表示"没有值"时
var users []User
// 当你需要明确表示"空列表"时
users := []User{}
- 如果你的代码不需要区分,两种方式都可以:
// 这两种方式在使用 append 时都没问题
var users []User
users = append(users, User{Name: "张三"})
users := []User{}
users = append(users, User{Name: "张三"})
- 在返回值时要保持一致:
func getUsers() []User {
// 始终返回同一种类型(nil 或空切片)
// 不要有时返回 nil,有时返回 []User{}
if someCondition {
return []User{}
}
return []User{} // 保持一致性
}