为了账号安全,请及时绑定邮箱和手机立即绑定

Go:无效操作 - 类型 *map[key]value 不支持索引

Go:无效操作 - 类型 *map[key]value 不支持索引

Go
尚方宝剑之说 2022-01-04 09:51:26
我正在尝试编写一个函数来修改由指针传递的原始地图,但 Go 不允许这样做。假设我有一张大地图,不想来回复制。使用按值传递的代码正在运行并且正在执行我需要的操作,但涉及按值传递(操场):package mainimport "fmt"type Currency stringtype Amount struct {    Currency Currency    Value float32}type Balance map[Currency]float32func (b Balance) Add(amount Amount) Balance {    current, ok := b[amount.Currency]    if ok {        b[amount.Currency] = current + amount.Value    } else {        b[amount.Currency] = amount.Value    }    return b}func main() {    b := Balance{Currency("USD"): 100.0}    b = b.Add(Amount{Currency: Currency("USD"), Value: 5.0})    fmt.Println("Balance: ", b)}但是,如果我尝试像这里(操场)那样将参数作为指针传递:func (b *Balance) Add(amount Amount) *Balance {    current, ok := b[amount.Currency]    if ok {        b[amount.Currency] = current + amount.Value    } else {        b[amount.Currency] = amount.Value    }    return b}我收到编译错误:prog.go:15: invalid operation: b[amount.Currency] (type *Balance does not support indexing)prog.go:17: invalid operation: b[amount.Currency] (type *Balance does not support indexing)prog.go:19: invalid operation: b[amount.Currency] (type *Balance does not support indexing)我该如何处理?
查看完整描述

2 回答

?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

您正在尝试索引指针而不是地图本身。有点令人困惑,因为通常指针与值解引用对于结构来说是自动的。但是,如果您的结构只是一个映射,那么它无论如何只能通过引用传入,因此您不必担心创建对指针起作用的方法以避免每次都复制整个结构。以下代码等效于您的第一个代码段,但使用的是指针类型。


package main


import "fmt"


type Currency string


type Amount struct {

    Currency Currency

    Value float32

}


type Balance map[Currency]float32


func (b *Balance) Add(amount Amount) *Balance {

    current, ok := (*b)[amount.Currency]

    if ok {

        (*b)[amount.Currency] = current + amount.Value

    } else {

        (*b)[amount.Currency] = amount.Value

    }

    return b

}


func main() {

    b := &Balance{Currency("USD"): 100.0}

    b = b.Add(Amount{Currency: Currency("USD"), Value: 5.0})


    fmt.Println("Balance: ", (*b))

}

但是要回答如何处理它:如果您的结构只是映射类型,我不会担心编写您的接收函数来获取指针,并且只接收值,因为无论如何该值只是一个引用。在你的原始片段中做喜欢。


查看完整回答
反对 回复 2022-01-04
?
POPMUISE

TA贡献1765条经验 获得超5个赞

您可以简单地取消引用b:(*b)


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


func (b *Balance) Add(amount Amount) *Balance {

    current, ok := (*b)[amount.Currency]

    if ok {

        (*b)[amount.Currency] = current + amount.Value

    } else {

        (*b)[amount.Currency] = amount.Value

    }

    return b

}

更新

@Serdmanczyk 提出了一个很好的观点......您可以安全地按值传递地图,底层地图将被更新,而不是地图的副本。也就是说; 在映射的情况下按值传递意味着传递映射的地址,而不是映射的内容。


见https://play.golang.org/p/i7Yz4zMq4v


type foo map[string]string


func main() {

    a := foo{}

    a["hello"] = "world"

    fmt.Printf("%#v\n", a)

    mod(a)

    fmt.Printf("%#v\n", a)


}


func mod(f foo) {

    f["hello"] = "cruel world"

}

哪些输出:


main.foo{"hello":"world"}

main.foo{"hello":"cruel world"}



查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 197 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信