3 回答

TA貢獻1829條經驗 獲得超13個贊
該地圖類型:
映射是一種類型的無序元素組,稱為元素類型,由一組另一種類型的唯一鍵索引,稱為鍵類型。
映射類型必須具有特定的值類型和特定的鍵類型。你想要的不符合這個條件:你想要一個值有時是另一個映射(相同類型)的映射,有時它是一個bool.
您的選擇:
1. 帶包裝值類型
這里的想法是不僅僅使用簡單的 ( bool) 值類型,而是使用一個包裝器來保存您的兩個潛在值:amap和簡單值 ( bool):
type Value struct {
Children MapType
V bool
}
type MapType map[int]*Value
var m MapType
這基本上是 user3591723 建議的,所以我不會進一步詳細說明。
2. 帶著一棵樹
這是#1 的變體,但通過這種方式我們可以清楚地傳達它是一棵樹。
實現層次結構的最簡潔的方法是使用樹,其中的節點可能如下所示:
type KeyType int
type ValueType string
type Node struct {
Children map[KeyType]*Node
Value ValueType
}
這樣做的好處是您可以選擇值類型(這是bool您的情況,但您可以將其更改為任何類型 - 我用于string演示)。
為了輕松構建/管理您的樹,我們可以在我們的Node類型中添加一些方法:
func (n *Node) Add(key KeyType, v ValueType) {
if n.Children == nil {
n.Children = map[KeyType]*Node{}
}
n.Children[key] = &Node{Value: v}
}
func (n *Node) Get(keys ...KeyType) *Node {
for _, key := range keys {
n = n.Children[key]
}
return n
}
func (n *Node) Set(v ValueType, keys ...KeyType) {
n = n.Get(keys...)
n.Value = v
}
并使用它:1. 構建一棵樹,2. 查詢一些值,3. 更改一個值:
root := &Node{Value: "root"}
root.Add(0, "first")
root.Get(0).Add(9, "second")
root.Get(0, 9).Add(3, "third")
root.Get(0).Add(4, "fourth")
fmt.Println(root)
fmt.Println(root.Get(0, 9, 3))
fmt.Println(root.Get(0, 4))
root.Set("fourthMod", 0, 4)
fmt.Println(root.Get(0, 4))
輸出(在Go Playground上試試):
&{map[0:0x104382f0] root}
&{map[] third}
&{map[] fourth}
&{map[] fourthMod}
3. 帶有遞歸類型定義
這可能令人驚訝,但可以map使用遞歸定義在 Go 中定義具有無限或動態“深度”的類型:
type X map[int]X
這就是它所說的:它是一個map帶有int鍵和與地圖本身相同類型的值。
這種遞歸類型的最大缺點是它不能在值類型中存儲任何“有用”的數據。它只能存儲是否存在與類似bool信息(booltype:true或false)相同的值的“事實” ,這在極少數情況下可能就足夠了,但在大多數情況下就不夠了。
讓我們看一個構建“樹”的例子:
var x X
x = map[int]X{}
x[0] = map[int]X{}
x[0][9] = map[int]X{}
x[0][9][3] = map[int]X{}
x[0][4] = map[int]X{}
fmt.Println(x)
輸出:
map[0:map[9:map[3:map[]] 4:map[]]]
如果我們想測試是否存在基于一系列鍵的“值”,我們有 2 個選項:使用特殊v, ok := m[i]索引(它報告指定鍵的值是否存在),或者測試該值是否不存在nil,例如m[i] != nil。
讓我們看一些測試上面構建的地圖的例子:
var ok bool
_, ok = x[0][9][3]
fmt.Println("x[0][9][3] exists:", ok, "; alternative way:", x[0][9][3] != nil)
_, ok = x[0][9][4]
fmt.Println("x[0][9][4] exists:", ok, "; alternative way:", x[0][9][4] != nil)
_, ok = x[0][4]
fmt.Println("x[0][4] exists:", ok, "; alternative way:", x[0][4] != nil)
_, ok = x[0][4][9][9][9]
fmt.Println("x[0][4][9][9][9] exists:", ok, "; alternative way:", x[0][4][9][9][9] != nil)
輸出:
x[0][9][3] exists: true ; alternative way: true
x[0][9][4] exists: false ; alternative way: false
x[0][4] exists: true ; alternative way: true
x[0][4][9][9][9] exists: false ; alternative way: false
在Go Playground上試試這些。
注意:即使x[0][4]是最后一個“葉子”,進一步索引x[0][4][9][9][9]也不會引起恐慌,因為nil可以索引映射并產生值類型的零值(nil如果值類型是映射類型)。

TA貢獻1818條經驗 獲得超3個贊
好吧,我玩這個有點樂趣。這是一個比我之前做的更好的實現:
type mymap map[int]*myentry
type myentry struct {
m mymap
b bool
}
func (mm mymap) get(idx ...int) *myentry {
if len(idx) == 0 {
return nil
}
entry, ok := mm[idx[0]]
if !ok {
return nil
} else if len(idx) == 1 {
return entry
}
for i := 1; i < len(idx); i++ {
if entry == nil || entry.m == nil {
return nil
}
entry = entry.m[idx[i]]
}
return entry
}
func (mm mymap) setbool(v bool, idx ...int) {
if len(idx) == 0 {
return
}
if mm[idx[0]] == nil {
mm[idx[0]] = &myentry{m: make(mymap), b: false}
} else if mm[idx[0]].m == nil {
mm[idx[0]].m = make(mymap)
}
if len(idx) == 1 {
mm[idx[0]].b = v
return
}
entry := mm[idx[0]]
for i := 1; i < len(idx); i++ {
if entry.m == nil {
entry.m = make(mymap)
entry.m[idx[i]] = &myentry{m: make(mymap), b: false}
} else if entry.m[idx[i]] == nil {
entry.m[idx[i]] = &myentry{m: make(mymap), b: false}
}
entry = entry.m[idx[i]]
}
entry.b = v
}
func (m mymap) getbool(idx ...int) bool {
if val := m.get(idx...); val != nil {
return val.b
}
return false
}
func (m mymap) getmap(idx ...int) mymap {
if val := m.get(idx...); val != nil {
return val.m
}
return nil
}
這樣的事情應該讓你開始

TA貢獻1911條經驗 獲得超7個贊
如果您不需要分層映射結構并且只想使用可變長度的鍵,那么一種方法可能是簡單地使用字符串作為鍵和一個單獨的映射。
m := make(map[string]bool)
k := fmt.Sprintf("%v_%v_%v", 1, 2, 3)
m[k] = true
fmt.Println(m[k])
- 3 回答
- 0 關注
- 207 瀏覽
添加回答
舉報