英文:
Go: reference types as arguments
问题
在Go语言中,某些类型是引用类型,包括map、slice、channel、函数和方法。
有时候你需要使用指针来引用。例如,
type Stack []interface{}
func (stack *Stack) Push(x interface{}) {
*stack = append(*stack, x)
}
你需要使用指针是因为所有的参数都是通过值的拷贝传递的,而且如果slice的容量不够,append()
函数可能需要重新分配内存。我理解这一点。
第一个问题。 那么map
类型呢?如果我有一个基于map
的自定义类型,如果预期会有一些键值对的插入或删除操作,是不是最好总是传递一个指针给它呢?
第二个问题。 其他引用类型呢?比如Channel
。我可以想象一种情况,我构建了一个基于channel的自定义类型,用来对传递给channel的值进行一些自定义的预处理。这里也需要使用指针吗?
如果这些问题太基础了,我很抱歉,但我真的想对这个主题有一个很好的理解。
英文:
Certain types in Go are reference types: maps, slices, channels, functions, and methods.
Sometimes you need to use pointers to references. For example,
type Stack []interface{}
func (stack *Stack) Push(x interface{}) {
*stack = append(*stack, x)
}
You need it because all arguments are passed by copying the value, and append()
might need to reallocate memory in the slice's capacity is not big enough. I get that.
First question. How about map
types? If I have a custom type based on a map
, should I better always pass a pointer to it if some key:value insertions or deletions are expected?
Second question. What about other reference types? Channel
, for example. I can imagine a situation where I build a custom type based on a channel to implement some custom pre-processing for the values being passed to a channel. Pointers needed here too?
Sorry if this is basic as heck, but I really want to get a good grasp of the subject.
答案1
得分: 16
规则相当简单,当你将所有东西都视为值时,一些值内部包含指针。
- 切片(slices):当你可能需要修改切片的长度或容量时,使用指针,因为这会改变切片的值。
- 映射(maps):不要使用指针,因为映射的值在修改时不会改变。
- 函数和方法:不要使用指针,通过函数值可以达到相同的效果。
- 通道(chan):不要使用指针。
当然也有例外情况,比如如果你想完全替换一个映射,你需要使用指针来实现,但这些情况很少见。
英文:
The rules are fairly easy when you think of everything as a value, where some values contain pointers internally.
- slices: Use a pointer when you may need to modify the length or capacity, which changes the value of the slice.
- maps: Don't use a pointer, since the map value doesn't change with modifications.
- functions and methods: Don't use a pointer, the same effect is had through function values.
- chan: Don't use a pointer.
There are of course exceptions, like if you want to be able to swap out a map entirely you would need to use pointer to do so, but these are rare cases.
答案2
得分: 5
"值类型"和"引用类型"之间并没有真正的二分法。"引用类型"只是用来描述一个值类型,其"值"完全由一个单一指针组成。
这对于映射类型和通道类型是正确的,它们基本上是指向内部结构的指针类型。但对于切片来说,情况并非完全如此,因为切片是一个复合类型(基本上是一个结构体),由两个整数值(长度和容量)和一个指针(指向元素)组成。因此,它在元素方面是一个"引用类型",通过指针访问元素,但在长度和容量方面是一个"值类型"。
向切片追加操作会改变其长度和可能的容量,因此需要改变切片的"值",而在原地分配元素时只使用指针,因此不需要改变切片的"值"。如果您希望将切片的指针更改为指向另一个切片的指针(可以通过分配给切片来实现),则可能需要更改切片的"值"。
对于"引用类型",映射和通道也是类似的。更改映射或通道的"内容"(即指针指向的内容)不需要更改映射或通道的"值"。但是,如果您想要更改指针以指向不同的底层映射或通道,则需要更改映射或通道变量的"值"。
英文:
There isn't really a dichotomy between "value types" and "reference types". "Reference type" is just used to describe a value type whose "value" consists wholly of a single pointer.
This is true for map and channel types, which are basically pointer types to an internal structure. But this is not completely true for slices, because a slice is a composite type (basically a struct), consisting of two integer values (length & capacity) and a pointer (to the elements). So it is a "reference type" with respect to the elements, which are accessed through the pointer, but it is a "value type" with respect to the length and capacity.
Appending to a slice operates on its length and potentially capacity, so it needs to change the "value" of the slice, whereas assigning to elements in place just uses the pointer, and thus does not need to change the "value" of the slice. You might also need to change the "value" of a slice if you want it to change the pointer to point to the same as another slice (which you would do by assigning to the slice).
It's similar for the "reference types", maps and channels. Changing the "contents" of the map or channel (which is in the stuff pointed to by the pointer) doesn't require changing the "value" of the map or channel. But if you wanted to change the pointer to point to a different underlying map or channel, then you would change the "value" of the map or channel variable.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论