Julia 具有有限数量或值的结构元素

Julia 具有有限数量或值的结构元素,julia,Julia,我想创建一个struct mutable struct myStruct id::string end 我确实希望id是一个字符串,但我希望它只接受3个值中的1个(例如“a”,“b”或“c”)。我的想法是,从理论上讲,这可以加快运营速度 关于提速,我说得对吗 这可能吗?如何实现 我不知道有什么方法可以让id成为String,同时限制它只有3个可能值中的一个,这样编译器就可以利用它 但是,如果可以选择离开字符串域,则有几种可能性。让我们尝试在这里对其中一些进行基准测试。为了便于示例,我们

我想创建一个
struct

mutable struct myStruct
    id::string
end
我确实希望
id
是一个字符串,但我希望它只接受3个值中的1个(例如
“a”
“b”
“c”
)。我的想法是,从理论上讲,这可以加快运营速度

  • 关于提速,我说得对吗
  • 这可能吗?如何实现

  • 我不知道有什么方法可以让
    id
    成为
    String
    ,同时限制它只有3个可能值中的一个,这样编译器就可以利用它

    但是,如果可以选择离开
    字符串
    域,则有几种可能性。让我们尝试在这里对其中一些进行基准测试。为了便于示例,我们假设此
    id
    字段用于测试两个
    MyStruct
    实例之间的相等性

    这种类型的一种可能的(非常简单的)通用实现如下所示,其中参数
    T
    确定用于id的类型

    mutable struct MyType{T}
        id :: T
    end
    
    # Two MyType instances are equal if their ids are equal
    import Base.==
    ==(a::MyType{T}, b::MyType{T}) where {T} = (a.id == b.id)
    
    
    现在让我们在各种情况下对等式运算符进行基准测试。首先,使用字符串作为标识符的基本情况:

    julia> using BenchmarkTools
    
    julia> a = MyType("apple")
    MyType{String}("apple")
    
    julia> b = MyType("banana")
    MyType{String}("banana")
    
    julia> @btime $a == $b
      4.326 ns (0 allocations: 0 bytes)
    false
    
    我们希望整数更快,事实上是这样的:

    julia> a = MyType(1)
    MyType{Int64}(1)
    
    julia> b = MyType(2)
    MyType{Int64}(2)
    
    julia> @btime $a == $b
      1.882 ns (0 allocations: 0 bytes)
    false
    
    但也许API不那么方便。使用可能更具可读性(用户不必记住哪个值对应于“apple”)。它还可以防止使用任何未预定义的值,同时保持相同的性能:

    julia> @enum Fruit begin
               apple
               banana
           end
    
    julia> a = MyType(apple)
    MyType{Fruit}(apple)
    
    julia> b = MyType(banana)
    MyType{Fruit}(banana)
    
    julia> @btime $a == $b
      1.816 ns (0 allocations: 0 bytes)
    false
    
    julia> a = MyType(:apple)
    MyType{Symbol}(:apple)
    
    julia> b = MyType(:banana)
    MyType{Symbol}(:banana)
    
    julia> @btime $a == $b
      1.883 ns (0 allocations: 0 bytes)
    false
    
    可能值得考虑的最后一个选项是用于密钥,它保留(IMO)可用性和性能:

    julia> @enum Fruit begin
               apple
               banana
           end
    
    julia> a = MyType(apple)
    MyType{Fruit}(apple)
    
    julia> b = MyType(banana)
    MyType{Fruit}(banana)
    
    julia> @btime $a == $b
      1.816 ns (0 allocations: 0 bytes)
    false
    
    julia> a = MyType(:apple)
    MyType{Symbol}(:apple)
    
    julia> b = MyType(:banana)
    MyType{Symbol}(:banana)
    
    julia> @btime $a == $b
      1.883 ns (0 allocations: 0 bytes)
    false
    
    没有任何东西可以阻止任何人构建非法值,例如
    MyStruct(:cheddar)
    ,但它非常适合处理字符串的上下文。例如,如果您在工作流中的某个位置以字符串形式获取id,则可以在构建
    MyStruct
    实例之前轻松地将其转换为符号:

    julia> id = "apple"
    "apple"
    
    julia> a = MyType(Symbol(id))
    MyType{Symbol}(:apple)
    

    使用朱莉娅的打字系统!不需要外部库

    abstract type Fruit end
    struct Apple <: Fruit end 
    struct Banana <: Fruit end
    struct Coconut <: Fruit end
    
    struct MyType{T<:Fruit}
        #could be some fields here...
    end
    
    a = MyType{Apple}()
    a2 = MyType{Apple}()
    b = MyType{Banana}()
    
    编辑 对问题的回答@Cameron Bieganek


    你对什么时候定义更合理有什么意见或指导吗 手动输入单例类型,以及何时使用
    枚举更有意义

    我个人的看法如下:

    • 每当编译时已知类型值时,始终使用单例类型
    • 只要在编译时已知一小组类型(符合小联合的条件),就使用单例时间
    • 如果您计划根据类型实现不同的处理,请使用单例类型-广播将比一系列if语句更快
    • 在设计API(您自己的Julia包)时,请使用单例类型,因为您可以使用Julia的文档功能
    • 当运行时生成大量值(例如
      String
      s)并且您计划对它们进行相等比较时,请使用
      Symbol
      s。很好的例子是解析一个CSV文件,其中列包含标称值 在其他情况下,考虑使用<代码> EnUM <代码> >或<代码>符号< /代码> s -使用代码可读性作为标准。李>
    听起来像是
    枚举
    在语义上更合适。我不知道是否会有性能上的差异。嗯,这听起来是一种可能的方式。你能详细解释一下并给出答案吗?你对手工定义单例类型和使用
    Enum
    更合理有什么意见或指导吗?@Cameron Bieganek谢谢你的提问。我试着回答:-)回答得好,谢谢!这已经包含在您的“其他案例”中,但我可能会更明确地补充一点,当您计划存储一个值集合时,枚举或符号允许在具体类型的容器中进行存储,因此可能是首选。@CameronBieganek我认为单例类型在您准备(de)时更有意义序列化枚举。我不知道从包含名称的字符串或符号构造枚举大小写的好方法。我想这可能是一个有趣的问题。当然,我们可以通过元编程找到一些想法。