golang-学习笔记-结构(struct)与方法(method)
在写过很多go代码之后,感觉自己并没有完全掌握go语言,还有很多知识盲区,所以有了这个go学习笔记系列,本系列是作者跟着电子书重新复习go语言相关内容的笔记
可以通过 new 函数来创建
组成结构体类型的那些数据称为 字段(fields)
结构体定义
|
|
结构体里的字段都有 名字,如果字段在代码中从来也不会被用到,那么可以命名它为 _。
结构体的字段可以是任何类型
使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T)
使用 fmt.Println 打印一个结构体的默认输出可以很好的显示它的内容,类似使用 %v 选项。
使用点号符给字段赋值:structname.fieldname = value
.Go 语言中这叫 选择器(selector).
为选择器符(selector-notation).指针使用.
操作会自动解引用
结构体能够定义在函数中,但是这种情况下只能函数可见,并且该类型不能作为返回值
初始化一个结构体实例:
|
|
混合字面量语法(composite literal syntax)&struct1{a, b, c} 是一种简写,底层仍然会调用 new (),这里值的顺序必须按照字段顺序来写。
结构体类型和字段的命名遵循可见性规则
结构体的内存布局:结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体
递归结构体:
|
|
结构体转换:当为结构体定义了一个 alias 类型时,此结构体类型和它的 alias 类型都有相同的底层类型,它们可以互相转换,使用强制类型转换typeA(b)
使用自定义包中的结构体
大写字母开头可见
带标签的结构体
标签的内容不可以在一般的编程中使用,只有包 reflect 能获取它,reflect.Field结构体的Tag属性存这个字符串,Tag字段的Get可以获取某一个键值对不过也是返回字符串
|
|
匿名字段和内嵌结构体
结构体可以包含一个或多个 匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型就是字段的名字。
匿名字段本身可以是一个结构体类型,即 结构体可以包含内嵌结构体
只有内嵌结构体能继承方法,类型别名也不能继承方法
go的继承行为
|
|
在一个结构体中对于每一种数据类型只能有一个匿名字段
访问其他包的匿名字段时直接通过最后的结构体名访问即可,比如
|
|
命名冲突
当两个字段拥有相同的名字(可能是继承来的名字):
- 外层名字会覆盖内层名字(但是两者的内存空间都保留),这提供了一种重载字段或方法的方式;
- 如果相同的名字在同一级别出现了两次,如果这个名字被程序使用了,将会引发一个错误(不使用没关系)。没有办法来解决这种问题引起的二义性,必须由程序员自己修正。
|
|
使用 c.a 是错误的,到底是 c.A.a 还是 c.B.a 呢?会导致编译器错误
方法
方法是什么
|
|
如果方法不需要使用 recv 的值,可以用 _ 替换它,比如:
|
|
recv 就像是面向对象语言中的 this 或 self,仍然是值拷贝
类型和作用在它上面定义的方法必须在同一个包里定义,这就是为什么不能在 int、float 或类似这些的类型上定义方法。
有一个间接的方式:可以先定义该类型(比如:int 或 float)的别名类型(这里指的是不使用"=“的类型定义),然后再为别名类型定义方法。
函数和方法的区别
方法没有和数据定义(结构体)混在一起:它们是正交的类型;表示(数据)和行为(方法)是独立的。
没啥区别,多了个默认参数recv,另外recv可以自动进行取地址,即使用引用可以接收示例
指针或值作为接收者
鉴于性能的原因,recv 最常见的是一个指向 receiver_type 的指针(因为我们不想要一个实例的拷贝,如果按值调用的话就会是这样),特别是在 receiver 类型是结构体时,就更是如此了。
如果想要方法改变接收者的数据,就在接收者的指针类型上定义该方法。否则,就在普通的值类型上定义方法。
指针方法和值方法都可以在指针或非指针上被调用
方法和未导出字段
可以给未导出字段添加Getter或Setter方法
并发访问对象:使用sync包进行并发安全控制
内嵌类型的方法和继承
当一个匿名类型被内嵌在结构体中时,匿名类型的可见方法也同样被内嵌,这在效果上等同于外层类型 继承 了这些方法:将父类型放在子类型中来实现亚型。
如何在类型中嵌入功能
主要有两种方法来实现在类型中嵌入功能:
A:聚合(或组合):包含一个所需功能类型的具名字段。
B:内嵌:内嵌(匿名地)所需功能类型
多重继承
但是在 Go 语言中,通过在类型中嵌入所有必要的父类型,可以很简单的实现多重继承
通用方法和方法命名
约定,鸭形语言
和其他面向对象语言比较 Go 的类型和方法
总结
类型就是类(数据和关联的方法)
代码复用通过组合和委托实现,多态通过接口的使用来实现:有时这也叫 组件编程(Component Programming)
类型的 String() 方法和格式化描述符
String() 方法: fmt.Printf() 中生成默认的输出:等同于使用格式化描述符 %v 产生的输出。 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。
不要在 String() 方法里面调用涉及 String() 方法的方法,会陷入无限递归。
垃圾回收和 SetFinalizer
Go 运行时中有一个独立的进程,即垃圾收集器(GC),可以通过 runtime 包访问 GC 进程
runtime.GC() 函数显式的触发 GC,
给出已分配内存的总量,单位是 Kb
|
|
设置一个对象 obj 被从内存移除前执行一些特殊操作:
|
|
结构体比较
结构体是否可比较:
- 结构体名同(如果某一个结构体为匿名结构体也可比较)
- 属性类型同
- 属性个数同
- 属性名同
- 属性顺序同
- 属性可比较(map,slice不可比较,chan可比较)
结构体是否相同:
- 属性值同