`+, -, *, /` 的类型

请问 +, -, *, / 的类型是什么?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

挺好的一个问题。

尝试回答下,以前我对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 个赞

文档里说

类型共用体 Union 是一种特殊的抽象类型
—— 类型 · Julia中文文档

2 个赞

讲一下怎么实现你要的这个功能,运算符重载我们一般用@eval做代码生成,这样也能防止歧义

for op in [:+, :-, :*, :/]
     @eval Base.$op(lhs::LHSType, rhs::RHSType) where {LHSType, RHSType} = # blabla
end

PS. 注意重载的时候最好别 import 而是显式写出要重载的函数路径,不然以后重构或者重新修改代码的时候就是火葬场的感觉…

2 个赞

是指应该这样吗?

是的,我最近在refactor以前的代码遇到这个坑。现在明白为啥大家都不用import来重载了。如果觉得麻烦可以用@eval做代码生成,但是前缀要加。