Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dictionary 在golang使用私人地图和切片的最佳实践是什么?_Dictionary_Go_Slice - Fatal编程技术网

Dictionary 在golang使用私人地图和切片的最佳实践是什么?

Dictionary 在golang使用私人地图和切片的最佳实践是什么?,dictionary,go,slice,Dictionary,Go,Slice,我希望在地图更新时收到通知,以便我可以重新计算总数。我的第一个想法是保持地图的私有性,并公开一个add方法。这是可行的,但我需要能够允许读取和迭代映射(基本上是只读的或映射的副本)。我发现会发送映射的副本,但底层数组或数据是相同的,并且实际上会被使用“getter”的任何人更新 在Go中有推荐的方法吗?那么您可以使用私有数据和公共迭代器,在每次调用时返回下一个键/值对的副本,不是吗 与没有与特定数据结构相结合的内置结构的语言相比,迭代器在Go中的存在较少。尽管如此,它们和其他任何地方一样容易制作

我希望在地图更新时收到通知,以便我可以重新计算总数。我的第一个想法是保持地图的私有性,并公开一个add方法。这是可行的,但我需要能够允许读取和迭代映射(基本上是只读的或映射的副本)。我发现会发送映射的副本,但底层数组或数据是相同的,并且实际上会被使用“getter”的任何人更新


在Go中有推荐的方法吗?

那么您可以使用私有数据和公共迭代器,在每次调用时返回下一个键/值对的副本,不是吗


与没有与特定数据结构相结合的内置结构的语言相比,迭代器在Go中的存在较少。尽管如此,它们和其他任何地方一样容易制作,也非常容易使用,只是没有语言语法来限定迭代器的范围。例如,
bufio.Scanner
只是一个迭代器,在它上面嫁接了一点方便的cruft…

您可以轻松地使用闭包公开私有数据上的迭代。 如果要禁用修改,只需不传递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
    })

}

最好返回地图的克隆(不是地图值,而是所有内容)。切片也是如此

请注意,映射和切片是描述符。如果返回映射值,它将引用相同的底层数据结构。有关详细信息,请参阅博客文章

创建新地图,复制元素并返回新地图。那么你就不必担心是谁修改了它

要制作地图的克隆,请执行以下操作:

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()
函数(在上尝试):

因此,您的
GetMailbox()
方法:

func (a Account) GetMailbox() map[string]Money{
    return Clone(a.mailbox)
}
“推荐”的方法之一是记录邮箱用户不得修改映射(甚至可能导出映射)

其他语言提倡编码,比如“如果我只是将大部分内容设置为私有和常量,那么代码的用户就不会错过使用我的代码,一切都很好”。我一直认为围棋哲学更像是“如果我的代码的用户不阅读我的文档,或者不愿意遵守它,那么他的代码无论如何都会崩溃,即使我封装了所有东西。”

例如,在Go(如C、Java等)中,没有办法表明某些代码对于并发使用是(或不是)安全的:这些东西只是文档。从技术上讲,除了文档之外,没有任何东西可以阻止用户为并发使用而并发调用不安全的方法或函数


在std库中,您会发现“用户不得复制/修改/任何此字段/在x之后”等类型的几个实例。

我认为这是正确的方法。我将研究如何创建一个迭代器,然后如果我能获得我想要的功能,请将此标记正确。您可能会对这篇博文感兴趣,这篇博文展示了在Go中实现迭代器的各种方法的良好探索:(假设您正在处理一个映射,并且考虑到性能因素,您可能希望坚持“模式1”与回调)谢谢,伟大的文章。这正是我需要知道的。假设映射足够小,并且函数不经常被调用。。。不过,您的方法的优点是原子性。调用方在迭代映射时不必担心映射的更改。
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
func (a Account) GetMailbox() map[string]Money{
    return Clone(a.mailbox)
}