考虑 Base 中的一个现有函数,它接受某种抽象类型的可变数量的参数 T
。我定义了一个子类型 S<:T
并想编写一个方法,如果任何参数是我的子类型 S
则进行调度.
作为示例,请考虑函数 Base.cat
,与 T
是 AbstractArray
和S
是一些MyCustomArray <: AbstractArray
.
期望的行为:
julia> v = [1, 2, 3];
julia> cat(v, v, v, dims=2)
3×3 Array{Int64,2}:
1 1 1
2 2 2
3 3 3
julia> w = MyCustomArray([1,2,3])
julia> cat(v, v, w, dims=2)
"do something fancy"
尝试:
function Base.cat(w::MyCustomArray, a::AbstractArray...; dims)
pritnln("do something fancy")
end
但这仅在第一个参数为 MyCustomArray
时才有效。 .
实现这一目标的优雅方法是什么?
最佳答案
我想说,如果没有类型盗版,就不可能干净地做到这一点(但如果可能的话,我也想学习如何做)。
例如考虑 cat
你问过的。它在 Base 中有一个非常通用的签名(实际上并不要求 A
是您所写的 AbstractArray
):
julia> methods(cat)
# 1 method for generic function "cat":
[1] cat(A...; dims) in Base at abstractarray.jl:1654
你可以编写一个特定的方法:
Base.cat(A::AbstractArray...; dims) = ...
并检查 A
中是否有任何元素是你的特殊数组,但这将是类型盗版。
现在的问题是你甚至不能写 Union{S, T}
自S <: T
以来它将被解析为 T
.
这意味着您必须使用S
明确地在签名中,但甚至:
f(::S, ::T) = ...
f(::T, ::S) = ...
有问题,编译器会要求您定义 f(::S, ::S)
因为上述定义导致调度含糊不清。因此,即使您想将可变参数的数量限制为某个最大数量,您也必须为 A
的所有分区注释类型。分成子集以避免分派(dispatch)歧义(这可以使用宏实现,但所需方法的数量呈指数级增长)。
关于julia - 如何根据任何 splatted args 的类型进行调度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63285604/