我的要求是有一个函数可以有效地返回数组。
据我所知,数组是值类型,因此当将输入/输出数组传递给函数时,它会这样做copy。因此,我正在考虑数组的返回指针。人们会推荐使用切片,但是通过使用切片,我仍然需要copy转移到数组。
这是游乐场包含两种解决方案,请建议返回数组指针是否是正确的方法,谢谢。
package main
import (
"fmt"
)
type geo [2]float32
func genArray () geo {
ret := geo{1.2, 2.3}
return ret
}
func genPointerOfArray () *geo {
ret := geo{1.2, 2.3}
return &ret
}
func main() {
ret1 := genArray()
ret2 := *genPointerOfArray()
fmt.Println(ret1, ret2)
}
Run Code Online (Sandbox Code Playgroud)
大多数开始学习 Go 的人都了解切片的概念。它是数组的轻量级包装器,可以但不一定必须表示底层数组的子集(或切片)。尽管有这样的理解,开发人员在将这些知识付诸实践时仍然会遇到困难。为什么?
当您想将数组传递给函数时,就会出现问题。Go 的文档明确指出数组是通过复制传递的。如果您希望数组不可变,也许有用。但在大多数情况下,这只是效率低下。最初,您可能会想做类似的事情:
names := []string{"leto", "paul", "teg"}
process(&names)
func process(names *[]string) {
...
}
Run Code Online (Sandbox Code Playgroud)
这可能会激发你的蜘蛛侠意识。因此,您前往 golang-nuts 用户组,阅读相关帖子,或者提出问题,您不可避免地得到的答案是:不要传递数组,而是传递切片。
这有点符合你所知道的,因为切片是数组的薄包装。但尽管如此,这只是感觉好一点:
names := []string{"leto", "paul", "teg"}
process(names[0:])
func process(names []string) {
...
}
Run Code Online (Sandbox Code Playgroud)
您心想,这些只处理数组切片的人是谁?95% 的情况下,我需要数组中的所有数据,而不仅仅是其中的一部分!
在这里,我们了解了人们在考虑数组和切片时存在的两个基本误解。
首先,将切片表示部分底层数组的能力视为次要好处。首先也是最重要的,切片是对数组的引用。代表整个数组的切片非常常见。第二点使这一点更加绝对。
其次,几乎可以肯定您已经在处理切片了。上面的名称已经是一个切片(覆盖整个底层数组)。唯一一次处理数组是在创建具有大小的数组时:
names := [3]string{"leto", "paul", "teg"}
//or
names := [3]string{}
Run Code Online (Sandbox Code Playgroud)
其他一切都是一个切片:
names := []string{"leto", "paul", "teg"}
//or
names := make([]string, 3)
//or
var names []string
Run Code Online (Sandbox Code Playgroud)
所以,上面代码的解决方案最终是最直观的:
names := []string{"leto", "paul", "teg"}
process(names)
func process(names []string) {
...
}
Run Code Online (Sandbox Code Playgroud)
让我们更进一步,利用这些知识来澄清另一个常见问题。你应该创建一个指针数组吗?例如,哪个更好?
sayans := []*Sayan{
&Sayan{Name: "Goku", Power: 9001,}
}
//or
sayans := []Sayan{
Sayan{Name: "Goku", Power: 9001,}
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,sayans 都是一个切片。因此,当将 this 传递给函数(或返回它)时,它们是相同的。第一个示例提供的额外间接是否有用取决于具体情况,但如果您不确定,它可能没有用,您应该使用第二个版本。
两个要点是:
切片是对数组的引用,数组恰好能够表示子集,并且几乎所有内容都已经是切片