
结构体就是把一组相关的数据捆绑在一起,自定义一种新的类型。
type Maid struct {
Name string // 姓名
Age int // 芳龄
Skill string // 特长
Salary int // 月钱
}
qiuxiang := Maid{
Name: "秋香",
Age: 18,
Skill: "背唐诗",
Salary: 50, // 结尾逗号不能少
}
p2 := Maid{"春夏", 20, "扫地", 30} // 必须按顺序写全,容易搞错
p3 := new(Maid) // p3 是 *Maid 类型 (指针)
p3.Name = "冬梅" // Go 语法糖:自动处理指针,不需要写 (*p3).Name
在 Go 语言里,变量名首字母的大小写决定了它的可见性(权限)。

Name)。
type Maid struct {
Name string // ✅ 公开:大家都知道她叫秋香
age int // 🔒 私有:女孩子的年龄是秘密 (外部包无法访问)
}
唐伯虎要把秋香的档案寄给“皇宫选秀办”(JSON 序列化),需要给字段贴上特殊的标签。
import "encoding/json"
type Maid struct {
// 后面反引号里的就是 Tag
Name string `json:"name"` // 转成 JSON 时变成小写 "name"
Age int `json:"age"`
Skill string `json:"-"` // "-" 表示忽略这个字段,不告诉皇上
}
func main() {
q := Maid{Name: "秋香", Age: 18, Skill: "武功"}
// 把结构体变成 JSON 字符串
data, _ := json.Marshal(q)
fmt.Println(string(data))
// 输出:{"name":"秋香","age":18} (Skill 被隐藏了)
}
Go 语言没有像 Java 那样的 constructor,但我们可以自己造一个工厂函数,通常以 New 开头。
func NewMaid(name string, age int) *Maid {
return &Maid{
Name: name,
Age: age,
// 其他字段可以在这里设置默认值
Skill: "全能",
Salary: 100,
}
}
func main() {
// 像大少爷一样直接领人,不用自己填表
q := NewMaid("秋香", 18)
fmt.Println(q.Name)
}
有时候我们需要一个临时的数据结构,只用一次,不想专门定义一个类型。这就叫匿名结构体。
func main() {
// 定义并初始化一个匿名结构体
// 场景:临时记录一下皇上的打赏
reward := struct {
Gold int
Silver int
}{
Gold: 100,
Silver: 50,
}
fmt.Printf("皇上赏赐:金 %d, 银 %d\n", reward.Gold, reward.Silver)
}
如果两个结构体的字段类型都支持比较(如 int, string),那这两个结构体就可以直接用 == 比较。
q1 := Maid{Name: "秋香", Age: 18}
q2 := Maid{Name: "秋香", Age: 18}
q3 := Maid{Name: "石榴", Age: 20}
fmt.Println(q1 == q2) // true (完全一样)
fmt.Println(q1 == q3) // false
光有属性还不够,秋香姐得会动啊!在 Go 语言里,我们可以给结构体绑定方法。这就像是给角色添加技能。

// (m Maid) 叫接收者 (Receiver),表示这个函数属于 Maid 类型
func (m Maid) Smile() {
fmt.Printf("%s 微微一笑,很倾城。\n", m.Name)
}
func main() {
qiuxiang := Maid{Name: "秋香"}
qiuxiang.Smile() // 调用方法
}
这和上一回的“指针”息息相关!
// 想要修改属性,必须用指针接收者 *Maid
func (m *Maid) Rename(newName string) {
m.Name = newName
}
func main() {
shiliu := Maid{Name: "石榴姐"}
// 石榴姐想冒充秋香
shiliu.Rename("秋香")
fmt.Println("现在她是:", shiliu.Name) // 输出:秋香
}
Go 没有“继承”,但有“组合”。我们可以把一个结构体塞进另一个结构体里。

type Person struct {
Name string
}
func (p *Person) SayHello() {
fmt.Println("你好,我是 " + p.Name)
}
type Maid struct {
Person // 匿名嵌入,Maid 直接拥有了 Person 的字段和方法
Job string
}
func main() {
// 初始化时要指定内部结构体
m := Maid{
Person: Person{Name: "秋香"},
Job: "领班",
}
// 字段提升:可以直接访问 Name,就像 Maid 自己的一样
fmt.Println(m.Name) // 输出:秋香
// 方法提升:可以直接调用 Person 的方法
m.SayHello() // 输出:你好,我是 秋香
// 也可以通过内部结构体访问
fmt.Println(m.Person.Name)
}
定义一个 Skill 方法,如果是 "秋香",输出 "念诗";如果是 "石榴姐",输出 "画妆"。
package main
import "fmt"
type Maid struct {
Name string
}
// 填空:定义方法 ShowTalent
func (m ______) ShowTalent() {
if m.Name == "秋香" {
fmt.Println("念诗")
} else {
fmt.Println("画妆")
}
}
func main() {
q := Maid{Name: "秋香"}
q.ShowTalent()
s := Maid{Name: "石榴姐"}
s.ShowTalent()
}
任务: 填补接收者定义。
答案: Maid 或 *Maid 都可以,因为不需要修改值。通常只读用值接收者,修改用指针接收者。
func (m Maid) ShowTalent() { ... }