Go中(_)字段有什么特殊用途?

2024-07-21 15:24:21 浏览数 (1)

首先,我们来看不包含下划线(_)字段的结构体代码示例。

model 包里定义一个 User 结构体,包含 NameAge 两个字段。

代码语言:javascript复制
go 代码解读复制代码type User struct {
    Name string
    Age  int
}

使用 位置初始化具名字段初始化 两种方式声明结构体变量。

代码语言:javascript复制
go 代码解读复制代码user := model.User{"陈明勇", 18}
user = model.User{Name: "陈明勇", Age: 18}

在上述代码中,无论是定义结构体,还是声明结构体,都没有任何问题。

我们再来看下包含下划线(_)字段的结构体代码例子:

model 包里定义一个 User 结构体,包含 NameAge 以及 _ 三个字段。

代码语言:javascript复制
go 代码解读复制代码type User struct {
    Name string
    Age  int
    _    struct{}
}

使用 位置初始化具名字段初始化 两种方式声明结构体变量。

代码语言:javascript复制
go 代码解读复制代码// 编译错误 too few values in struct literal of type model.User
user := model.User{"陈明勇", 18}
// 编译错误 implicit assignment to unexported field _ in struct literal of type model.User
user = model.User{"陈明勇", 18, struct{}{}}
// 正常
user = model.User{}
user = model.User{Name: "陈明勇", Age: 18}

在上述例子中,如果通过 user := model.User{"陈明勇", 18}model.User{"陈明勇", 18, struct{}{}} 这两种 位置初始化 的方式声明结构体变量,程序将会编译错误,而通过 零值初始化具名字段初始化 的方式去声明结构体变量则没有问题。

通过对比有无下划线(_)字段的结构体代码示例,我们可以总结出在结构体中定义下划线(_)字段的用途:在结构体中定义一个名为 _ 的字段,可以强制要求该结构体在初始化时必须使用具名字段初始化(声明零值结构体变量的场景除外)。

原理浅析

当我们使用 位置初始化 的方式声明结构体时,需要按照结构体字段的顺序依次提供所有字段的值。

如果在结构体中定义了一个名为 _ 的字段,那么使用 位置初始化 的方式时,如果没有提供 _ 字段的值,编译器会提示 too few values in struct literal of type XXX,这是因为没有提供所有的结构体字段值。

即使按照结构体字段的顺序提供了所有字段的值,编译器也会报错,提示 implicit assignment to unexported field _ in struct literal of type XXX。这是因为 _ 字段的首字母没有大写,被认为是未导出的字段,我们不能隐式赋值给未导出的字段,因此不能通过位置初始化进行赋值。

综上所述,由于无法通过 位置初始化 的方式去声明这个结构体的变量,我们只能通过 零值初始化具名字段初始化 的方式去声明结构体变量。

小结

通过本文的探讨,我们了解了在 Go 语言中结构体字段命名使用下划线(_)的特殊用途。

具体来说,定义一个名为 _ 的字段可以有效地强制开发者在初始化结构体时使用具名字段初始化,而不是位置初始化。这样做的好处包括:

  • 代码可读性:具名字段初始化使得代码更具可读性和可维护性,因为每个字段的值都显式地与字段名关联。
  • 避免错误:位置初始化需要严格遵循字段顺序,容易引入错误。具名字段初始化则避免了这一问题。

0 人点赞