Go中struct是值类型,定义需type关键字、显式字段类型和导出控制;初始化支持字面量(带名/无名)、new()或取地址;传指针才能修改原值;匿名字段提升内嵌成员;tag用于序列化等反射场景。

Go 语言中 struct 是值类型,定义时必须显式命名字段类型,没有隐式继承或字段访问修饰符;直接赋值、作为函数参数传入、或用指针修改,行为差异明显,容易因忽略值拷贝导致修改失效。
如何定义 struct 并初始化
struct 定义需用 type 关键字声明新类型,字段名首字母大小写决定是否导出(即能否被其他包访问)。初始化支持字面量(带字段名或不带)、new()、或取地址方式。
- 导出字段(首字母大写)才能被其他包访问,如
Name;非导出字段(如age)仅限本包内使用 - 字面量初始化时若省略字段名,必须按定义顺序提供全部字段值,且不能混用“带名”和“无名”写法
-
new(Person)返回指向零值struct的指针,所有字段为对应类型的零值(""、0、nil等)
type Person struct {
Name string
Age int
}
p1 := Person{Name: "Alice", Age: 30} // 带字段名,推荐
p2 := Person{"Bob", 25} // 无字段名,要求顺序严格
p3 := &Person{Name: "Charlie"} // 直接取地址,Age 自动为 0
为什么传 struct 指针才能修改原值
struct 是值类型,函数参数传递时会复制整个结构体。若想在函数内修改调用方的原始数据,必须传 *struct 类型参数,否则修改只作用于副本。
- 接收
Person参数:函数内对字段赋值不影响原变量 - 接收
*Person参数:可通过ptr.Field = ...修改原始 struct 字段 - 方法接收者也遵循该规则:
func (p Person) SetName(...)是只读副本;func (p *Person) SetName(...)才能真正修改
func updateName(p Person, name string) {
p.Name = name // 不会影响调用方的 p
}
func updateNamePtr(p *Person, name string) {
p.Name = name // 修改生效
}
p := Person{Name: "Old"}
updateName(p, "New") // p.Name 仍是 "Old"
updateNamePtr(&p, "New") // p.Name 变为 "New"
嵌套 struct 与匿名字段(内嵌)的区别
嵌套 struct 是显式字段,访问需逐层点号;匿名字段(即只写类型不写字段名)会提升内嵌类型的方法和导出字段到外层,但仅限一层提升,且同名字段会冲突。
立即学习“go语言免费学习笔记(深入)”;
- 匿名字段本质是“类型即字段名”,如
struct{ User }中User是字段名,也是类型名 - 若两个匿名字段有同名导出字段(如都含
ID int),则外层 struct 访问.ID会报错:ambiguous selector - 嵌套字段可设标签(tag),用于 JSON、数据库映射等,如
json:"user_name"
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
type Profile struct {
User // 匿名字段:提升 User 的 ID、Name 和方法
Active bool `json:"active"`
}
p := Profile{User: User{ID: 123, Name: "Tom"}}
fmt.Println(p.ID) // ✅ 合法,ID 被提升
fmt.Println(p.User.ID) // ✅ 也可显式访问
fmt.Println(p.Name) // ✅ Name 也被提升
struct 字段标签(tag)的实际用途
字段后紧跟的反引号字符串是 struct tag,不是注释,由反射读取,常用于序列化、ORM 映射、验证等场景。标准库如 encoding/json、database/sql 都依赖它,但 tag 本身不改变运行时行为。
- tag 键名(如
json)区分大小写,值用双引号包裹,空格分隔多个键值对 -
json:"-"表示忽略该字段;json:"name,omitempty"表示值为空时不输出 - 自定义解析需用
reflect.StructTag.Get("key"),注意处理转义和空格
type Config struct {
Port int `json:"port" env:"PORT"`
Host string `json:"host" env:"HOST"`
}
cfg := Config{Port: 8080, Host: "localhost"}
data, _ := json.Marshal(cfg)
// 输出:{"port":8080,"host":"localhost"}
struct 的零值、内存布局、字段对齐、以及是否可比较(所有字段都可比较才可整体比较),这些细节在高性能或跨平台场景下容易被忽略,但直接影响程序正确性与效率。










