在Julia中,如何正确地对调用方提供的(超级)类型的参数执行方法分派?
我想定义一个函数在Julia中,如何正确地对调用方提供的(超级)类型的参数执行方法分派?,julia,Julia,我想定义一个函数f(x,t::Type),根据isa(x,t)是否执行不同的行为。假设我想调用b1(x),如果是,则调用b2(x) 我知道我可以在运行时执行如下动态检查: function f(x, t::Type) if isa(x, t) b1(x) else b2(x) end end 然而,有没有一种方法可以完全通过参数化方法分派来实现这一点?例如,如果我定义 f{T}(x::T, t::Type{T}) = b1(x) f(x, t::Type) = b2
f(x,t::Type)
,根据isa(x,t)
是否执行不同的行为。假设我想调用b1(x)
,如果是,则调用b2(x)
我知道我可以在运行时执行如下动态检查:
function f(x, t::Type)
if isa(x, t)
b1(x)
else
b2(x)
end
end
然而,有没有一种方法可以完全通过参数化方法分派来实现这一点?例如,如果我定义
f{T}(x::T, t::Type{T}) = b1(x)
f(x, t::Type) = b2(x)
对于f(1,Int)
和f(1.0,Int)
调用正确的行为。但我希望这也适用于t
的所有子类型:
f(1, Number)
这实际上调用了b2
,因为f
的第一个签名不匹配。有趣的是,f(x::Number,t::Type{Number})=b1(x)
在这种情况下会匹配
我是不是漏掉了什么明显的东西
这显然是一个bug,在0.4中已修复
问题:
f{T}(x::T,T::Type{T})
与f(1,Number)
不匹配,即使T
(Number
)有一个匹配的类型替换f{T2,T1回答您的问题:
正如user3580870所评论的,这在Julia0.4中似乎是可行的
这是“三角分派”,尚未实施。请参阅
取决于。编译器可以在编译时计算isa(x,t)
,并消除分支。但是,使用isa
仍有一些可能的方法不太理想:
- 如果两个分支返回不同的类型,则类型推断将无法正确推断返回类型,因为它发生在
isa(x,t)
变成常量之前。(这可能代价高昂;下面其他可能的去优化可能不是什么大问题。)
- 如果一个分支执行堆分配,而另一个不执行,则可能会发出不必要的GC帧
- 该函数不能内联
内部函数将与使用isa
等类似的性能问题。从Julia 0.5开始,在这种情况下,内部函数应该与顶级函数一样高效
归档一个bug;-)。我认为这应该是可行的。在0.4中修复的任何东西都可能被后端口到0.3。但是如果失败,isa
不是一个好方法,只要它不会导致类型推断问题
我有版本0.4.0-dev+1307和f(1,编号)您说得对,我已经确认这在0.4.0-dev+1521上有效。感谢您快速而出色的回答。这在0.4中确实有效,解决了我的问题。但是您能否详细说明内部函数方法的性能问题,或者指导我到一个可以了解更多信息的地方?为什么这比在顶层定义函数?只是澄清一下:如果调用的函数确实返回不同类型的对象,f{T}(x::T,T::Type{T})=b1(x)
-方法会更快?