Golang新手入门:数组、可变参数函数和指针的使用指南
Golang新手入门:数组、可变参数函数和指针的使用指南 大家好,
我是Go语言的新手,目前刚了解到硬拷贝值在某些情况下是不好的。这里有一个小例子,我想知道:
- 为什么我必须在代码中标出的位置使用 *(解引用)?
- 我在这里尝试实现的方式是否高效,或者是否有更好的方法(消耗更少的内存)来达到相同的结果?
type SomeObject struct {
a string
b string
c string
}
type SomeInterface interface {
setup(name string, unknownAmountOfObjects ...*SomeObject)
}
type InterfaceTest struct {
ExaxtAmountOfObjects *[3]SomeObject
name string
}
// 通过实现此方法来实现接口
func (interfacetest *InterfaceTest) setup(name string, somename ...*SomeObject) {
interfacetest.name = name
for i, value := range rotors {
// 首先检查大小
if i < len(interfacetest.ExaxtAmountOfObjects) {
// !!!! 为什么我需要在这里解引用??!
interfacetest.ExaxtAmountOfObjects[i] = *value
}
}
}
提前感谢您的帮助和建议。
更多关于Golang新手入门:数组、可变参数函数和指针的使用指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1.) @kync 谢谢,我有点把可变参数类型和某种数组搞混了。但你是对的,它不是 ;) 谢谢
2.) @lutzhorn “rotors” 是个笔误…… 那里当然应该是指 SomeObject
我的错误还在于这两者之间存在区别:
*[3]Object
and
[3]*Object
更多关于Golang新手入门:数组、可变参数函数和指针的使用指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这行代码
for i, value := range rotors {
遍历了 rotors,但在这个代码片段的其他地方都没有提到它。所以我们不知道 value 是什么。它与 SomeInterface.setup(...) 签名中的 somename 无关。rotors 是什么?
- 为什么我必须在代码中标记的位置使用 *(解引用)?
ExaxtAmountOfObjects *[3]SomeObject 持有一个 SomeObject 的值,但你传递给函数的是指向对象的指针(*SomeObject),这就是你需要解引用的原因。
我在这里尝试实现的方式是否高效?或者是否有更好的选择来实现相同的结果(同时消耗更少的内存)?
ExaxtAmountOfObjects 是一个数组,这意味着它是固定大小的。setup 是一个可变参数函数,你可以传递任意数量的参数。如果我在没有看到其实现的情况下看到你的函数,我会期望向函数传递 4 个项目,并期望数组中的所有元素都被处理。
这是一个很好的问题,涉及到Go语言中指针、数组和切片的核心概念。让我们直接解答你的疑问。
1. 为什么需要解引用(*)?
在你的代码中,ExaxtAmountOfObjects 是一个指向数组的指针:*[3]SomeObject。这意味着 interfacetest.ExaxtAmountOfObjects[i] 已经是在访问数组的元素了。
然而,somename 参数是 ...*SomeObject,这是一个指向 SomeObject 的指针的切片。所以 value 的类型是 *SomeObject(指针),而 interfacetest.ExaxtAmountOfObjects[i] 的类型是 SomeObject(值类型)。
你需要解引用 *value 来获取指针指向的实际 SomeObject 值,然后将其赋值给数组元素。
示例说明:
// 假设 value 是一个指针:*SomeObject
var value *SomeObject = &SomeObject{a: "test"}
// 这行代码会报类型错误:
// interfacetest.ExaxtAmountOfObjects[i] = value
// 错误:不能将 *SomeObject 赋值给 SomeObject
// 正确的做法是解引用:
interfacetest.ExaxtAmountOfObjects[i] = *value
// 现在是把 SomeObject 值赋值给 SomeObject
2. 更高效的内存使用方式
你当前的实现确实有内存拷贝,因为解引用 *value 会创建值的副本。如果你想要避免拷贝并直接使用原始对象,可以修改设计:
方案A:存储指针而不是值
type InterfaceTest struct {
// 改为存储指针数组
ExaxtAmountOfObjects *[3]*SomeObject // 注意这里的改变
name string
}
func (interfacetest *InterfaceTest) setup(name string, somename ...*SomeObject) {
interfacetest.name = name
for i, value := range somename {
if i < len(interfacetest.ExaxtAmountOfObjects) {
// 现在直接存储指针,无需解引用
interfacetest.ExaxtAmountOfObjects[i] = value
}
}
}
// 使用示例:
obj1 := &SomeObject{a: "a1", b: "b1", c: "c1"}
obj2 := &SomeObject{a: "a2", b: "b2", c: "c2"}
obj3 := &SomeObject{a: "a3", b: "b3", c: "c3"}
test := &InterfaceTest{
ExaxtAmountOfObjects: &[3]*SomeObject{},
}
test.setup("test", obj1, obj2, obj3)
方案B:使用切片而不是数组
type InterfaceTest struct {
// 使用切片,更灵活
Objects []*SomeObject // 切片而不是固定数组
name string
}
func (interfacetest *InterfaceTest) setup(name string, somename ...*SomeObject) {
interfacetest.name = name
interfacetest.Objects = somename // 直接赋值,无拷贝
}
// 或者如果你需要限制数量:
func (interfacetest *InterfaceTest) setupLimited(name string, somename ...*SomeObject) {
interfacetest.name = name
max := 3
if len(somename) < max {
max = len(somename)
}
interfacetest.Objects = make([]*SomeObject, max)
for i := 0; i < max; i++ {
interfacetest.Objects[i] = somename[i] // 仅复制指针
}
}
方案C:如果你想完全避免指针
type InterfaceTest struct {
ExaxtAmountOfObjects [3]SomeObject
name string
}
func (interfacetest *InterfaceTest) setup(name string, somename ...SomeObject) { // 注意:不是指针
interfacetest.name = name
for i, value := range somename {
if i < len(interfacetest.ExaxtAmountOfObjects) {
interfacetest.ExaxtAmountOfObjects[i] = value // 值拷贝
}
}
}
// 使用示例:
test := &InterfaceTest{}
test.setup("test",
SomeObject{a: "a1", b: "b1", c: "c1"},
SomeObject{a: "a2", b: "b2", c: "c2"},
)
性能考虑:
- 存储指针:内存占用小(仅指针大小),修改原始对象会影响存储的对象
- 存储值:有拷贝开销,但数据独立,修改安全
- 切片 vs 数组:切片更灵活,数组大小固定但可能有轻微性能优势
选择哪种方案取决于你的具体需求:是否需要修改原始对象、数据大小、性能要求等。

