在golang中使用私有地图,切片的最佳做法是什么?

时间:2015-08-05 15:12:56

标签: dictionary go slice

我希望在更新地图时收到通知,以便我可以重新计算总计。我的第一个想法是保持地图私密,并公开一个添加方法。这是有效的,但后来我需要能够读取和迭代地图(基本上,只读或地图的副本)。我发现是发送了地图的副本,但底层数组或数据是相同的,实际上任何使用“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中有推荐的方法吗?

4 个答案:

答案 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图书馆。