返回指针和返回值在初始化方法中的区别是什么?

huangapple go评论82阅读模式
英文:

Difference between returning a pointer and a value in initialization methods

问题

考虑以下结构体:

type Queue struct {
  Elements []int
}

以下是两种不同的写法之间的区别:

func NewQueue() Queue {
  queue := Queue{}
  return queue
}

func NewQueue() *Queue {
  queue := &Queue{}
  return queue
}

对我来说,它们似乎是几乎相同的(实际上,通过一些入队和出队的尝试,它们产生了相同的结果),但我仍然在实际应用中看到两种用法,所以可能有一种更可取的方式。

英文:

Consider the following struct:

type Queue struct {
  Elements []int
}

What would be the different between:

func NewQueue() Queue {
  queue := Queue{}
  return queue
}

and

func NewQueue() *Queue {
  queue := &Queue{}
  return queue
}

To me the seem practically the same, (and in fact trying it with some enqueuing and dequeueing yields the same results) but I still see both usages in the wild, so perhaps one is preferable.

答案1

得分: 2

可以返回一个值,然后调用者可以调用具有指针接收器的方法。然而,如果调用者总是希望使用指针,因为对象很大或者方法需要就地修改它,那么最好返回一个指针。关于在Go中使用指针还是值的问题,有一个回答试图解释何时使用其中之一。

对于基于切片的Queue类型,将其作为值进行复制非常小且快速,但是如果您希望能够复制它并且每个副本访问相同的数据,那么您将需要使用指针,因为切片实际上是一个由起始指针、长度和容量组成的小结构体,当您重新切片或扩展它时,这些值会发生变化。如果这让您感到惊讶,Go博客上关于append机制的文章和关于切片用法和内部机制的文章可能会有所帮助。

如果您的队列不是用于共享或传递,而是在单个函数中本地使用,您可以提供一个类似于append的接口,其中操作返回一个修改后的队列,但此时也许您只想直接使用切片技巧。

(如果您的队列用于并发使用,请仔细考虑使用带缓冲的通道。它可能不完全符合您的想象,但实现者已经为您解决了许多棘手的问题。)

另外,如果Queue实际上是一个添加了方法的切片,您可以将其定义为type Queue []int

英文:

It's possible to return a value and then the caller to call methods that have a pointer receiver. However, if the caller is always going to want to use pointers, because the object's big or because methods need to modify it in place, you might as well return a pointer. Pointers vs. values is a common question in Go and there's an answer trying to break down when to use one or the other.

In the specific case of a slice-backed Queue type, it's pretty small and fast to copy as a value, but if you want to be able to copy it around and have everyone see the same data whichever copy is accessed, you're going to need to use a pointer, because a slice is really a little struct of start pointer, length, and capacity, and those change when you reslice or grow it. If this is a surprise, the Go blog posts on the mechanics of append and slice usage and internals could be useful reading.

If your queue isn't for sharing or passing around but for using locally in a single function, you could provide an append-style interface where operations return a modified queue, but at that point maybe you just want to use slice tricks directly.

(If your queue is meant to be used concurrently, think hard about using a buffered channel. It might not be exactly what you're imagining, but a lot of the tricky bits have already been figured out for you by the implementers.)

Also--if Queue is really a slice with methods added, you can make it type Queue []int.

huangapple
  • 本文由 发表于 2016年11月14日 02:09:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/40577116.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定