具有可变列表的 Julia 不可变结构

Julia immutable struct with mutable list

这是一些损坏的代码:

struct NumberedList
  index::Int64
  values::Vector{Int64}

  NumberedList(i) = new(i, Int64[])
end

function set_values!(list::NumberedList, new_values::Vector{Int64})
  list.values = new_values
end

# ---
mylist = NumberedList(1)
set_values!(mylist, [1, 2, 3])

我不想做这些:

  1. 我可以将 NumberedList 声明为 mutable struct(使 一切 可变)
  2. 我可以用这样的东西替换 set_values!(复制所有值):
function set_values!(list::NumberedList, new_values::Vector{Int64})
  for i in new_values
      push!(list.values, i)
  end
end

但我想使index不可变,但允许将values分配给。


其他说明:

这取决于你到底想改变什么。

  1. 如果您真的想重新分配字段 values::Vector{Int64} 本身,那么您必须使用 mutable struct。没有办法解决这个问题,因为当您重新分配该字段时,结构的实际数据会发生变化。
  2. 如果你使用一个带有values::Vector{Int64}字段的不可变结构,这意味着你不能改变包含哪个数组,但数组本身是可变的并且可以改变它的元素(不存储在结构中)。在这种情况下,您确实必须将值从外部数组复制到它,就像您的示例代码一样(尽管我会指出您的代码没有将数组重置为空数组)。我个人认为这样会更干净:
function set_values!(list::NumberedList, new_values::Vector{Int64})
  empty!(list.values) # reset list.values to Int64[]
  append!(list.values, new_values)
end
  1. 您链接的主题讨论了使用 Base.RefBase.Ref 几乎是使不可变结构的字段间接充当可变字段的方法。它是这样工作的:字段不能改变 which RefValue{Vector{Int64}} instance is contained,但实例本身是可变的并且可以将其引用(同样,不存储在结构中)更改为任何 Int64 数组。但是,您必须使用索引 values[] 来访问数组:
struct NumberedList
  index::Int64
  values::Ref{Vector{Int64}}

  NumberedList(i) = new(i, Int64[])
end

function set_values!(list::NumberedList, new_values::Vector{Int64})
  list.values[] = new_values # "reassign" different array to Ref
end

# ---
mylist = NumberedList(1)
set_values!(mylist, [1, 2, 3])