返回一个在 Julia 中更改了字段的新结构

Returning a new structure with fields changed in Julia

我在尝试创建一个结构时遇到了这个问题,该结构是更改了特定字段的现有结构的新副本。我知道大概可以通过元编程来实现。但是,这是正确的方法还是我会重新发明轮子?

例如:

struct A
  a
  b
end

var = A(1,2)
var.b  = 4 # This means var = A(1,4)

我不确定是否已经有类似的或更好的实现,但这有效并且不依赖于任何元编程:

struct A
  a
  b
end

var = A(1,2)

function reinstantiate(old, pairs::Pair...)
    T = typeof(old)
    field_values = [getfield(old, field) for field in fieldnames(T)]
    for pair in pairs
        index = findfirst(fieldnames(T) .== pair.first)
        @assert index != nothing "$(pair.first) is not a field of $(T)"
        field_values[index] = pair.second
    end
    return T(field_values...)
end

var2 = reinstantiate(var, :a=>3, :b=>4)

我通常使用 Base.@kwdef 定义 struct,然后定义一个外部构造函数,如

Base.@kwdef struct A
  a
  b
end

Base.convert( ::Type{NamedTuple}, a::A ) = NamedTuple{propertynames(a)}(a)

function A( a::A; kwargs... )
    nt = convert(NamedTuple, a)
    nt = merge( nt, kwargs.data )
    return A(;nt...)
end

然后你可以做

var = A(1, 2)
var2 = A(var, b = 4)

您还可以定义 setindex! 以获取您在 OP 中的语法,但那样一次只能更改一个字段。

更新:检查Accessors.jl,继任者:

Setfield.jl 就是一个可以做到这一点的软件包。