在Go语言中返回结构体的引用

10

我对以下代码有一些思考问题

package main

import (
    "fmt"
)

type Company struct {
    Name string
    Workers []worker
}

type worker struct {
    Name string
    Other []int
}

func (cmp *Company) NewWorker(name string) worker {
    wrk := worker{Name: name}
    cmp.Workers = append(cmp.Workers, wrk)
    return wrk
}

func main() {
    cmp := Company{}
    cmp.Name = "Acme"
    wrk := cmp.NewWorker("Bugs")
    for i := 1; i <= 10; i++ {
        wrk.Other = append(wrk.Other, i)
    }
    fmt.Println(wrk)
    fmt.Println(cmp)
}

如您所见,代码返回的不是我创建的worker而是它的副本。我该如何让它返回实际的worker?尝试过在不同的worker上使用*和&的变化,但最终遇到以下问题:

https://play.golang.org/p/Bja7u148mg

invalid indirect of worker literal (type worker)
或者:
cannot use wrk (type worker) as type *worker in return argument

有什么关于如何做到这一点的想法吗?

1个回答

27
func (cmp *Company) NewWorker(name string) *worker {
    wrk := worker{Name: name}
    cmp.Workers = append(cmp.Workers, wrk)
    return &wrk
}

& 总是表示“取地址”(除了二进制按位运算符版本)。然而,* 的含义取决于上下文。表达式 *Type 表示“指向 Type 的指针”。表达式 *Pointer 表示“Pointer 指向的对象”。这就是为什么如果尝试使用表达式 *wrk,会出现“无效的工作字面量间接引用”的原因,因为你在说“给我 wrk 指向的对象”,但 wrk 并不是一个指针。

因此,你需要将返回类型设置为 *worker(返回一个指向 worker 的指针),并返回 &wrk,即你要返回的结构体的地址。

另一种选择是使用内置的 new() 来首先创建指针:

func (cmp *Company) NewWorker(name string) *worker {
    wrk := new(worker)
    wrk.Name = name
    cmp.Workers = append(cmp.Workers, *wrk)
    return wrk // wrk is a pointer here
}

尽管如此,在这里返回指向工人结构体的指针几乎没有理由。这个结构体本身只有两个字段,这两个字段都已经是引用类型了(字符串实际上只是不可变切片),因此整个结构体只有5个机器字长(所以在32位或64位上分别为20或40字节)。你在返回后不会修改该结构体,而你在公司结构体中存储的版本也是副本(公司保存的是工人的切片,而不是指向工人的指针的切片)。


计划是能够在主函数中使用wrk来更新cmp的Workers切片中相同wrk的值。您的第一个示例没有这样做。第二个示例无法在playground中运行tmp/sandbox713099900/main.go:20: cannot use wrk (type *worker) as type worker in append tmp/sandbox713099900/main.go:21: cannot use wrk (type *worker) as type worker in return argument - Johan
是的,在第二个中犯了一个错误,我的错。但是,如果您想在主函数内更新它们,那么Company结构中的切片需要是[]*worker类型的指针切片,并且您需要附加工人的地址(因此对于第一个版本是append(cmp.Workers, &wrk),对于使用new()的第二个版本是append(cmp.Workers, wrk)),这样Company切片通过地址引用与您从函数返回的相同工人。 - Kaedys
以下是与公司拥有指针切片相关的编程内容,展示了它实际上可以进行原地更新:https://play.golang.org/p/XAV1365jer - Kaedys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接