我应该在Go中封装切片和地图吗?如果是这样,该怎么做?

时间:2019-05-28 12:33:16

标签: go

我想创建一个可以在其他软件包中访问的结构,但是我不想允许修改此结构。在其他语言中,通过将所有字段设置为私有并仅公开公共获取程序来对它进行存档。

使用getter的解决方案对除切片和映射之外的所有数据类型均适用,因为默认情况下不会复制返回的切片和映射,因此可以对其进行修改。我设法找出的唯一解决方案是创建新的地图/切片并在循环中分配所有项目,但这会引入很多重复且难看的代码,尤其是对于大型嵌套结构。

package main

import (
    "fmt"
)

type OtherStruct struct {
    prop string
}

type Struct struct {
    prop map[string]OtherStruct
}

func (s Struct) Prop() map[string]OtherStruct {
    return s.prop
}

func (s Struct) Prop2() map[string]*OtherStruct {
    prop := make(map[string]*OtherStruct, 0)
    for k := range s.prop {
        v := s.prop[k]
        prop[k] = &v
    }

    return prop
}

func main() {
    var s Struct;

    // Simple getter
    s = Struct{make(map[string]OtherStruct, 0)}
    p1 := s.Prop()
    fmt.Println(s) // &{map[]}
    p1["something"] = OtherStruct{"test"}
    fmt.Println(s) // {map[something:{test}]}

    // Getter which copies map
    s = Struct{make(map[string]OtherStruct, 0)}
    p2 := s.Prop2()
    fmt.Println(s) // &{map[]}
    p2["something"] = &OtherStruct{"test"}
    fmt.Println(s) // &{map[]}
}

在Go中,有没有更好的方法来封装切片/地图?或者也许我不应该在Go中完全使用封装并使用其他方法?

1 个答案:

答案 0 :(得分:1)

返回切片或地图值是惯用的Go。您的包用户将知道这些数据结构如何在Go中工作。

在您的示例中,Struct的用户应该知道在返回的地图中添加新条目将反映同一地图的任何其他用户。

// Simple getter
s = Struct{make(map[string]OtherStruct, 0)}
p1 := s.Prop()
fmt.Println(s) // &{map[]}
p1["something"] = OtherStruct{"test"}
fmt.Println(s) // {map[something:{test}]}

仅在并发的情况下才应担心此类情况。也就是说,当多个goroutine正在访问并可能更改切片或地图中的元素时。