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
的确切类型,所以这种风格应该不会影响你的代码的性能。
但是,有两个注意事项:
- 使用多种方法可能会导致代码更清晰。
- 如果您使用
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"
假设我有一个函数,其中 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
的确切类型,所以这种风格应该不会影响你的代码的性能。
但是,有两个注意事项:
- 使用多种方法可能会导致代码更清晰。
- 如果您使用
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"