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

Posted

技术标签:

【中文标题】Go: 无效操作 - 类型 *map[key]value 不支持索引【英文标题】:Go: invalid operation - type *map[key]value does not support indexing 【发布时间】:2016-07-27 14:13:29 【问题描述】:

我正在尝试编写一个函数来修改通过指针传递的原始地图,但 Go 不允许这样做。假设我有一张大地图,不想来回复制。

使用按值传递的代码正在工作并且正在做我需要但涉及按值传递的代码 (playground):

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 := BalanceCurrency("USD"): 100.0
    b = b.Add(AmountCurrency: Currency("USD"), Value: 5.0)

    fmt.Println("Balance: ", b)

但是如果我尝试像这里一样将参数作为指针传递(playground):

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)

我该如何处理?

【问题讨论】:

Go update slice iterating error "does not support indexing"的可能重复 【参考方案1】:

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

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 := &BalanceCurrency("USD"): 100.0
    b = b.Add(AmountCurrency: Currency("USD"), Value: 5.0)

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

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

【讨论】:

【参考方案2】:

你可以简单地取消引用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 提出了一个很好的观点......您可以安全地按值传递地图,底层地图将被更新,而不是地图的副本。也就是说;在 map 的情况下 pass-by-value 意味着传递 map 的地址,而不是 map 的内容。

见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"

【讨论】:

以上是关于Go: 无效操作 - 类型 *map[key]value 不支持索引的主要内容,如果未能解决你的问题,请参考以下文章

go map 基本操作

GO语言复合类型04---映射

Go语言map实践

Go语言基础之map

Go的map字典及约束

Go的map字典及约束