Golang中的不可变结构

时间:2017-12-04 11:48:54

标签: go immutability

是否可以在Golang中定义不可变结构?初始化后,只对struct的字段进行读取操作,不修改字段值。如果是这样,那该怎么做。

3 个答案:

答案 0 :(得分:24)

通过使其成员不导出并为读者提供,可以使结构在包外只读。例如:

package mypackage

type myReadOnly struct {
  value int
}

func (s myReadOnly) Value() int {
  return s.value
}

func NewMyReadonly(value int) myReadOnly{
  return myReadOnly{value: value}
}

用法:

myReadonly := mypackage.NewMyReaonly(3)
fmt.Println(myReadonly.Value())  // Prints 3

答案 1 :(得分:1)

无法以通用方式将字段/变量标记为只读。你唯一能做的就是将字段/变量标记为未导出(首字母小)并提供公共getter以防止其他包编辑变量。

答案 2 :(得分:1)

无法在Go中定义不可变的结构:struct字段是可变的,而const关键字不适用于它们。但是,通过Go可以很容易地通过简单的赋值复制整个结构,因此我们可能认为以值传递参数是具有不变性所需要的,而这是以复制为代价的。

但是,毫不奇怪,它不会复制指针引用的值。由于内置集合(映射,切片和数组)是引用并且是可变的,因此复制包含其中一个的结构只会将指针复制到相同的基础内存中。

示例:

type S struct {
    A string
    B []string
}

func main() {
    x := S{"x-A", []string{"x-B"}}
    y := x // copy the struct
    y.A = "y-A"
    y.B[0] = "y-B"

    fmt.Println(x, y)
    // Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified!
}

注意:因此,您必须对此格外小心,并且如果按值传递参数,则不要假定不变性。

有一些Deepcopy库试图使用(慢速)反射来解决此问题,但是由于不能通过反射访问私有字段,因此它们不足。因此,为了避免出现竞争状况而进行防御性复制将很困难,需要大量样板代码。 Go甚至没有将其标准化的Clone接口。

信用:https://bluxte.net/