Files
cs-note/hzh/GolangStar/Go语言基础/Go语言结构体.md
T

3.6 KiB
Raw Blame History

tags, create time
tags create time
go
golang
go基础语法
结构体
2026-06-07 15:00

Go 语言结构体

概述

Go 没有类(class),但通过**结构体(struct)**实现数据的组合。本文介绍结构体的定义、初始化、成员访问,以及嵌入(匿名字段)机制。

正文

为什么 Go 不用 class?

在 Java / C++ 中,你用 class 同时定义数据和行为。Go 把它们拆开了:struct 只负责数据,method(方法)是后来绑定到 struct 上的。这种设计让数据结构和方法可以独立演化。

[!question] ❓ 思考 如果一个 Student 有 Name、Age、Score 三个属性,用基本类型能表示吗?为什么需要组合?

定义与初始化

定义

type Student struct {
    ID    int
    Name  string
    Age   int
    Score int
}

字段声明格式为 名称 类型,同类型的可以合并:

type Student struct {
    ID    int
    Name  string
    Age   int
    Score int
}
// 等价于
type Student struct {
    ID, Age    int
    Name       string
    Score      int
}

初始化方式

键值对初始化(推荐,清晰明了):

st := Student{
    ID:    100,
    Name:  "zhangsan",
    Age:   18,
    Score: 98,
}
fmt.Printf("%v\n", st)  // {100 zhangsan 18 98}

位置初始化(按字段顺序,字段少时可用):

st := Student{101, "lisi", 20, 97}

[!tip] 💡 零值初始化 只写 Student{} 会创建一个所有字段为零值的结构体:

st := Student{}  // {0 "" 0 0}

new() vs 直接初始化:

st1 := &Student{}          // ✅ 推荐:简洁,可直接赋值字段
st2 := new(Student)        // 等价于 &Student{},返回 *Student

[!note] 📝 new(T) 的作用 new(T) 分配零值内存并返回 *T。它与 &T{} 功能等价,但后者更灵活——可以直接内联初始化部分字段。

成员访问

使用 . 操作符。指针类型的 struct 也可以直接用 . 访问字段(Go 自动解引用):

st := Student{Name: "zhangsan", Age: 18}
fmt.Println(st.Name)       // zhangsan

ptr := &st
fmt.Println(ptr.Name)      // zhangsan(Go 自动解引用,等价于 (*ptr).Name)

结构体嵌套(组合)

Go 没有继承,但通过组合实现类似效果:

type Address struct {
    City  string
    Postal string
}

type Person struct {
    Name  string
    Age   int
    Address  // 匿名嵌入(anonymous field)
}

p := Person{
    Name: "Alice",
    Address: Address{City: "Beijing"},
}
fmt.Println(p.City)  // 直接访问嵌入字段!

[!info] ℹ️ 嵌入 vs 普通字段

  • 匿名嵌入(无字段名):外层可以直接访问内层字段,模拟"继承"
  • 命名字段:需要通过字段名访问,如 p.Address.City
graph LR
    A["Person"] --> B["Name: string"]
    A --> C["Age: int"]
    A --> D["Address ← 嵌入"]
    D --> E["City: string"]
    D --> F["Postal: string"]

结构体作为函数参数

[!warning] ⚠️ 值拷贝陷阱 Go 的结构体是值类型,传入函数时会被完整拷贝。修改函数内的参数不会影响原始 struct。

func ChangeName(s Student) {
    s.Name = "modified"  // 只修改了副本
}

func ChangeNamePtr(s *Student) {
    s.Name = "modified"  // 通过指针修改原值
}

[!tip] 💡 大结构体传指针 结构体较大时,传递 *T 而非 T 可以避免不必要的内存拷贝。即使你不打算修改它,传指针也是常见的性能优化手段。