我希望在更新地图时收到通知,以便我可以重新计算总计。我的第一个想法是保持地图私密,并公开一个添加方法。这是有效的,但后来我需要能够读取和迭代地图(基本上,只读或地图的副本)。我发现是发送了地图的副本,但底层数组或数据是相同的,实际上任何使用“getter”的人都会更新。
type Account struct{
Name string
total Money
mailbox map[string]Money // I want to make this private but it seems impossible to give read only access - and a public Add method
}
func (a *Account) GetMailbox() map[string]Money{ //people should be able to view this map, but I need to be notified when they edit it.
return a.mailbox
}
func (a *Account) UpdateEnvelope(s string, m Money){
a.mailbox[s] = m
a.updateTotal()
}...
在Go中有推荐的方法吗?
答案 0 :(得分:2)
返回地图的克隆可能更好(不是地图值,而是所有内容)。切片也一样。
请注意,地图和切片是描述符。如果返回映射值,则它将引用相同的基础数据结构。有关详细信息,请参阅博文Go maps in action。
创建新地图,复制元素并返回新地图。然后你不必担心谁修改它。
制作地图的克隆:
func Clone(m map[string]Money) map[string]Money {
m2 := make(map[string]Money, len(m))
for k, v := range m {
m2[k] = v
}
return m2
}
测试Clone()
函数(在Go Playground上尝试):
m := map[string]Money{"one": 1, "two": 2}
m2 := Clone(m)
m2["one"] = 11
m2["three"] = 3
fmt.Println(m) // Prints "map[one:1 two:2]", not effected by changes to m2
所以你的GetMailbox()
方法:
func (a Account) GetMailbox() map[string]Money{
return Clone(a.mailbox)
}
答案 1 :(得分:1)
然后你可以拥有私有数据和一个公共迭代器,它在每次调用时返回下一个键/值对的副本,不是吗?
Go中的迭代器不像没有与特定数据结构结合的内置构造的语言。尽管如此,它们与其他任何地方一样容易制作,并且非常容易使用,除了没有语言语法来处理迭代器的事实。例如,bufio.Scanner
只是一个迭代器,有一些方便的嫁接......
答案 2 :(得分:1)
您可以使用闭包轻松地通过私有数据公开迭代。 如果您想要禁用修改,请不要传递map参数,只需传递键和值,或仅传递键或仅显示值,无论您需要什么。
package main
import "fmt"
type M map[string]int
type S struct {
m M
}
func (s *S) Foreach(fn func(M, string, int)) {
for k, v := range s.m {
fn(s.m, k, v)
}
}
func main() {
s := S{m: make(M)}
s.m["xxx"] = 12
s.m["yyy"] = 254
s.m["zzz"] = 138
s.Foreach(func(m M, k string, v int) {
fmt.Println(k, v)
m[k] = v + 1
})
s.Foreach(func(m M, k string, v int) {
fmt.Println(k, v)
m[k] = v + 1
})
}
答案 3 :(得分:1)
其中一个"推荐"方法是文档,邮箱用户不得修改地图(甚至可能导出地图)。
其他语言促进编码,如#34;如果我只是将大多数事物设为私有和常量,那么我的代码用户将无法使用我的代码而且一切都很好"。我一直都认为Go哲学更像是"如果我的代码的用户没有阅读我的文档,或者心甘情愿地不遵守它,他的代码就会破坏,即使我封装了所有内容。&#34 ;
E.g。在Go中(如在C,Java等中),没有办法表明某些代码对于并发使用是安全的(或者不是):这些东西只是文档。从技术上讲,没有任何东西可以阻止用户同时调用不安全的并发使用方法或函数,除了文档。
你会发现这种类型的几个实例"用户不得复制/修改/在x / etc之后的任何字段。"在std图书馆。