结构体类型可以包含若干字段,每个字段通常都需要有确切的名字和类型。也可以不包含任何字段,这样并不是没有意义的,因为还可以为这些类型关联上一些方法,这里可以把方法看作事函数的特殊版本。

  函数事独立的程序实体,可以声明有名字的函数,也可以声明没名字的函数,还可以把它们当作普通的值传来传去(把具有相同签名的函数抽象陈独立的函数类型,作为一组输入或输出的代表)。方法则不同,它需要名字,不能被当作值来看待,更重要的是,它必须隶属于某一个类型。方法所属的类型会通过期声明中的接收者声明(关键字func和方法名称之间那个圆括号包裹起来的内容,其中必须包含确切的名称和类型字面量,这个接收者的类型其实就是当前方法所属的那个类型,而接收者的名称则用于在当前方法中引用它所属的类型的当前值)体现出来。

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)
}

  从String方法的接收者声明可以看出,它隶属于AnimalCategory类型。通过该方法的接收者名称ac,可以在其中引用到当前的任何一个字段或者调用到当前值的任何一个方法(包括string方法自己)。使用时可以这样表示

    category := AnimalCategory{species: "cat"}
fmt.Printf("The animal category: %s\n", category)

  在Go语言中,可以通过为一个类型编写名为String的方法,来自定义该类型的字符串表示形式,这个String方法不需要任何参数声明,但需要一个string类型的结果声明。正因为如此,在调用fmt.Print函数时,无需显式调用它的string方法,fmt.Print会自己去寻找它。

  方法隶属的类型并不局限于结构图,但必须时某个自定义的数据类型,并且不能时任何接口类型。一个数据类型关联的所有方法,共同组成了该类型的方法集合。同一个方法集合中的方法不能出现重名,并且如果它们所属的是一个结构图类型,那么它们的名称与该类型中任何字段的名称也不能重复。

  可以把结构体类型中的一个字段看作是它的一个属性或一项数据,再把隶属于它的一个方法看作是附加再其中数据之上的一个能力或一项操作。将属性及其能力封装再一起,是面向对象编程的一个主要原则。

1、结构体嵌入字段

  Go语言规范规定,如果一个字段的声明中只有字段的类型名而没有字段的名称,那么它就是一个嵌入字段。可以通过此类型变量的名称后跟“.”,再后跟嵌入字段类型的方法引用到该字段。

type Animal struct {
scientificName string // 学名。
AnimalCategory // 动物基本分类。
} func (a Animal) Category() string {
return a.AnimalCategory.String()
}

  Category方法的接收者类型是Animal,接收者名称是a。在该方法中,通过表达式a.AnimalCategory选择到了a这个嵌入字段,然后又选择了该字段的String方法并调用了它。

  把一个结构体类型嵌入到另一个结构体中的,嵌入字段的方法集合会被无条件地合并进被嵌入类型地方法集合中。

    animal := Animal{
scientificName: "American Shorthair",
AnimalCategory: category,
}
fmt.Printf("The animal: %s\n", animal)

  这里声明了Animal类型地变量animal并对它进行初始化,把字符串值“American Shorthair”赋值给它的字段scientificName,并把前面声明过的变量category赋给它的嵌入字段AnimalCategory

  那再后面使用fmt.Printf函数相当于调用animal的String方法(虽然还没有为Animal类型编写String方法,但这样做并没有问题,因为嵌入字段AnimalCategory的String方法会被当做animal的方法调用)

  那如果为Animal类型也编写一个String方法呢?会调用哪一个?

  答案是animal的String方法会被调用,AnimalCategory的String方法被屏蔽掉了。注意:只要名称相同,无论这两个方法的签名是否一致,被嵌入类型的方法都会屏蔽掉嵌入字段的同名方法。

  同样,如果两个结构体类型中存在同名的字段,那嵌入字段中的那个字段一定会被“屏蔽‘。即使是两个同名的成员,一个是字段,一个是方法,这种屏蔽现象依然会存在。

  不过,即使被屏蔽了仍然可以通过链式的选择表达式,选择到嵌入字段的字段或方法。

  当出现多层嵌入时,屏蔽现象会以嵌入的层级为依据,嵌入层级越深的字段或方法越可能被屏蔽。如果同一层级的多个嵌入字段拥有同名的字段或方法,那么被嵌入类型的值那里,选择此名称的时候就会引发一个编译错误。

2、Go语言用嵌入字段实现了继承吗?

  Go语言中根本没有继承的概念

  它所做的事通过嵌入字段的方式实现了类型之间的组合。

  面向对象编程中的继承事通过牺牲一定的代码简洁性来换取可扩展性,这种可扩展性事通过侵入的方式实现的。

  而类型之间的组合采用的是非声明的方式。不需要显式声明,而且也非侵入式的。只是通过嵌入字段的方式把一个类型的属性和能力嫁接给另外一个类型

3、值方法和指针方法都是什么意思?有什么区别

  方法的接收者必须是某个自定义的数据类型,而且不能是接口类型或接口的指针类型。

  值方法就是接收者是非指针的自定义数据类型的方法。前面的AnimalCategory、Animal声明的那些方法都是值方法。

type Cat struct {
name string
Animal
} func (cat *Cat) SetName(name string) {
cat.name = name
}

  方法SetName的接收者类型是*Cat(Cat类型的指针类型)。那指针方法,就是接收者类型是指针类型的方法

  区别:

    1)值方法的接收者是该方法所属的那个类型值的一个副本,在该方法内对该副本的修改一般不不会体现在原值上(除非这个类型本身是某个引用类型(如切片或字典)的别名类型)。

      指针方法的接收者,是该方法所属那个基本类型值的指针值的一个副本,这样的方法内对该副本指向值的进行修改,一定会体现在原值上。

    (2)一个自定义数据类型的方法集合中仅会包含它的所有值方法

      而该类型的指针类型的方法集合却包含了所有值方法和所有指针方法

[Go]结构体及其方法的更多相关文章

  1. 六、golang中的结构体和方法、接口

    结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...

  2. Go part 5 结构体,方法与接收器

    结构体 结构体定义 结构体的定义只是一种内存布局的描述(相当于是一个模板),只有当结构体实例化时,才会真正分配内存空间 结构体是一种复合的基本类型,通过关键字 type 定义为 自定义 类型后,使结构 ...

  3. go结构体的方法和普通函数

    package main import ( "fmt" "math" ) type vertex struct { X, Y float64 } //值接收者是 ...

  4. go 结构体与方法

    go 结构体与方法   go 结构体相当于 python 中类的概念,结构体用来定义复杂的数据结构,存储很多相同的字段属性 结构体的定义 1.结构体的定义以及简单实用 package main imp ...

  5. go结构体与方法

    go结构体相当于python中类的概念 结构体用来定义复杂的数据结构,存储很多相同的字段属性 1.结构体的定义以及简单实用 package main import ( "fmt" ...

  6. Go 语言 结构体和方法

    @ 目录 1. 结构体别名定义 2. 工厂模式 3. Tag 原信息 4. 匿名字段 5. 方法 1. 结构体别名定义 变量别名定义 package main import "fmt&quo ...

  7. Go基础之--结构体和方法

    结构体的定义 结构体是将零个或者多个任意类型的命令变量组合在一起的聚合数据类型.每个变量都叫做结构体的成员. 其实简单理解,Go语言的结构体struct和其他语言的类class有相等的地位,但是GO语 ...

  8. go的基结构体如何使用派生结构体的方法

    将派生类的方法声明为接口嵌入到基结构体中,派生结构体声明该接口为自身.

  9. go_结构体和方法

    面向对象:go语言仅支持封装不支持继承和多态 所以go语言没有class,只有struct(结构体) 无论地址还是结构本身,一律用 . 来访问成员 go语言编译器可以自动区分是值传递还是指针传递,值传 ...

  10. Go语言 6 结构体、方法和接口

    文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 结构体(struct)是由一系列具有相同类型或不同类 ...

随机推荐

  1. 关于在@Controller所返回的视图的css,js文件404问题

    本人在使用layui打开一个请求后台的页面时,页面成功由controller重定向到了正确的位置,然而几乎所有的js文件和css文件都报404,并且确定这些css文件还有js文件的引入的路径都是正确的 ...

  2. 130 Surrounded Regions 被围绕的区域

    给定一个二维的矩阵,包含 'X' 和 'O'(字母 O), 找到所有被 'X' 围绕的区域.并将区域里所有 'O'用 'X' 填充.例如,X X X XX O O XX X O XX O X X运行你 ...

  3. 用NPOI从DataTable到Excel,向Excel模板填充数据

    DataTable---->Excel,填充数据 private IWorkbook workbook = null; private ISheet sheet = null; private ...

  4. 初识jstl标签库

    JSTL(JSP Standard Tag Library,JSP标准标签库) 是一个不断完善的开源的 JSP 标签库,是由 apache 的 jakarta 小组来维护的,根据 JST L标签所提供 ...

  5. 获取第三方软件的包名、入口Activity的类名

    要启动指定的第三方软件,需要知道第三方软件的包名.类名. 获取第三方软件包名.类名的两种方法: 1.使用aapt aapt是sdk自带一个工具,在 Sdk\builds-tools 目录下 .如果没有 ...

  6. 【学习笔记】深入理解js原型和闭包(16)——完结

    之前一共用15篇文章,把javascript的原型和闭包讲解了一下. 首先,javascript本来就“不容易学”.不是说它有多难,而是学习它的人,往往都是在学会了其他语言之后,又学javascrip ...

  7. jdbc获取数据具体过程

    下面是个最简单的使用jdbc取得数据的应用.在例子之后我将分成4步,分别是①取得连接,②创建PreparedStatement,③设置参数,④执行查询,来分步分析这个过程.除了设置参数那一步之外,其他 ...

  8. CentOS 7上修改主机名

                                       如何在CentOS 7上修改主机名                                           在Cent ...

  9. uva1612 Guess

    和cf的打分有点像啊 因为一共只有三道题,所以每个人的得分最多有8种可能性.把这8种可能性都算出来,存在数组里,排好序备用排名就是一个天然的链表,给出了扫描的顺序扫描时,维护两个变量:前一个playe ...

  10. 自己封装一个readline函数实现服务器客户端回射

    实现的功能:一次只能读取一行,客户端输入之后,一回车,马上字符串传到服务器端并显示在终端,然后服务器端将字符串又传回给客户端. 服务器端可以接收多个客户端的连接请求,并fork一个子进程来进行服务. ...