在Julia中以编程方式定义struct 问题

在Julia中以编程方式定义struct 问题,struct,julia,Struct,Julia,我从一个文件中读取数据,该文件将附加到一个树状结构。文件的每一行都包含有关树节点的属性 三个属性是必需的(并且是不可变的),用户可以指定任何其他属性。用户提供的属性可以是任何东西,但我们在导入时知道它们的名称和类型,因为它们是在文件中提供的 当树完成时,在典型的用例中,只读取节点的一些字段,但修改一些字段 我目前正在使用Dict{String,Any}在我的节点结构中存储用户定义的数据,但我知道这对性能是不可取的。这是特别重要的考虑,因为许多计算是事后作出的。 我的当前结构有两个字段,一个用于与

我从一个文件中读取数据,该文件将附加到一个树状结构。文件的每一行都包含有关树节点的属性


三个属性是必需的(并且是不可变的),用户可以指定任何其他属性。用户提供的属性可以是任何东西,但我们在导入时知道它们的名称和类型,因为它们是在文件中提供的

当树完成时,在典型的用例中,只读取节点的一些字段,但修改一些字段

我目前正在使用Dict{String,Any}在我的节点结构中存储用户定义的数据,但我知道这对性能是不可取的。这是特别重要的考虑,因为许多计算是事后作出的。 我的当前结构有两个字段,一个用于与任何节点相关的强制属性(它们是不可变的),另一个用于文件中给出的其他属性。结构如下所示:

mutable struct Node1
    attr1::Node2
    attr2
end
mutable struct Node{T}
    attr1::ImmutableNodeData
    attr_name::String
    attr_val::T
end
mutable struct Node{T <: NamedTuple}
    attr1::ImmutableNodeData
    user_attrs::T
end
Node1
的第一个字段中的不可变结构如下所示:

struct Node2
    link::AbstractString
    symbol::Union{Missing,AbstractString}
    index::Union{Missing,Integer}
end
问题 现在我的问题是:我能做得更好吗?

例如,我是否可以基于文件中给定的属性,通过编程将我的
Node1
struct设置为带有字段的结构?这将允许我至少给出每个属性的类型,而不仅仅是
Any

。其思想是在创建节点对象时,在运行时确定字段
attr2
的类型。参数化类型允许字段的类型是可变的。下面是一个这样的示例:

struct ImmutableNodeData
    link::String
    symbol::Union{Nothing,String}
    index::Union{Nothing,Int}
end

mutable struct Node{T}
    attr1::ImmutableNodeData
    attr2::T
end
我已经重新命名了structs,使其更具信息性。以下是我们如何在REPL上使用这些类型:

julia> imm = ImmutableNodeData("a", "b", 1)
ImmutableNodeData("a", "b", 1)

julia> n1 = Node(imm, 100)
Node{Int64}(ImmutableNodeData("a", "b", 1), 100)

julia> n2 = Node(imm, "hello")
Node{String}(ImmutableNodeData("a", "b", 1), "hello")
请注意,我们如何创建一个
节点{Int64}
节点{String}
,只需分别调用第二个参数为
Int64
字符串的构造函数

还要注意,对于
ImmutableNodeData
,我已将字段的类型更改为具体类型或具体类型的并集。为了提高性能,您总是希望结构的字段具有具体类型,而不是抽象类型

编辑:

如果在运行时也确定了
attr2
名称,则可以将
attr2::T
拆分为如下两个字段:

mutable struct Node1
    attr1::Node2
    attr2
end
mutable struct Node{T}
    attr1::ImmutableNodeData
    attr_name::String
    attr_val::T
end
mutable struct Node{T <: NamedTuple}
    attr1::ImmutableNodeData
    user_attrs::T
end
编辑#2:

如果有多个用户提供的属性,那么您可以将所有这些属性存储在名为tuple的
中,正如Oscar Smith在评论中提到的那样。您可以将此命名元组作为参数化类型的字段包含在
节点
结构中,如下所示:

mutable struct Node1
    attr1::Node2
    attr2
end
mutable struct Node{T}
    attr1::ImmutableNodeData
    attr_name::String
    attr_val::T
end
mutable struct Node{T <: NamedTuple}
    attr1::ImmutableNodeData
    user_attrs::T
end
请注意,命名元组存储这两个字段的类型(
Int64
String
),而字典只将值视为具有type
Any

我想读操作更快,但变异操作更慢,对吧


我不希望变异
MutableNamedTuple
比变异
Dict
慢,但你必须做一些基准测试来确认这一点。

使用命名元组怎么样?它们是不可变的,对吗?除非有一种方法可以在与Dict相比没有太多开销的情况下改变元组中的值,否则“用户提供的属性可以是任何东西。”它们真的可以是任何东西吗?或者是否存在一组有限的可接受的属性类型?因为如果有一组有限的可接受类型的属性,并且该集的大小不太大,那么为每种类型的属性创建自定义类型可能是有意义的。谢谢您在这么短的时间内给出了这个非常完整的答案!是的,我需要几个属性,然后我将接受你的最后一个建议,我将尝试研究MutableNamedTuple。与Dict相比,使用它们真的有优势吗?我想读操作更快,但变异操作更慢,对吧?不管怎样,我会测试一下,再次谢谢你@rvezy,我编辑了我的答案以回答您的问题。:)