go语言代码记知识点 go语言编程入门与实战技巧( 六 )


通过这个测试用例可以发现,指针接收者实现的接口可以同时支持转移到值接收者接口和指针接收者接口,而用值接收者实现的接口 , 则无法转移到使用指针接收者实现的接口,为啥子呢?目前网上或者各类资料上都是给的一个很官方很官方,而且很书面话难以理解的说明,大致意思如下:
这是目前网络或者各种资料上都是差不多是这样说的 , 看似讲了,实际上就说了一个结果,根本就没说出来一个为什么 。这样的总结出来,一个初学者的角度来看 , 是很不好理解的 , 初学者要么就是死记硬背,要么就是生搬硬套 , 甚至直到写了好多好多代码了,都还没有搞明白一个为啥子,只是会用了而已,从长远来说这是不利于自身提高的 。
有这两个本质点,咱们自己来思考一下,如果你来实现这个编译器的时候,用指针接收的时候,指针接收者,默认就能直接获取支持,而值接收者实现接口的咱们可以直接来一个解指针就变成了值 , 就能匹配上值接收者实现的接口了,反过来说,如果值接收者,此时要匹配指针接收者,如何匹配呢,取一个地址就变成了指针了,此时数据类型确实是匹配了,但是,地址指向的数据区不对了,因为我们刚刚说了值接收者拷贝了一个新值之后是完全的一个新的对象 , 这个新对象和原始对象一点关系都没有 , 咱们取地址 , 取的也是这个新对象地址,对这个地址进行操作,也是这个新对象的内部数据,和原始数据内部没有任何关系,所以由此就能推断出,这个是为啥子值接收者不能匹配上指针接收者,而指针接收者却可以匹配上值接收者了 。
1、在某个作用域内部,所有定义的字符串的数据区相同
这个很好验证 , 代码如下:
2、字符串相加会产生一个新串
这个也很好验证
3、字符串真的是不可变的吗
实际上从字符串的结构
从这个结构,就能大致的推断出来,字符串设计成这样就不具备直接扩容+来增加新数据 , 而如果咱们直接使用string[index] = 'a',用这种方式,就不能编译通过,官方也确定说字符串是不可变的 。那么真的是不可变的吗?
通过上面的结构,在加上go的slice切片的数据结构
由此可见 , 咱们可以将字符串通过指针方式强转为一个byte数组指针,然后通过byte切片来修改 , 试试
编译通过,运行报错
unexpected fault address 0xae2e27
fatal error: fault
这个错误,基本上就是一个内存的保护错误 , 是写异常 , 所以说明了,这个肯定做了内存写保护,那么直接修改一下内存区的属性 , 去掉他的写保护 , 就能写了
以下代码都是在Win平台,Go1.18,Win上修改内存权限属性,使用VirtualProtect,代码如下
此时运行 , 就能发现tstr的内容被咱们变了,这种情况实际上在实际开发中不具有实际意义,因为本身在语言层面,已经做了层层限制 , 咱们这是属于非法强制的操作方式 , 是流氓行为,那么是否有比较温和一点的操作方式呢?答案是有的,且往下看 。
通过上面,我们已经用到了字符串结构,切片结构,要想字符串内容可变 , 那么咱们自己构造字符串的数据内容区域,且让这个数据区木有内存写保护不就行了,内容区可变,GO原生态的byte数组不就行嘛,所以咱们自己构造一下
此时我们直接修改buffer的内容,就是直接修改了str的数据内容了 。而又不会像前面的一样遇到内存写保护

推荐阅读