【问题标题】:Ruby: how to overload arithmetic operations between numeric types and user-defined typesRuby:如何重载数值类型和用户定义类型之间的算术运算
【发布时间】:2026-01-03 21:55:01
【问题描述】:

在 Ruby 中,表达式 1 + Complex(1,1) 生成 Complex

我想为用户定义的类型实现相同的功能,以便 (1 + MyType.new(...)) 产生 MyType 的值

(1 - MyType.new(...)) 类似,但减法不可交换。

这可能吗?怎么样?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    你可以使用强制来处理这个问题:

    class MyType
      attr_reader :value
      def initialize(value)
        @value = value
      end 
      def +(n)
        if n.is_a?(MyType)
          MyType.new(self.value + n.value)
        else
          @value += n 
          self
        end 
      end 
      def coerce(other)
        [MyType.new(other), self]
      end
    end
    
    1 + MyType.new(12) 
    #=> #<MyType:0x0000561609d5d9a8 @r=13>
    # or even 
    1 + MyType.new(12) + 3 
    #=> #<MyType:0x0000561bc671d170 @r=16>
    

    Integer 1 收到MyType 作为+ 方法的参数时,它不知道如何直接处理它,因此它会尝试通过调用coerce 将其强制为它可以理解的东西参数对象并将其自身传递给coerce 方法。

    coerce 方法应始终返回包含 2 个值的 Array。然后Integer 将尝试和+ 一起使用第一个作为接收者,第二个作为参数。

    所以本质上是这样的:

    a = 1
    b = MyType.new(12) 
    begin 
      a + b
    rescue TypeError 
      b.coerce(a).reduce(&:+)
    end 
    

    This article 对强制转换的工作原理进行了更深入的解释,并提供了何时有用的示例。

    【讨论】:

    • 非常有趣。另一个例子:1.2 + MyType.new(12) + Rational(3,4) #=&gt; #&lt;MyType:0x00005abcba32b230 @value=13.95&gt;.
    • @CarySwoveland ahhh 强制链非常好
    • 非常适合像“+”这样的交换运算符。非交换运算符呢? 3 - x != x - 3
    • @engineersmnky -- 谢谢!