Golang Go语言中用 & 返回对象和直接返回对象有啥区别?

发布于 1周前 作者 caililin 来自 Go语言

楼主这几天心血来潮,看了下 golang 语法(本身是 java 出身),发现一个让我疑惑的问题:

代码如下

写法一:

package factory

type Api interface { Say(name string) string }

type SimpleApi struct { }

func (*SimpleApi) Say(name string) string { return "this is " + name }

func CreateApi(t int) Api { if t == 1 { // 只能这样写 return &SimpleApi{} } return nil }

写法二:

package factory

type Api interface { Say(name string) string }

type SimpleApi struct { }

func (SimpleApi) Say(name string) string { return "this is " + name }

func CreateApi(t int) Api { if t == 1 { // 两种写法皆可 //return &SimpleApi{} return SimpleApi{} } return nil }

不能理解的是,为什么写法一不能写成 return SimpleApi{}

golang 不是可以隐式的进行取地址和解引用操作吗? 基于 golang 1.18


Golang Go语言中用 & 返回对象和直接返回对象有啥区别?

更多关于Golang Go语言中用 & 返回对象和直接返回对象有啥区别?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

17 回复

因为写法二是拷贝,取和解是一样的,写法一则不是,每次取的都不是预期结果

更多关于Golang Go语言中用 & 返回对象和直接返回对象有啥区别?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


变量自动取地址和指针自动解引用是在方法的调用阶段,为了方便所以加了这样的语法糖。
而案例中 return 值到 interface 变量,是在方法的定义阶段,可能这时候不让具体类型变量满足指针 receiver 的 interface ,为了强调吧。当然假如不是这种设计,像 op 期待的那样,返回值是具体类型,自动取地址以满足指针 recieve 的 interface ,实现上应该也是可以的,只不过设计者没有做这种选择。我个人还是觉得就是为了在方法的定义阶段强调返回值的正确性吧。

Anyway ,暴露指针而不是采用引用类型,可能是 Go 的缺点之一吧。(如果采用引用类型又可能会带来什么问题,我没有了解)。

根本原因是 go 中参数传递都是值传递,编译器为了不出错做了这个兼容。用 java 的话说,写法一中的 Say 是个实例方法,所以必须传回实例,写法二中的方法是个类方法,你传回实例或者类都行。

用 go 的逻辑说,写法一中如果可以传回结构体,那么函数调用方拿到的是该返回结构体的拷贝,并不能修改和访问真正在 CreateApi 中创建的那个 SimpleApi 结构体,但是定义的 Say 方法是个指针方法,代表它应该可以访问和修改内部那个结构体,所以冲突了。

go 这种语言设计都是做一半不做一半,也不是一天两天的事了

返回 SimpleApi 是拷贝,返回&SimpleApi 是指针.

Javaer 不应该用 new 吗,Go 是可以用 new 的。

还是建议都来 C++,自己封装个 interface 类,什么引用、指针、右值都能分别捕获,不要太爽。

你的例子里面 simpleApi 没有私有变量,加一个比如 id 然后 say 的例子用 id 加 name ,然后调用过程修改 id 试试就知道区别了

因为一是 *SimpleApi 实现的 API, 二是SimpleApi实现的API. 两者不一样, 因为返回值是API, 所以哪个实现了API才能返回.

看了大佬的解释一下就明白了

感谢大佬找的两篇文章,明白原因了

指针,指针,指针

https://go.dev/doc/effective_go#pointers_vs_values 看文档应该是在编译阶段吧 不是调用阶段

建议用 2 ,能不用指针就别用,否则空指针 panic 就难受了。只有传大结构体时才用指针。多人都会有种误解,认为传 struct 的指针比复制一份值快很多,所以喜欢传 struct 的指针。但实际上并不是的,指针引用的对象是分配到堆上的,在函数内使用指针引用的值都需要取堆去取,并且堆中的内存受 GC 管理会增加 GC 压力。而传值的话复制后的值会直接分配在栈上,栈的速度比堆快,并且函数执行完毕后栈会销毁没有 GC 之类的压力。

其实这个 best practice 有点迷,就是“多大的 struct 算大”,一般成员变量不超过 5 个我会直接复制,但是超过 5 个用指针是否合适我也不知道啊…

在Golang(Go语言)中,使用 & 返回对象和直接返回对象的主要区别在于返回的是值的拷贝还是指针。

  1. 直接返回对象:当你直接返回一个对象(如结构体、数组、切片等)时,你实际上返回的是该对象的一个副本。这意味着调用者得到的是一个新的、独立的对象,对返回对象的修改不会影响到原始对象。这种方式适用于小对象,因为它避免了指针的复杂性,且由于Go的内存管理机制(逃逸分析和垃圾回收),性能影响通常可以忽略不计。

  2. 使用 & 返回对象:当你使用 & 运算符返回对象时,你返回的是该对象的内存地址,即一个指向该对象的指针。调用者通过指针可以访问和修改原始对象。这种方式适用于大对象或当你需要让调用者能够修改原始对象时。然而,使用指针增加了代码的复杂性,并可能导致悬挂指针或内存泄漏等问题,因此需要谨慎处理。

总结来说,选择直接返回对象还是使用 & 返回对象取决于你的具体需求。对于小对象且不需要修改原始对象的情况,直接返回对象通常是更好的选择。对于大对象或需要修改原始对象的情况,使用 & 返回对象可能更合适。在设计接口时,应仔细考虑这些因素,以确保代码的清晰性和健壮性。

回到顶部