比如,我想写一个函数f(x)
, 这里x
可以是1:10
或者Vector
等等支持Iteration
的类型。
x
本身的类型没法提前知道,故无法直接通过Union{}
给参数x
添加类型约束。
若函数 f
要求 x
的类型必须支持某种 Iteration
类型,若 x
不满足,则报一个 Argument Error, 可以用 trait 来实现这种行为:
julia> struct IsIteration end # trait singleton type
julia> struct NotIteration end # trait singleton type
julia> trait_judge(x::AbstractRange) = IsIteration # trait function only for dispatch purpose
trait_judge (generic function with 1 method)
julia> trait_judge(x) = NotIteration # trait function only for dispatch purpose
trait_judge (generic function with 2 methods)
julia> trait_judge(x::AbstractVector) = IsIteration # trait function only for dispatch purpose
trait_judge (generic function with 3 methods)
# implementation subroutine if x supports some traits
julia> _f(x, ::Type{IsIteration}) = "ok, x is iterable, can safely do the following stuff..."
_f (generic function with 1 method)
julia> f(x) = _f(x, trait_judge(x))
f (generic function with 1 method)
julia> f(1:10)
"ok, x is iterable, can safely do the following stuff..."
julia> f([1,2,3])
"ok, x is iterable, can safely do the following stuff..."
julia> f(1)
ERROR: MethodError: no method matching _f(::Int64, ::Type{NotIteration})
Closest candidates are:
_f(::Any, ::Type{IsIteration}) at REPL[8]:1
Stacktrace:
[1] f(::Int64) at .\REPL[6]:1
julia> @code_typed f(1:10)
CodeInfo(
1 1 ─ return "ok, x is iterable, can safely do the following stuff..." │
) => String
可以看到 trait 函数被优化调了,没有 overhead 。