复杂数据类型作为Go中的映射键

huangapple go评论78阅读模式
英文:

Complex datatypes as keys in maps in Go

问题

我正在尝试在Go中创建一个以大整数为键的映射。Effective Go明确指出:

结构体、数组和切片不能用作映射键,因为这些类型上没有定义相等性。

这是有道理的。当然,我可以将大整数转换为字符串并将字符串用作键,但我在这里寻找一个更通用的解决方案。我可以将我的结构包装到实现相等性函数的某个东西(接口?)中,然后使用它来代替吗?

当然,下面的示例代码是无法工作的:

package main

import (
    "big"
    "fmt"
)

func main() {
    one1 := big.NewInt(1)
    one2 := big.NewInt(1)

    hmap := make(map[*big.Int] int)
    hmap[one1] = 2
    _, exists := hmap[one2]
    fmt.Printf("Exists=%v\n", exists)
}
英文:

I'm trying to create a map in Go that is keyed by big integers. Effective Go explicitly says that:

> Structs, arrays and slices cannot be used as map keys, because equality is not defined on those types.

which makes sense. I could of course convert the big integers to strings and use the string as a key, but I'm looking for a more general solution here. Can I wrap my structure into something (an interface?) that implements an equality function and use that instead?

Example code that, of course, doesn't work:

package main                                                                                                           
                                                                                                                   
import (                                                                                                               
        "big"                                                                                                          
        "fmt"                                                                                                          
)                                                                                                                      
                                                                                                                   
func main() {                                                                                                          
        one1 := big.NewInt(1)                                                                                          
        one2 := big.NewInt(1)                                                                                          
                                                                                                                   
        hmap := make(map[*big.Int] int)                                                                                
        hmap[one1] = 2                                                                                                 
        _, exists := hmap[one2]                                                                                        
        fmt.Printf("Exists=%v\n", exists)                                                                              
}                                                                                                                      

答案1

得分: 9

关于相等性的规则将很快发生变化。根据Go 1计划

> Go 1将在结构体和数组值上定义相等性,这些值由也定义了相等性的字段组成(逐元素比较)。它将删除函数和映射值上的相等性,除非与nil进行比较。Go 1将继续排除切片的相等性。(在一般情况下是不可行的。)

然而,即使有了这些规则,你也不能将*BigInt用作键,因为它包含一个切片。还要注意的是,在Go中不可能编写自定义的相等运算符(也不可能覆盖任何其他运算符)。但在我看来,这实际上是Go的一个优点-没有它,事情就更简单。

因此,你将不得不使用字符串作为键。然而,这些字符串不需要以十进制(或任何其他格式)格式化,只要你不想打印它们。所以最快的方法可能是使用Bytes()方法(它也会丢弃符号,在字符串中单独包含它)。

英文:

The rules about equality are going to change soon. From the Go 1 plan:

> Go 1 will define equality on struct and array values composed from
> fields on which equality is also defined (element-wise comparison).
> It will remove equality on function and map values except for
> comparison with nil. Go 1 will continue to exclude equality for
> slices. (In the general case it is infeasible.)

However, even with this rules, you can not use *BigInt as key, since it contains a slice. Also note, that it is not possible in Go to write a custom equality operator (neither it is possible to override any other operator). But that's actually a strength of Go in my opinion - things are just simpler without it.

So, you will have to use strings for your keys. The strings however do not need to be formatted in decimal (or any other format) as long as you do not want to print them. So the fastest way is probably to use the Bytes() method (which will also discard the sign, make sure to include that separately in your string).

huangapple
  • 本文由 发表于 2011年11月10日 04:42:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/8071383.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定