为什么要在 Julia 中创建抽象超类型?

log*_*ick 6 types supertype julia

我正在查看某人的代码,它<:在创建结构时使用。我查看了文档,发现这意味着他们正在创建一个抽象超类型。谁能解释一下这是什么以及为什么要使用它?

Dav*_*ela 9

什么是抽象类型?

抽象类型是类型层次结构中的节点:它们将类型组合在一起。这允许您编写适用于整个类型组的方法:

julia> abstract type AbstractFoo end

julia> struct Foo1 <: AbstractFoo end

julia> struct Foo2 <: AbstractFoo end

julia> foo_op(x::AbstractFoo) = "yay!"
foo_op (generic function with 1 method)

julia> foo_op(Foo1())
"yay!"

julia> foo_op(Foo2())
"yay!"
Run Code Online (Sandbox Code Playgroud)

为什么抽象类型有用?

抽象类型允许您将行为与实现分开。这对性能至关重要。当你声明一个抽象超类型时,你会自动继承超类型的核心行为,但可以自由地实现该行为的更有效的实现

一个常见的例子是AbstractArray抽象类型。它代表了访问某些多维元素集合的单个元素的能力。给定一些问题,我们通常可以选择抽象数组的子类型,这将产生高效的操作:子类型上的附加约束构成了程序员可以利用的信息来使某些操作更高效

例如,假设我们要找到 1..N 的总和。我们可以使用整数数组,但这与 a 相比效率非常低UnitRangeUnitRange关于数据特征的编码信息的选择;我们可以利用信息来提高效率。(有关示例的更多信息,请参阅此答案)。

julia> using BenchmarkTools

julia> @btime sum($(1:1000_000))
  0.012 ns (0 allocations: 0 bytes)
500000500000

julia> @btime sum($(collect(1:1000_000)))
  229.979 ?s (0 allocations: 0 bytes)
500000500000
Run Code Online (Sandbox Code Playgroud)

BitArray为布尔数组提供空间高效的表示,SparseArrays为稀疏数据提供高效的操作,等等。如果您有一些数据通常表现得像一个抽象数组,但具有独特的特征,您可以定义自己的子类型。

这种模式推广到其他抽象类型。使用它们来对某些共享行为的不同实现进行分组。


phi*_*ler 5

一个更实际的用例是创建强类型的、可能相互递归的结构。例如,您不能编写以下内容:

struct Node
    edges::Vector{Edge}
end

struct Edge
    from::Node
    to::Node
end
Run Code Online (Sandbox Code Playgroud)

写这个的一种方法是相当人为的

abstract type AbstractNode end
abstract type AbstractEdge end

struct Node{E<:AbstractEdge}
    edges::Vector{E}
end

struct Edge{N<:AbstractNode}
    from::N
    to::N
end
Run Code Online (Sandbox Code Playgroud)

通常,有了足够的经验,这个问题在数据结构的设计过程中自然就已经解决了,如下所示:

abstract type Program end
abstract type Expression <: Program end
abstract type Statement <: Program

struct Literal <: Expression
    value::Int
end

struct Var <: Expression
    name::Symbol
end

struct Plus <: Expression
    x::Expression
    y::Expression
end

struct Assign <: Statement
    var::Var
    expr::Expression
end

struct Block <: Expression
    side_effects::Vector{<:Program}
    result::Expression
end
Run Code Online (Sandbox Code Playgroud)

这确保Expressions(计算为数字Statement的东西)和s(只是副作用的东西)被正确分开——你永远不能创建像1 + (x = 2). 如果没有抽象类型(或相互递归的类型,但它们目前不存在),就无法编写它。