go语言封装是怎么回事( 四 )


回到面向对象的传统编程规范上,一般实例化对象用的是关键字 new,而 new 并不是 Go 中的关键字.
Go 语言中的函数是一等公民,正如刚才说的 make 也不是关键字,同样是函数.

go语言封装是怎么回事

文章插图
 
即便对于同一个目标,Go 也是有着自己的独到见解!
new 不是以关键字形式出现而是以函数的身份登场,初步推测应该也具备实例化对象的能力吧?
go语言封装是怎么回事

文章插图
 
难道 new 函数不能实例化对象?为什么报错说赋值错误,难不成姿势不对?
吓得我赶紧看一下 new 的文档注释.
go语言封装是怎么回事

文章插图
 
根据注释说明,果然是使用姿势不对,并不像其他的面向对象语言那样可以重复赋值,Go 不支持这种形式,还是老老实实初始化声明吧!
go语言封装是怎么回事

文章插图
 
既然存在着两种方式来实例化对象,那么总要看一下有什么区别.
go语言封装是怎么回事

文章插图
 

go语言封装是怎么回事

文章插图
 
这里简单解释下 t.Logf("%[1]T %[1]v", myDynamicArray) 语句是什么意思?
%[1]T 其实是 %T 的变体,%[1]v 也是 %v 的变体,仔细观察的话就会发现占位符刚好都是同一个变量,这里也就是第一个参数,所以就用 [1] 替代了,再次体现了 Go 语言设计的简洁性.
下面再举一个简单的例子加深印象,看仔细了哦!
go语言封装是怎么回事

文章插图
 
%T 是打印变量的类型,应该是类型 type 的缩写,v 应该是值 value 的缩写.
解释清楚了测试代码的含义,再回头看看测试结果,发现采用字面量方式得到的变量类型和 new 函数得到的变量类型明显不同!
具体表现为 _struct.MyDynamicArray {0xc0000560f0 10 10} 是结构体类型,而 *_struct.MyDynamicArray &{0xc000056190 10 10} 是结构体类型的指针类型.
这种差异也是可以预期的差异,也是符合语义的差异.
字面量实例化的对象是值对象,而 new 实例化对象开辟了内存,返回的是实例对象到引用,正如其他编程语言的 new 关键字一样,不是吗?
既然说到了值对象和引用对象,再说一遍老生常谈的问题,函数或者说方法传递时应该传递哪一种类型?
值传递还是引用传递接下来的示例和动态数组并没有什么关系,简单起见,新开一个结构体叫做 Employee,顺便回顾一下目前学到的封装知识.
go语言封装是怎么回事

文章插图
 
首先测试引用传递,这也是结构体常用的传递方式,行为表现上和其他的主流编程语言表现一致,方法内的修改会影响调用者的参数.
go语言封装是怎么回事

文章插图
 

go语言封装是怎么回事

文章插图
 
unsafe.Pointer(&e.Name) 是查看变量的内存地址,可以看出来调用前后的地址是同一个.

go语言封装是怎么回事

文章插图
 

go语言封装是怎么回事

文章插图
 
调用者发送的内存地址和接收者接收的内存地址不一样,符合期望,值传递都是拷贝变量进行传递的嘛!
值类型还是引用类型的区分无需赘述,接下来请关注一个神奇的事情,方法的接收者是值类型,方法的调用者是不是一定要传递值类型呢?
go语言封装是怎么回事

文章插图
 
方法的调用者分别传递值类型和引用类型,两者均能正常工作,是不是很神奇,好像和方法的定义没什么关系一样!
go语言封装是怎么回事

文章插图
 

go语言封装是怎么回事

文章插图
 
虽然方法的接收者要求的是值类型,调用者传递的是值类型还是引用类型均可!

go语言封装是怎么回事

文章插图
 
仅仅更改了方法接收者的类型,调用者不用做任何更改,依然可以正常运行!


推荐阅读