【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的行为是有差异的,而且是我们不想要的行为。

相关推荐
yttandb10 分钟前
重生到现代之从零开始的C语言生活》—— 内存的存储
c语言·开发语言·生活
我明天再来学Web渗透13 分钟前
【hot100-java】【二叉树的层序遍历】
java·开发语言·数据库·sql·算法·排序算法
结衣结衣.27 分钟前
python中的函数介绍
java·c语言·开发语言·前端·笔记·python·学习
程序员陆通28 分钟前
Spring Boot RESTful API开发教程
spring boot·后端·restful
茫茫人海一粒沙30 分钟前
Python 代码编写规范
开发语言·python
原野心存30 分钟前
java基础进阶知识点汇总(1)
java·开发语言
程序猿阿伟33 分钟前
《C++高效图形用户界面(GUI)开发:探索与实践》
开发语言·c++
暗恋 懒羊羊41 分钟前
Linux 生产者消费者模型
linux·开发语言·ubuntu
五味香1 小时前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
无理 Java1 小时前
【技术详解】SpringMVC框架全面解析:从入门到精通(SpringMVC)
java·后端·spring·面试·mvc·框架·springmvc