【Go】A和*A在作为Receiver和接口实现上的差别

内容均来自 https://www.bilibili.com/video/BV1Eb4y1F7b9

https://juejin.cn/post/6963476381728702501

什么时候要使用指针接收器?

1.A很大,因为Go语言在执行函数时会进行参数的拷贝,拷贝一个大的对象和拷贝一个

指针相比代价肯定要大。

2.当方法中要修改A本身的数据时。同样是因为拷贝的原因,对于拷贝对象的修改不

会影响原对象

go 复制代码
type I1 interface{
	F1()
}
type I2 interface{
    F1()
    F2()
}
type T1 struct{
   d int
}
func(t T1)F1(){
   fmt.Printin("F1",t.d)
}
func(t *T1)F2(){
   fmt.Printin("F2",t.d)
}
//OK
var _ I1=T1
//OK
var _ I1=&T1
//OK
var _ I2=&T1
//Not OK
var _ I2=T1

如果一个类型A实现了某方法,就相当于*A也实现了该方法。
反过来不成立。

前提A本身不能是指针类型,如果*A实现了某方法,对于**A没有影响。

所以A实现了的接口,*A一定也实现了。

反过来不一定。

A是如何调用*A的方法的 (互相调用)

可以认为是golang中的一种语法糖

go 复制代码
func (s *mystruct)Read(data []byte)(int,error){
	return 0,nil
} 

如果有了上面的不允许再定义下面的
func (s myStruct)Read(data []byte)(int,error){
	return 0,nil
}

不管在上面是谁实现了Read方法,下面的两段代码都是0K的
a:=mystruct{}
a.Read(nil)

b:=&mystruct{}
b.Read(nil)
go 复制代码
type A struct
	d int
}
func(a *A)F1(× int)(
	a.d+=x
}
func main(){
	a:=A{d:10}
	a.F1(5)  //等于(&a).F1(5)
	fmt.Println(a.d)
}
go 复制代码
type A struct{
	d int
}
func(a A)F2(x int){
	a.d+=x
}
func main(){
	a:=&A{d:10}
	a.F2(5)  //等于(*a).F2(5)
	fmt.Println(a.d)//结果还是10
}

*A拥有A的所有方法。对A的方法做了包装,先做指针解引用,再调用A的方法。

*A的变量可以直接调用A的方法,处理逻辑同上

可以理解为语法糖,也可以理解为对于上面的包装后的方法的调用。

A没有A的方法
A的变量可以直接调用
A的方法,处理逻辑是先取指针,再调用*A的方法。

只能理解为是语法糖。

https://stackoverflow.com/questions/48790663/why-value-stored-in-an-interface-is-not-addressable-in-golang

https://go.dev/doc/faq#different_method_sets

为什么要让*A拥有A的所有方法?

可能的原因:

1.*A调用A的方法的过程总是安全的。

2.*A调用A的方法的结果总是符合预期的,而且是有益的。

不太可能是因为接口实现的需要而实现这样的特性。

1.这是在Go的Spec里面设定的行为,正常的顺序是Spec在前,实现在后。

2.Go语言在设计层面并没有对接口实现做设定,所以不允许取接口的地址

为什么不让A拥有*A的方法?

go 复制代码
看一个例子,假设A拥有*A的方法,下面的代码将是正确的,但是结果不符合预期
var buf bytes.Buffer
io.Copy(buf,os.Stdin)//将数据拷贝到buf里面


//相关代码
func Copy(dst Writer,src Reader)(written int64,err error){
	return copyBuffer(dst,src,nil)
}
type Writer interface{
	Write(p []byte)(n int,err error)
}
func (b *Buffer)Write(p []byte)(n int,err error){
}

如果让A拥有A的方法,也就是让A实现A所实现的接口,此时将A作为接口类型的变量使用,与*A的行为是有差异的,而且是我们不想要的行为。

相关推荐
秃头佛爷7 分钟前
Python学习大纲总结及注意事项
开发语言·python·学习
待磨的钝刨8 分钟前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉4 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer4 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
码农小旋风4 小时前
详解K8S--声明式API
后端
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍