【问题标题】:Go: invalid operation - type *map[key]value does not support indexingGo: 无效操作 - 类型 *map[key]value 不支持索引
【发布时间】: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 := Balance{Currency("USD"): 100.0}
    b = b.Add(Amount{Currency: 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 pass-by-reference


【解决方案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 := &Balance{Currency("USD"): 100.0}
    b = b.Add(Amount{Currency: 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"}
    

    【讨论】:

      猜你喜欢
      • 2018-09-16
      • 2018-05-24
      • 2014-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 2019-08-21
      • 1970-01-01
      相关资源
      最近更新 更多