结构体
约 1158 字大约 4 分钟
2026-03-25
定义一个结构体的标准格式为 type StructName struct {},大括号包包裹的部分是属性列表,由一个或若干个字段构成,每个字段通过属性名和属性类型组成。字段的名称不允许重复
type User struct {
Id int
Score float64
Name, Address string
}提示
字段名要大写才能被其它包访问,且字段在未赋值时采用各自类型的零值
结构体的使用
结构体的声明与初始化
结构体实例化可以通过四种方式进行
字面量初始化
通过变量承接结构体字面量并同时赋值
func main() { user := User{ Id: 1, Score: 99.5, Name: "Alice", Address: "123 Main St", } }这种方式清晰且不受字段定义顺序的限制
位置简写
省略字段名,直接在定义顺序上提供值进行初始化。必须完全遵守定义顺序
func main() { user := User{1, 99.5, "Alice", "123 Main St"} }先声明零值再赋值
通过
.语法为字段赋值func main() { var user User user.Id = 1 user.Score = 99.5 user.Name = "Alice" user.Address = "123 Main St" }指针实例化
通过
&得到结构体的引用func main() { user := &User { Id: 1, Score: 99.5, Name: "Alice", Address: "123 Main St", } }使用这种方式在访问或修改字段时会自动解引用,直接对同一份数据进行操作
访问和修改结构体的属性值
通过 . 可以对实例化的结构体进行字段访问和修改
结构体基本使用
package main
import "fmt"
type Human struct {
Age int
Sex bool
Height float32
}
func main() {
h := Human{Age: 12, Sex: true, Height: 154}
fmt.Println("初始:", h)
fmt.Printf("Age is %d \n", h.Age)
fmt.Printf("Height is %.2f \n", h.Height)
fmt.Printf("Sex is %t \n", h.Sex)
h.Age += 1 // 修改字段
p := &h
p.Height = 155.5 // 指针自动解引用
fmt.Printf("修改后: %+v \n", h)
fmt.Printf("%#v\n", h)
}笔记
通过 Printf 输出结构体时,可以使用 %v 来按默认格式展示字段值、%+v 输出包含字段名称的内容、%#v 输出 Go 源码的写法把值打印出来
匿名结构体
匿名结构体不需要声明一个结构体名称,只需在使用的地方直接通过 struct 声明即可,适合一次性、局部使用的临时数据
匿名结构体
package main
import "fmt"
func main() {
p := struct {
Name string
Age int
}{
Name: "Alice",
Age: 30,
}
fmt.Printf("%+v\n", p)
}构造函数
从本质上说,Go 语言的类型或结构体本身是没有构造函数功能的,也就是没有 constructor 函数,但可以 使用结构体初始化的过程来模拟实现构造函数。这种函数通常以 New 开头,返回一个结构体实例或其指针,提供默认值或进行必要的初始化逻辑
type User struct {
Id int
Score float64
Name, Address string
}
func NewUser(id int, score float64, name string, address string) *User {
return &User{
Id: id,
Score: score,
Name: name,
Address: "default address",
}
}
func main() {
u := NewUser(1, 99.5, "Alice", "123 Main St")
fmt.Printf("%+v\n", u)
}方法
方法(Method)就是给结构体添加的行为。通过 func (接收者 *类型) 方法名() 的方式定义
注
在定义方法时,需要注意接收器的类型。使用指针与否,将决定了是否对原始变量产生影响。如果需要修改结构体的字段值,应该使用指针接收器;如果只是读取字段值,可以使用值接收器
package main
import "fmt"
type User struct {
Name string
Age int
}
func (u User) Greet() {
fmt.Printf("Hello, my name is %s and I am %d years old.\n", u.Name, u.Age)
}
func main() {
user := User{Name: "Alice", Age: 30}
user.Greet() // 输出: Hello, my name is Alice and I am 30 years old.
}继承
与构造函数类似,Go 中的继承也是通过结构体的嵌套来实现的。通过在一个结构体中嵌入另一个结构体,可以实现字段和方法的提升,从而达到类似于继承的效果
type Animal struct {
Name string
Age int
Gender string
}
// 父类中的方法
func (a *Animal) Eat() {
fmt.Println(a.Name, "我要吃到饱!")
}
type Dog struct {
Color string
Animal
}
type Bird struct {
WingColor string
Animal
}
func NewBird(name string, age int, gender string, wingColor string) *Bird {
return &Bird{
WingColor: wingColor,
Animal: Animal{
Name: name,
Age: age,
Gender: gender,
},
}
}
func NewDog(name string, age int, gender string, color string) *Dog {
return &Dog{
Color: color,
Animal: Animal{
Name: name,
Age: age,
Gender: gender,
},
}
}
func main() {
bird := NewBird("小鸟", 1, "公", "绿色")
bird.Animal.Eat()
dog := NewDog("小狗", 2, "公", "黄色")
dog.Animal.Eat()
}重要
若多个嵌入类型包含同名字段/方法,访问时会因冲突而需要显式限定,如 u.Human.Age
