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

相关推荐
程序猿DD4 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i6 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8267 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
死磕音视频7 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
凤山老林8 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne9 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF9 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li9 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
顽疲10 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog10 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友