如何在 Go 中编写双向映射?
How to write a bidirectional mapping in Go?
我正在编写一个简单的控制台游戏,并希望将玩家映射到一个符号。对于两个玩家,我的方法是这样的:
func playerToString(p player) string {
if p == 0 {
return "X"
}
return "O"
}
func stringToPlayer(s string) player {
if s == "X" {
return 0
}
return 1
}
当然你也可以把它写成两个映射,将 int 映射到 string,将 string 映射到 int。上述方法和地图方法似乎都容易出错。有没有更惯用的方式来写这个?也许一些非 iota 枚举方式?
[我假设你的例子只是最小的,你的实际映射有两个以上的选项。我还假设你的意思是双向映射]
我会写一张地图:
var player2string = map[int]string{
0: "0",
1: "X",
// etc...
}
然后将创建一个函数以编程方式填充不同的地图 string2player
。像这样:
var player2string = map[int]string{
0: "0",
1: "X",
// etc...
}
var string2player map[string]int = convertMap(player2string)
func convertMap(m map[int]string) map[string]int {
inv := make(map[string]int)
for k, v := range m {
inv[v] = k
}
return inv
}
func main() {
fmt.Println(player2string)
fmt.Println(string2player)
}
除了 Eli 的回答之外,您还可以进行另外两项更改。您可以使 to-symbol 函数成为 player
类型的方法。并且因为玩家值是整数(从零开始顺序),您可以使用切片而不是映射来存储 int-to-symbol 映射——存储和查找效率更高。
type player int
var playerSymbols = []string{"X", "O", "A", "B", "C", "D", "E", "F", "G", "H"}
func (p player) Symbol() string {
if int(p) < 0 || int(p) >= len(playerSymbols) {
return "?" // or panic?
}
return playerSymbols[p]
}
这个方法签名甚至可以是 String() string
所以它是一个 fmt.Stringer
,这对于打印和调试很有用。
假设您不需要任何特定的映射并且玩家整数值的序列为 0,1,2,3,...,25,您可以直接生成玩家符号而不使用地图,如下所示以下片段:-
type player int
func ToSymbol(p player) string {
return fmt.Sprintf("%c", 'A' + p)
}
func ToPlayer(symbol string) player {
return player([]rune(symbol)[0] - 'A')
}
我正在编写一个简单的控制台游戏,并希望将玩家映射到一个符号。对于两个玩家,我的方法是这样的:
func playerToString(p player) string {
if p == 0 {
return "X"
}
return "O"
}
func stringToPlayer(s string) player {
if s == "X" {
return 0
}
return 1
}
当然你也可以把它写成两个映射,将 int 映射到 string,将 string 映射到 int。上述方法和地图方法似乎都容易出错。有没有更惯用的方式来写这个?也许一些非 iota 枚举方式?
[我假设你的例子只是最小的,你的实际映射有两个以上的选项。我还假设你的意思是双向映射]
我会写一张地图:
var player2string = map[int]string{
0: "0",
1: "X",
// etc...
}
然后将创建一个函数以编程方式填充不同的地图 string2player
。像这样:
var player2string = map[int]string{
0: "0",
1: "X",
// etc...
}
var string2player map[string]int = convertMap(player2string)
func convertMap(m map[int]string) map[string]int {
inv := make(map[string]int)
for k, v := range m {
inv[v] = k
}
return inv
}
func main() {
fmt.Println(player2string)
fmt.Println(string2player)
}
除了 Eli 的回答之外,您还可以进行另外两项更改。您可以使 to-symbol 函数成为 player
类型的方法。并且因为玩家值是整数(从零开始顺序),您可以使用切片而不是映射来存储 int-to-symbol 映射——存储和查找效率更高。
type player int
var playerSymbols = []string{"X", "O", "A", "B", "C", "D", "E", "F", "G", "H"}
func (p player) Symbol() string {
if int(p) < 0 || int(p) >= len(playerSymbols) {
return "?" // or panic?
}
return playerSymbols[p]
}
这个方法签名甚至可以是 String() string
所以它是一个 fmt.Stringer
,这对于打印和调试很有用。
假设您不需要任何特定的映射并且玩家整数值的序列为 0,1,2,3,...,25,您可以直接生成玩家符号而不使用地图,如下所示以下片段:-
type player int
func ToSymbol(p player) string {
return fmt.Sprintf("%c", 'A' + p)
}
func ToPlayer(symbol string) player {
return player([]rune(symbol)[0] - 'A')
}