如何给一个支持某种interface的参数加类型约束?


#1

比如,我想写一个函数f(x), 这里x可以是1:10或者Vector等等支持Iteration的类型。

x本身的类型没法提前知道,故无法直接通过Union{}给参数x添加类型约束。


#2

若函数 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 。


Dispatch, Traits and MetaProgramming Over Reflection