Julia

时间:2019-01-26 20:17:38

标签: julia

在Julia中是否可以有两个具有相同名称但被赋予不同类型并因此可区分的结构?

我一直在读https://docs.julialang.org/en/v1/manual/types/#Parametric-Types-1,它似乎可以达到我想要的目的,但是我无法使它正常工作...

在分子模拟的力场中,存在二面体参数来描述分子中的扭转角。为了示例目的有不同的种类,让我们将它们限制为2种:适当和不适当。我想有两个结构,都称为二面体,但是给定了类型“ proper”和“ improper”。然后,我将有针对每种类型的特定方法来计算由于二面角而产生的力。我认为抽象参数类型使我最接近想要的参数,但是我无法对它们进行排序...

abstract type proper end
abstract type improper end

struct Dihedral <: proper
    ai::Int64
    kparam::Vector{Float64}
end

struct Dihedral <: improper
    ai:Int64
    kparam::Float64
end

上面的代码不起作用...我尝试使用

abstract type dihedral end
abstract type proper <: dihedral end
abstract type improper <: dihedral end

struct Dihedral <: dihedral{proper}
...
end

struct Dihedral <: dihedral{improper}
...
end

但是我总是在重新定义Dihedral

时遇到麻烦
ERROR: LoadError: invalid redefinition of constant Dihedral
Stacktrace:
 [1] top-level scope at none:0

我的想法是,我可以添加更多类型的二面体,而我所需要做的就是添加它们的方法,并且模拟将自动使用新的dihedral.methods。如果我尝试使用不同名称的结构,那么我开始不得不使用if语句将程序定向到正确的结构,然后再定向到正确的方法...这就是我要避免的,即

if dihedraltype == "proper"
    struct_proper(...)
elseif dihedraltype =="improper"
    struct_improper() 
elseif dihedraltype == "newStyle"
    struct_newStyle()
end

使用此方法,我将不得不在代码中找到所有我称为dihedral的位置并添加新类型... dihedral只是一个示例,许多“现象”具有不同的计算现象的方法。

1 个答案:

答案 0 :(得分:5)

如果要使用参数类型,我将使用以下方法:

abstract type DihedralType end

struct Proper <: DihedralType
    ai::Int64
    kparam::Vector{Float64}
end

struct Improper <: DihedralType
    ai::Int64
    kparam::Float64
end

struct Dihedral{T<:DihedralType}
    value::T
end

Dihedral(ai::Int64, kparam::Vector{Float64}) = Dihedral(Proper(ai, kparam))
Dihedral(ai::Int64, kparam::Float64) = Dihedral(Improper(ai, kparam))

现在您可以编写例如:

Dihedral(1, [1.0, 2.0])
Dihedral(1, 1.0)

类型Dihedral的参数向您传递信息,说明您正在使用哪种对象。然后,某些方法可能是通用的,并调用Dihedral,例如:

julia> ai(d::Dihedral) = d.value.ai
ai (generic function with 1 method)

julia> ai(Dihedral(1, 1.0))
1

julia> ai(Dihedral(1, [1.0, 2.0]))
1

julia> kparam(d::Dihedral) = d.value.kparam
kparam (generic function with 1 method)

julia> kparam(Dihedral(1, 1.0))
1.0

julia> kparam(Dihedral(1, [1.0, 2.0]))
2-element Array{Float64,1}:
 1.0
 2.0

有些可能是类型参数所特有的:

julia> len(d::Dihedral{Proper}) = length(kparam(d))
len (generic function with 1 method)

julia> len(Dihedral(1, [1.0, 2.0]))
2

julia> len(Dihedral(1, 1.0))
ERROR: MethodError: no method matching len(::Dihedral{Improper})
Closest candidates are:
  len(::Dihedral{Proper}) at REPL[15]:1
Stacktrace:
 [1] top-level scope at none:0

这种方法能给您期望吗?

编辑

实际上,对于您来说,甚至更简单的方法可能就足够了(取决于用例)。只需定义:

abstract type AbstractDihedral end

struct Proper <: AbstractDihedral
    ai::Int64
    kparam::Vector{Float64}
end

struct Improper <: AbstractDihedral
    ai::Int64
    kparam::Float64
end

,然后使用DihedralType来实现方法(如果它们对于所有二面体都是通用的),并且如果您想向给定的具体类型中添加某些特定方法,只需在签名中将此方法与具体类型一起添加即可。例如:

ai(d::AbstractDihedral) = d.ai
kparam(d::AbstractDihedral) = d.kparam
len(d::Proper) = length(d.kparam) # will not work for Improper

在这种方法中,您不需要使用参数类型。区别在于,在参数类型方法中,您可以提取出所有与“父”结构的所有二面体相同的参数,并仅在“包装”结构中定义特定于二面体的参数。在第二种方法中,您每次都为每个结构定义所有字段。