请问 +, -, *, /
的类型是什么?Julia REPL 默认给的是 typeof(+),typeof(-),typeof(*),typeof(/)
. 他们的超类型是 Function
.
julia> supertype(typeof(+))
Function
问这个的原因是我想 forward +, -, *, /
四个运算到我自己定义的类型 X
上,
function (op::Function)(f::T, g::T)::T where {T <: X}
T(op(f, g))
end
希望能把类型再限制的死一点。不过这个函数似乎过不了编译。
查了一下发现好像 typeof(+)
也是一个类型:
julia> subtypes(Function)
8244-element Array{Any,1}:
Base.Fix1
Base.Fix2
Colon
Core.Builtin
Core.Compiler.Colon
Core.Compiler.Fix1
Core.Compiler.Fix2
getfield(Base, Symbol("###44#45#46"))
getfield(Base, Symbol("##10#11"))
getfield(Base, Symbol("##101#102"))
getfield(Base, Symbol("##103#104"))
getfield(Base, Symbol("##106#108"))
getfield(Base, Symbol("##107#109"))
getfield(Base, Symbol("##110#111"))
getfield(Base, Symbol("##112#113"))
getfield(Base, Symbol("##115#117"))
getfield(Base, Symbol("##116#118"))
getfield(Base, Symbol("##119#121"))
getfield(Base, Symbol("##12#13"))
getfield(Base, Symbol("##120#122"))
getfield(Base, Symbol("##123#125"))
getfield(Base, Symbol("##124#126"))
getfield(Base, Symbol("##129#132"))
⋮
typeof(widen)
typeof(withenv)
typeof(write)
typeof(xor)
typeof(yield)
typeof(yieldto)
typeof(zero)
typeof(zeros)
typeof(zip)
typeof(|)
typeof(|>)
typeof(~)
typeof(∉)
typeof(∋)
typeof(∌)
typeof(∘)
typeof(≉)
typeof(⊇)
typeof(⊈)
typeof(⊉)
typeof(⊊)
typeof(⊋)
完整版在 https://gist.github.com/singularitti/fc849e36a79b3e17672dbb0ae76982f8
Jun
3
挺好的一个问题。
尝试回答下,以前我对Function
也有过误解 关于Function和参数类型的一个疑惑 - #3,来自 thautwarm 以下回答不一定准确,仅供参考。
我用下面的代码把你的问题稍稍展开下:
struct X
x::Int
end
const KnownOps = Union{typeof(+), typeof(-), typeof(*), typeof(/)}
function (op::KnownOps)(f::X, g::X)
op(f.x, g.x)
end
但是,如你所说,这段代码会报错,
julia> function (op::KnownOps)(f::X, g::X)
op(f.x, g.x)
end
ERROR: cannot add methods to an abstract type
这个错在好几个地方有讨论:
不过,这里只是 Union
类型,并不是AbstractType
(为啥也会报同样的错呢?坐等其他人解答)
所以,可以这样子:
julia> function (op::typeof(*))(f::X, g::X)
op(f.x, g.x)
end
julia> function (op::typeof(-))(f::X, g::X)
op(f.x, g.x)
end
julia> *(X(2), X(3))
6
julia> -(X(2), X(3))
-1
一个一个写有点蠢,可以用@eval宏。
1 个赞
Roger
5
讲一下怎么实现你要的这个功能,运算符重载我们一般用@eval
做代码生成,这样也能防止歧义
for op in [:+, :-, :*, :/]
@eval Base.$op(lhs::LHSType, rhs::RHSType) where {LHSType, RHSType} = # blabla
end
PS. 注意重载的时候最好别 import
而是显式写出要重载的函数路径,不然以后重构或者重新修改代码的时候就是火葬场的感觉…
2 个赞
Roger
7
是的,我最近在refactor以前的代码遇到这个坑。现在明白为啥大家都不用import来重载了。如果觉得麻烦可以用@eval
做代码生成,但是前缀要加。