假设我有一个函数,其中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"