julia - Julia 中的抽象参数类型

标签 julia

在 Julia 中是否可以有两个具有相同名称但被分配不同类型从而可区分的结构体?

我一直在读https://docs.julialang.org/en/v1/manual/types/#Parametric-Types-1它似乎正朝着我想要的方向发展,但我无法让它发挥作用......

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

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

使用这种方法,我将不得不在我的代码中找到我调用二面角并添加新类型的所有地方......二面角只是一个例子,有许多“现象”有不同的方法来计算现象。

最佳答案

如果您想使用参数类型,我会使用以下方法:

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

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

关于julia - Julia 中的抽象参数类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54382340/

相关文章:

julia - 在 Julia 中,从矩阵访问的值无法用作函数中的参数

matrix - 在 Julia 中平铺或重复 n 维数组

optimization - 获取大量点积的更好方法?

macros - Julia 宏 : @__FILE__ @__LINE__ in macro

julia - 是否有将 REPL 内容打印到 Julia 语言文件的功能?

Julia 中的模块别名

regression - Julia 混合效应模型中随机斜率的相互作用

string - 对于未更改的字符串,去掉 Julia 的 `WARNING: redifining constant` 吗?

julia - Julia 1.0 的环境变量

arrays - 将数组从 Julia 发送到 Rust(使用 "ccall")