Julia 函数内的联合类型特化

Union type specialization within a function in Julia

假设我有一个函数,其中 c 关键字参数是 Union 类型。根据 c 的类型,我想在函数内做一些事情:

function foo(a :: Integer, b :: AbstractFloat; c :: Union{Integer, AbstractFloat} = nothing)
    if typeof(c) <: AbstractFloat
        d = c / pi
    elseif typeof(c) <: Integer
        d = typeof(b)(c ^ 2)
    end
    return d
end

这是处理这种情况的正确方法吗?我应该改为使用多重分派来实现更有效的实现吗?我也在考虑这里的性能。

谢谢。

一些评论。

这部分:

c::Union{Integer, AbstractFloat} = nothing

不会编译,你必须写成c::Union{Nothing, Integer, AbstractFloat} = nothing.

一般来说,typeof(c) <: AbstractFloat 应该被编译器优化掉,因为编译器知道你传递的 c 的确切类型,所以这种风格应该不会影响你的代码的性能。

但是,有两个注意事项:

  1. 使用多种方法可能会导致代码更清晰。
  2. 如果您使用 Union,则在定义方法时必须更加小心以避免分派歧义。这是一个例子:
julia> f(x::Int, y::Union{Int, Float64}) = "f1"
f (generic function with 1 method)

julia> f(x::Integer, y::Int) = "f2"
f (generic function with 2 methods)

julia> f(1, 1)
ERROR: MethodError: f(::Int64, ::Int64) is ambiguous.

这有时被认为是令人惊讶的(尽管从技术上讲这是正确的行为)

编辑。这是一个编译器不会抱怨的例子,因为它总是可以建立一个更具体的方法:

julia> g(x::Int, y::Union{Int, Float64}) = "f1"
g (generic function with 1 method)

julia> g(x::Integer, y::Union{Int, Float64}) = "f2"
g (generic function with 2 methods)

julia> g(1, 1)
"f1"