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

相关推荐
凡人的AI工具箱32 分钟前
40分钟学 Go 语言高并发:【实战】并发安全的配置管理器(功能扩展)
开发语言·后端·安全·架构·golang
我的运维人生40 分钟前
Spring Boot应用开发实战:构建RESTful API服务
spring boot·后端·restful·运维开发·技术共享
颜淡慕潇1 小时前
【K8S系列】深入解析 Kubernetes 中的 Deployment
后端·云原生·容器·kubernetes
vvw&1 小时前
使用同一个链接,如何实现PC打开是web应用,手机打开是一个H5应用
开发语言·前端·javascript·智能手机·面试题·每日一道前端面试题
Iced_Sheep1 小时前
Spring @Transactional 你真的会用吗???
后端·spring
黑客Ela2 小时前
网络安全加解密原理
开发语言·php
MATLAB代码顾问2 小时前
MATLAB实现多种群遗传算法(multiple population GA,MPGA)
开发语言·matlab
wqyc++2 小时前
C++ 中的 Lambda 表达式
开发语言·c++
黄昏_2 小时前
在Springboot项目中实现将文件上传至阿里云 OSS
java·spring boot·后端·阿里云
成为不掉头发的工程师2 小时前
conda下载与pip下载的区别
开发语言·python