Golang Go语言中初学,有一个关于 Pointer receiver 的问题

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

Golang Go语言中初学,有一个关于 Pointer receiver 的问题

根据 Go 文档中的例子 (链接), 如果 receiver 的类型是 *T ,那么传入的是指针;如果类型是 T, 则传入的是值的拷贝。 但是我在写代码的时候遇到一个奇怪的现象,明明我传入的是拷贝,但是函数对拷贝的操作影响到了原来的值。具体请看一面的代码:

package main

import (
	"fmt"
)

type A struct {
	a int
}

type Alist []*A

func (a Alist) swap(i int, j int) {
	a[i], a[j] = a[j], a[i]
}

func main() {
	alist := make(Alist, 2)
	alist[0] = &A{a: 3}
	alist[1] = &A{a: 4}
	fmt.Println(alist[0], alist[1]) // 输出: &{3} &{4}
	alist.swap(0, 1)
	fmt.Println(alist[0], alist[1]) // 输出: &{4} &{3}
}

swap 操作应该改变a,即 alist 的复制,而不应该改变 alist 中值的顺序。但事实就是alist的顺序也被改变了。

请各位大神指出我哪里理解错了。


更多关于Golang Go语言中初学,有一个关于 Pointer receiver 的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

18 回复

搞清楚拷贝的到底是什么。就跟 java 从来都没有引用传递一样

更多关于Golang Go语言中初学,有一个关于 Pointer receiver 的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


切片是引用类型

slice 就是引用,引用了底层数组

接收器是一个 []*A 切片,因此传的是引用

浅拷贝啦,拷贝的是 slice 结构体,底层引用的数组是同一个

指针类型,内容是指向内存的另外一个地方,值拷贝,只拷贝了这个指针的内容到一个新的指针,不会把指向的内容再拷贝。

接收器是 slice,你确实是拷贝了 slice 的值。但是 slice 内部存储的是指向数组的指针,操作指针自然会影响原有的值。

数组的结构体中有一个指针,指向存放数组成员的内存区域,再加一个变量,表示一共有多少个成员,( go 中还有个 cap 变量,这里不讨论)
你的例子中传数组是传值,但不影响数组的成员,go 只会拷贝数组结构体(就是上面说的三个变量),但不拷贝数组中的成员(即指针指向的内存区域)

类似的
type A struct {
a int
b *B

type B struct {
c int


如果通过传值传入 A 对象,不影响 A 结构体中引用的 B 结构体的内容,在接受 A 的函数中修改 b.c 一样会表现为传址

指针跟 int 等类型无异,对其进行拷贝不会导致对被指向对象内容的拷贝

饮用类型,和其他语言是类似的,比如 Python list 传进函数里也是可以修改的

1.golang 里传参都是值传递,没有引用传递
2.你这段代码最简单的改法是把声明 make()语句放在 main 函数中,也就是放在方法体外就可以了
3.原理的话可以去网上搜一下,在这就不多做解释了

go 里面能用 make 创建的 3 种类型都是引用类型( chan slice 和 map )
你传递的时候传递的是这个引用的复制

纠正一下我的回复,刚才没太看清问题
1.第一点没有问题,golang 里传参都是值传递,没有引用传递,所谓的引用传递也是地址的值传递
2.这一点有问题,没看清题目,如果你想不改变数组的顺序,可以直接在 swap 方法内第一行加上 a = make(Alist, 2),顺序就不会改变了。注意,加上 a = make(Alist, 2)后输出的 2 行都是 3,4,而不是 3,4 和 nil,nil,这正好说明第一点 golang 里传参都是值传递,没有引用传递

熟悉 c 系语言的同学 会明白 这所谓的浅拷贝 而你期望的是深拷贝

写一波 rust 包你懂

命令式编程的原罪

切片,字典,channel 在 Go 里面就是引用

你好!很高兴你对Go语言中的Pointer receiver(指针接收器)有疑问。在Go语言中,方法接收器可以是值接收器(value receiver)也可以是指针接收器(pointer receiver),选择哪种接收器取决于你的具体需求。

当你使用指针接收器时,你可以改变接收器指向的值。这在某些情况下是非常有用的,比如当你需要在方法中修改结构体的字段时。使用指针接收器还可以避免在每次方法调用时都复制整个结构体,这在结构体较大时可以提高性能。

然而,如果你不需要修改接收器的值,或者结构体非常小,使用值接收器可能会更简单、更直观。值接收器的一个好处是,它们可以让调用者更清楚地知道哪些方法可能会修改数据。

在选择接收器类型时,还有一个重要的考虑因素是代码的一致性。如果你已经开始使用值接收器,并且没有遇到性能问题或需要修改结构体的需求,那么保持一致性可能会更好。

总之,选择值接收器还是指针接收器取决于你的具体需求,包括是否需要修改数据、性能考虑以及代码的一致性。希望这能帮助你更好地理解Go语言中的Pointer receiver。如果你有更具体的问题或示例代码,欢迎继续提问!

回到顶部