初始化一个结构字段,它是 Julia 中的一个向量

Initializing a struct field that is a vector in Julia

我有以下可变结构:

mutable struct foo
    x::Vector{String}
    # other field(s)...

    # constructor(s)
end

我想从这个结构创建一个对象并像下面这样编辑它:

bar = foo()  # or some other constructor
push!(bar.x, "a")
# Do some stuff...
push!(bar.x, "b")
# Do some more stuff...
push!(bar.x, "c")

为此,foo 的最佳构造函数是什么?


P.S。我尝试了以下构造函数:

foo() = new()

如果我使用它并执行 push!(bar.x, "a"),我会得到一个 UndefRefError。我可以在外部初始化 bar.x(如 bar.x = []),但我真的想避免这种情况。

我也试过:

foo() = new([])

有了这个,我就可以毫无问题地进行推送操作了。但是,如果我在结构中还有许多其他字段也是向量,我将不得不这样做:

mutable struct foo
    x::Vector{String}
    y::Vector{String}
    z::Vector{String}
    w::Vector{String}
    # maybe dozens more...

    foo() = new([], [], [], [], ...)  # kind of ugly and wastes time to type

end

这是最好的吗?

你可以这样做:

julia> mutable struct Foo
           x::Vector{String}
           Foo() = new(String[])
       end

julia> Foo()
Foo(String[])

但是,对于您的情况,最方便的是 Base.@kwdef:

Base.@kwdef mutable struct FooB
    x::Vector{String} = String[]
    y::Vector{String} = String[]
end

现在当然可以了:

julia> FooB()
FooB(String[], String[])

但是也可以使用其他方法:

julia> methods(FooB)
# 3 methods for type constructor:
[1] FooB(; x, y) in Main at util.jl:478
[2] FooB(x::Vector{String}, y::Vector{String}) in Main at REPL[9]:2
[3] FooB(x, y) in Main at REPL[9]:2

所以你可以这样做:

julia> FooB(;y=["hello","world"])
FooB(String[], ["hello", "world"])

有一种替代方法非常简洁,几乎与写出输入一样快:

struct Foo  # Typenames should be uppercase
    x::Vector{String}
    y::Vector{String}
    z::Vector{String}
    w::Vector{String}
    Foo() = new((String[] for _ in 1:4)...) # using a generator and splatting
    # Foo() = new(ntuple(_->String[], 4)...) # also possible
end