go 修改结构体方法_Go36-13-结构体及其方法
结构体及其方法
结构体类型表示的是实实在在的数据结构。一个结构体类型可以包含若干个字段,每个字段通常都需要有确切的名字和类型。
结构体类型也可以不包含任何字段,这样并不是没有意义的,因为我们还可以为这些类型关联上一些方法,这里你可以把方法看做是函数的特殊版本。
方法和函数不同,它需要有名字,不能被当作值来看待,最重要的是,它必须隶属于某一个类型。方法所属的类型会通过其声明中的接收者(receiver)声明体现出来。
方法隶属的类型其实并不局限于结构体类型,但必须是某个自定义的数据类型,并且不能是任何接口类型。
方法的使用
接收者声明就是在关键字func和方法名称之间的那个圆括号包裹起来的内容,其中必须包含确切的名称和类型字面量。这个接收者的类型其实就是当前方法所属的那个类型,而接收者的名称,则用于在当前方法中引用它所属的类型的当前值。
举个例子:
// AnimalCategory 代表动物分类学中的基本分类法
type AnimalCategory struct {
kingdom string // 界
phylum string // 门
class string // 纲
order string // 目
family string // 科
genus string // 属
species string // 种
}
func (ac AnimalCategory) String() string {
return fmt.Sprintf(
"%s%s%s%s%s%s%s",
ac.kingdom,
ac.phylum,
ac.class,
ac.order,
ac.family,
ac.genus,
ac.species)
}
在Go语言中,我们可以通过为一个类型编写名为String的方法,来自定义该类型的字符串表示形式。这个String方法不需要任何参数声明,但需要有一个string类型的结果声明。所以在再用fmt包里的函数时,会打印出上面自定义的字符串表示形式,而无需显示的调用它的String方法。
我们可以把结构体类型中的一个字段看作是它的一个属性或者一项数据,再把隶属于它的一个方法看作是附加在其中数据之上的一个能力或者一项操作。将属性及其能力(或者说数据及其操作)封装在一起,是面向对象编程(object-orientedprogramming)的一个主要原则。
匿名字段
下面声明了一个结构体类型Animal,有两个字段,一个是string类型的scientificName。另一个字段声明中只有AnimalCategory,就是上面示例的那个结构体的名字:
type Animal struct {
scientificName string // 学名
AnimalCategory // 动物基本分类
}
字段声明AnimalCategory代表了Animal类型的一个嵌入字段。Go语言规范规定,如果一个字段的声明中只有字段的类型名而没有字段的名称,那么它就是一个嵌入字段,也可以被称为匿名字段。我们可以通过此类型变量的名称后跟“.”,再后跟嵌入字段类型的方式引用到该字段。也就是说,嵌入字段的类型既是类型也是名称。
强调一下,Go语言中没有继承的概念,它所做的是通过嵌入字段的方式实现了类型之间的组合。
简单来说,面向对象编程中的继承,其实是通过牺牲一定的代码简洁性来换取可扩展性,而且这种可扩展性是通过侵入的方式来实现的。类型之间的组合采用的是非声明的方式,我们不需要显式地声明某个类型实现了某个接口,或者一个类型继承了另一个类型。
同时,类型组合也是非侵入式的,它不会破坏类型的封装或加重类型之间的耦合。我们要做的只是把类型当做字段嵌入进来,然后坐享其成地使用嵌入字段所拥有的一切。如果嵌入字段有哪里不合心意,我们还可以用“包装”或“屏蔽”的方式去调整和优化。
值方法和指针方法
方法的接收者类型必须是某个自定义的数据类型(不能是接口)。所谓的值方法,就是接收者类型是非指针的自定义数据类型的方法。之前的示例中的方法都是值方法。
下面的这个就是指针方法:
func (a *Animal) SetScientificName(name string) {
a.scientificName = name
}
方法的接受者类型是*Animal,是一个指针类型。这时Animal可以被叫做*Animal的基本类型。可以认为,指针类型的值就是指向某个基本类型值的指针。指针方法,就是接收者类型是上述指针类型的方法。
值方法和指针方法之间的不同点:
值方法的接收者是方法所属类型的一个副本。在方法内对副本的修改一般不会提现在原值上,除非这个类型本身是某个引用类型。而指针方法内对的修改是一定会提现在原值上的。
严格来讲,通过值只能调用到值方法,通过指针只能调用到指针方法。但是,Go会适时的进行自动的转义,使得通过值也能调用到它的指针方法。比如,Animal.SetScientificName("Duck")会自动转义为(&Animal).SetScientificName("Duck"),即:先取指针值,然后再在改指针值上调用指针方法。
这条和接口相关,一个类型的方法集合中有哪些方法与它能实现哪些接口类型是息息相关的。如果一个基本类型和它的指针类型的方法集合是不同的,那么它们具体实现的接口类型的数量就也会有差异,除非这两个数量都是零。比如,一个指针类型实现了某某接口类型,但它的基本类型却不一定能够作为该接口的实现类型。
这个是验证上述差异的示例:
package main
import "fmt"
type Cat struct {
name string // 名字。
scientificName string // 学名。
category string // 动物学基本分类。
}
func New(name, scientificName, category string) Cat {
return Cat{
name: name,
scientificName: scientificName,
category: category,
}
}
func (cat *Cat) SetName(name string) {
cat.name = name
}
func (cat Cat) SetNameOfCopy(name string) {
cat.name = name
}
func (cat Cat) Name() string {
return cat.name
}
func (cat Cat) ScientificName() string {
return cat.scientificName
}
func (cat Cat) Category() string {
return cat.category
}
func (cat Cat) String() string {
return fmt.Sprintf("%s (category: %s, name: %q)",
cat.scientificName, cat.category, cat.name)
}
func main() {
cat := New("little pig", "American Shorthair", "cat")
cat.SetName("monster") // (&cat).SetName("monster")
fmt.Printf("The cat: %s\n", cat)
cat.SetNameOfCopy("little pig")
fmt.Printf("The cat: %s\n", cat)
type Pet interface {
SetName(name string)
Name() string
Category() string
ScientificName() string
}
_, ok := interface{}(cat).(Pet)
fmt.Printf("Cat implements interface Pet: %v\n", ok) // false
_, ok = interface{}(&cat).(Pet)
fmt.Printf("*Cat implements interface Pet: %v\n", ok) // true
}
这里牵涉到了接口的知识点,所以这个例子和下面的内容,下一篇还会再讲一遍。
最后的2行输出的内容,说明cat没有实现Pet的接口,而&cat是实现了Pet的接口。
因为要实现Pet接口需要实现接下的那4个方法。而Cat类型没有实现SetName方法,所以cat没有实现Pet接口。代码中SetName方法是通过*Cat实现的,另外其他的3个方法都已经通过Cat实现了,通过*Cat也能调用(差异的第2条),所以只有指针方法实现了Pet接口的所有方法。
go 修改结构体方法_Go36-13-结构体及其方法相关推荐
- Golang——结构体创建与初始化、结构体与数组、结构体与切片、结构体与map、结构体作为函数参数、结构体方法、结构体方法继承
结构体: 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合 结构体可以很好的管理一批有联系的数据,使用结构体可以提高程序的易读性,类似于Java的类一样 不能在结构体直接赋值 字段名必须唯一 ...
- c语言结构体作为形参是否加struct_(struct)结构体变量作为函数参数调用的方法小结...
结构体变量作为函数参数传递的3种方法将一个结构体变量中的数据传递给另一个函数,有下列3种方法:用结构体变量名作参数.一般较少用这种方法.用指向结构体变量 结构体变量.结构指针变量.结构数组作为函数的参 ...
- 方法参数是结构体指针,报错信息是空指针怎么办
方法参数是结构体指针,报错信息是空指针怎么办 如果是函数方法需要使用前面定义的结构体指针,但这时候指针为空,编译器报错指针为空,这时候只需要在我们需要指针的地方加上 if(T){}; 确保它不为空就行 ...
- c++结构体嵌套结构体_Go学习每日一问(13)-结构体嵌套
每次学习并整理一个Golang的知识点,每天进步一点点.今天学习一个go结构体嵌套的知识点. 日省吾身 1.下面这段代码的输出结果? func main() { a := -7 b := +7 fmt ...
- 2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[derive(Builder)] pub stru
2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法. 宏使用如下: #[derive(Builder)] pub stru ...
- C语言定义一个结构体方法,C语言结构体定义的方法汇总
什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...
- C语言结构体的作用、定义、使用方法以及实例
目前已学的数据类型:数组(1.所有数据的类型必须一致 2.访问数组的成员必须通过下标) 学籍管理系统:学生(姓名.学号.性别.年龄.成绩...) 飞机票订票系统:机票(订票时间.班号.起点.终点. ...
- 11【C语言 趣味算法】个人所得税问题(结构体应用):结构体的声明、定义结构体类型的三种方法等
Contents 一.Review 二.New Problem:Personal income tax issues(个人所得税问题) 2.1 Description of the problem 2 ...
- 【C 语言】结构体 ( 结构体类型定义 | 结构体类型别名 | 声明结构体变量的三种方法 | 栈内存中声明结构体变量 | 定义隐式结构体时声明变量 | 定义普通结构体时声明变量 )
文章目录 一.结构体类型定义 二.结构体类型别名 三.结构体类型变量声明 1.使用结构体类型 ( 别名 ) 声明变量 2. 定义隐式结构体时声明变量 3.定义普通结构体时声明变量 二.完整代码示例 一 ...
- c 结构体转byte_C中结构体和字节流的互换及内存对齐
mystruct p; char buff[50]; memcpy(buff,&p,sizeof(p)); //把p的内容以字节形式拷贝到buff中 mystruct* q; q = (mys ...
最新文章
- matlab 12脉波变压器,12脉波中频炉专用变压器外形尺寸
- SQL Server 求结果
- 合并的表格怎么加横线_excel表格如何在数据之间加横线-在excel里怎么添加单元格横线...
- [C#]泛型与非泛型集合类的区别及使用例程,包括ArrayList,Hashtable,ListT,DictionaryTkey,Tvalue,SortedListTkey,Tvalue,...
- java中重新加载指定文件_java-更改后重新加载属性文件
- 【LeetCode】4月5日打卡-Day21-最大子序和问题
- Apsara Stack 技术百科 | 可运营的行业云,让云上资源跑起来
- uplift 模型开源包(causalml)尝试
- RGB格式转换的实现
- Java初学者作业——定义客户类(Customer),客户类的属性包括:姓名、年龄、电话、余额、账号和密码;方法包括:付款。
- 树莓派 Pico ADC温度测量
- 计算机管理中其它设备问号,Win10设备管理器中设备上有白色问号如何解决
- mysql加减时间-函数-时间加减
- 乱七八糟之处理器天梯图
- 回到那个夏天(千与千寻)
- 关联规则与强关联规则计算
- 绷紧数据安全这根弦 数据安全法 实施参考发布
- 国科大--多媒体分析与理解--2019考试试题
- a16z:工作的未来是 DAO 和加密网络
- unity3D 魔兽争霸游戏开发案例教程
热门文章
- python爬虫哪个选择器好用_Python网络爬虫四大选择器用法原理总结
- gethours_日期getHours()方法以及JavaScript中的示例
- NVIDIA Jetson Nano B01 安装Ubuntu 18.04.3 LTS
- 跌倒识别 摔倒识别 -lightweight_openpose
- vCenter Server Appliance(VCSA )6.7部署指南
- Bootstrap-select使用说明
- 了解mysql processlist_哪些MySQL processlist状态要引起关注
- 拼团功能实现 php_PHP实现微信提现功能
- 自动提示_EXCEL2013版突然打不开,自动修复提示1907错误
- java提取多行嵌套div/div内容的正则表达式_提取某一段div标签之间内容的正则表达式怎么写...