Lazy loaded image
Lazy loaded imagego-面向对象
字数 3169阅读时长 8 分钟
2025-7-30
2025-8-1
type
status
date
slug
summary
tags
category
icon
password

结构体

在 Go 语言中,结构体(struct)是一种复合数据类型,可以用来组合多个不同类型的字段,用于表示一个整体对象。结构体类似于面向对象编程语言中的类(class),但 Go 没有引入传统意义上的类和继承,而是采用了更加简洁灵活的组合方式来实现对象建模。
编程语言的本质目的是模拟现实世界的问题和事物。现实中的对象,如:人通常具有两类特征:属性:名字、年龄、身高等,行为:说话、走路、吃饭等。用之前学过的基本类型,如 int、string 或数组、切片等,很难完整表达一个人或其他复杂对象。而结构体正是用来描述具有多个属性的对象,使我们可以更自然地建模现实世界中的事物。
下面我们来列举一个简单的例子。在很久很久以前,200 岁的老王家里有几只老鼠。由于年纪太大,老王已经无法亲自捉老鼠了,于是他养了两只小猫:一只 3 岁的黑猫,名叫小黑;一只 5 岁的白猫,名叫小白。我们现在要编写一个程序:当用户输入猫的名字时,程序会输出对应猫咪的姓名、颜色和年龄。如果输入的名字错误,则提示老王家没有这只猫。
使用传统方式:每个属性写一个变量
这样写在猫数量很少的时候还可以,但如果老王养了 20 只甚至上百只猫,就不可能每一只都手动定义变量了。你可能想到用数组来存储:
虽然看起来变量少了,但这其实也不方便管理。每只猫的信息被拆散保存在不同的数组中。比如 catNames[0]catAges[0]catColors[0] 都是小黑的信息,但它们之间没有直接的结构化关联。当你要遍历、查找、添加新猫信息时,维护起来会变得复杂且容易出错。最合理的方式是把猫的各种属性抽象出来,构建成一个自定义的数据类型 —— 结构体:
有了这个结构体类型,我们可以方便地创建猫的对象了:
通过上面的案例可以看出:结构体是自定义的数据类型,代表一类事物。结构体变量是具体的,代表一个具体变量

定义结构体

结构体定义的一般方式如下:
比如我要定义一个可以存储个人资料名为 Profile 的结构体,可以这么写
上面的结构体 Profile 称为命名的结构体(Named Structure)。我们创建了名为 Profile 的新类型,而它可以用于创建 Profile 类型的结构体变量。

匿名结构体

声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体,标识符直接使用 struct 部分结构体本身来作为类型,而不是使用type定义的名字的结构体的标识符。比如创建一个匿名结构体 employee
使用 var 定义一个变量employee,后面跟类型,这个类型没有名字,只有结构体本身

初始化

在 Go 语言中,未进行显式初始化的变量都会被初始化为该类型的零值,例如 bool 类型的零值为 false,int 类型的零值为 0,string 类型的零值为空字符串,float 类型的零值为 0.0
运行结果:
扩展方式:
运行结果:

字段

在 Go 中,结构体是一组字段(也叫成员)的集合。你可以通过 结构体变量.字段名 的形式,来访问或修改结构体中的字段。点号操作符 . 是访问结构体字段的标准方式。
示例:

方法

Go 语言不支持传统类的概念,因此也就没有像 Java/C++ 中那样在类中直接定义成员方法的方式。不过,Go 提供了一种结构体绑定函数的机制,让我们可以为结构体定义方法,实现面向对象的效果。要为结构体定义方法,Go 要求你在 func 和方法名之间声明接收者(receiver)。接收者就像是这个方法属于哪个类型的声明,相当于其它语言中隐藏的 this 关键字。
示例:为结构体定义方法
(s Student) 就是接收者声明,表示这个方法属于 Student 类型。s 是接收者变量名,可以换成任何合法名字,类似 this。这样一来,我们就可以在初始化 Student 类后,通过 GetName() 方法获取 name 值:
我们通过在函数签名中增加接收者声明的方式定义了函数所归属的类型,这个时候,函数就不再是普通的函数,而是类的成员方法了。在类的成员方法中,可以通过声明的类型变量来访问类的属性和其他方法。GetName 是一个只读方法,如果我们要在外部通过 Student 类暴露的方法设置 name 值,可以这么做:
Student 类型设置成了指针类型,因为 Go 语言面向对象编程不像 PHP、Java 那样支持隐式的 this 指针,所有的东西都是显式声明的,在 GetXXX 方法中,由于不需要对类的成员变量进行修改,所以不需要传入指针,而 SetXXX 方法需要在函数内部修改成员变量的值,并且该修改要作用到该函数作用域以外,所以需要传入指针类型。结构体是值类型,不是引用类型,所以需要显式传入指针。接下来,我们可以在 main 函数中初始化 Student 类之后,通过 SetName 方法修改 name 值,然后再通过 GetName 将其打印出来:
接收者可以是值类型或指针类型。我们可以把接收者类型为指针的成员方法叫做指针方法,把接收者类型为非指针的成员方法叫做值方法,二者的区别在于值方法传入的结构体变量是值类型。因此传入函数内部的是外部传入结构体实例的值拷贝,修改不会作用到外部传入的结构体实例。
输出结果如下:
一句话总结:值方法(值接收器):操作的是副本,不会影响原始变量。指针方法(指针接收器):操作的是地址,能直接修改原始变量。
 
 
 
 
 
 
 
上一篇
go-函数
下一篇
kubernetes