Golang中的不可变结构

Vik*_*ary 23 immutability go

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

Ale*_*nok 32

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

package mypackage

type myReadOnly struct {
  value int
}

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

func NewMyReadonly(value int) myReadOnly{
  return myReadOnly{value: value}
}
Run Code Online (Sandbox Code Playgroud)

用法:

myReadonly := mypackage.NewMyReaonly(3)
fmt.Println(myReadonly.Value())  // Prints 3
Run Code Online (Sandbox Code Playgroud)

  • @VIKRAMSINGHCHOUDHARY尽管这可能是矫枉过正,你也可以只动型到它自己的包那里是什么,但它,它导出的方法和构造函数. (6认同)
  • 不,但是由于您控制了包内的代码,所以您只需在创建结构后就不会写入结构. (4认同)

Arm*_*ani 8

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


Alo*_*thi 7

Go 中无法定义不可变结构:结构字段是可变的,并且 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!
}
Run Code Online (Sandbox Code Playgroud)

注意:因此,您必须对此非常小心,如果您按值传递参数,则不要假设不变性。

有一些深度复制库尝试使用(慢速)反射来解决此问题,但由于无法通过反射访问私有字段,因此它们的效果不佳。因此,避免竞争条件的防御性复制将很困难,需要大量样板代码。Go 甚至没有一个可以标准化这一点的 Clone 接口。

信用: https: //bluxte.net/

  • 这对 2020 年的我来说感觉很疯狂。缺乏不变性是 golang 中的热门话题还是这只是系统人员不关心的事情? (7认同)
  • 我不同意“系统人员”部分。例如,在 Rust 中,不可变是默认值。是的,Golang 不支持这一点真是太疯狂了。 (2认同)
  • @AnthonyNaddeo Go 最初的设计目标是:保持语言轻量和简单,以便易于快速阅读和编译,并通过轻量级例程和通信通道而不是共享内存实现并发。不变性使得共享内存变得廉价且安全,但它增加了编译器的复杂性。由于您不应该共享内存并且编译器应该很快,因此包括显式不变性(或默认不变性和选择可变性,如 Rust 那样)最初并不是优先考虑的事情。 (2认同)