具有可变列表的 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])
我不想做这些:
- 我可以将
NumberedList
声明为 mutable struct
(使 一切 可变)
- 我可以用这样的东西替换
set_values!
(复制所有值):
function set_values!(list::NumberedList, new_values::Vector{Int64})
for i in new_values
push!(list.values, i)
end
end
但我想使index
不可变,但允许将values
分配给。
其他说明:
- 讨论帖:“Mutable field in immutable type”,但这不适用于此设置中的矢量。
这取决于你到底想改变什么。
- 如果您真的想重新分配字段
values::Vector{Int64}
本身,那么您必须使用 mutable struct
。没有办法解决这个问题,因为当您重新分配该字段时,结构的实际数据会发生变化。
- 如果你使用一个带有
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
- 您链接的主题讨论了使用
Base.Ref
。 Base.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])
这是一些损坏的代码:
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])
我不想做这些:
- 我可以将
NumberedList
声明为mutable struct
(使 一切 可变) - 我可以用这样的东西替换
set_values!
(复制所有值):
function set_values!(list::NumberedList, new_values::Vector{Int64})
for i in new_values
push!(list.values, i)
end
end
但我想使index
不可变,但允许将values
分配给。
其他说明:
- 讨论帖:“Mutable field in immutable type”,但这不适用于此设置中的矢量。
这取决于你到底想改变什么。
- 如果您真的想重新分配字段
values::Vector{Int64}
本身,那么您必须使用mutable struct
。没有办法解决这个问题,因为当您重新分配该字段时,结构的实际数据会发生变化。 - 如果你使用一个带有
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
- 您链接的主题讨论了使用
Base.Ref
。Base.Ref
几乎是使不可变结构的字段间接充当可变字段的方法。它是这样工作的:字段不能改变 whichRefValue{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])