如何在Ruby中执行反向运算符?我已经为我的类A实现了运算符'+',所以A + 2工作得很好,问题是:2 + A不起作用[重复]

vh0rcniy  于 2023-03-22  发布在  Ruby
关注(0)|答案(1)|浏览(88)

此问题在此处已有答案

Ruby: overload operator behaviour for some cases only(2个答案)
Multiplying string by integer vs integer by string in ruby(3个答案)
How to implicitly convert custom class to integer in Ruby?(2个答案)
Ruby: How ist the .+ method working internally?(2个答案)
4天前关闭。
在Ruby中,我应该如何执行反向运算符?例如,我已经为我的对象A实现了运算符'+',所以现在A + 2工作得很好。问题是:2 + A不起作用:(Python提供了__radd__来解决这个问题。我应该如何用Ruby解决这个问题?
我必须覆盖Integer的'+'运算符吗?如果它是一个float,我也必须覆盖Float的'+'运算符吗?我喜欢Ruby胜过Python(严格来说是个人和主观的意见),但在Python中你可以简单地做:

def __radd__(self, other): # other + self
    return self + other

Python提供了可以被覆盖的__add____radd__。Ruby提供了类似的东西吗?
希望在Ruby中有一个快速简单的解决方案,因为99.9%的时候都是这样。
谢谢!

j8yoct9x

j8yoct9x1#

在Python中,__radd____rsub__和friends的用法如下:文件
调用这些方法来实现二进制算术运算(+-*@///%divmod()pow()**<<>>&^|),具有反射(交换)操作数。只有当左操作数不支持相应的操作并且操作数的类型不同时,才会调用这些函数。例如,要计算表达式x - y,其中y是具有__rsub__()方法的类的示例,如果type(x).__sub__(x, y)返回NotImplemented,则调用type(y).__rsub__(y, x)
Ruby没有像这样的东西(也没有这种显式的东西);然而,Ruby可以使用#coerce执行类似的过程,以确保与其他数值类的示例的互操作性。
让我们假设A如下所示

class A 
  attr_reader :attr
  def initialize(a) 
    @attr = a 
  end 
 
  def +(other)
    other = other.attr if other.is_a?(A)
    A.new(attr + other)
  end 
end

用法:

a = A.new(12)
a + 2 
#=> #<A:0x00007fb2942c7f38 @attr=14>
a + a 
#=> #<A:0x00007fb294156eb0 @attr=24>
2 + a 
#=> `+': A can't be coerced into Integer (TypeError)

在本例中,您希望能够使用Integer#+A作为参数。

class A 
  def coerce(other) 
    [A.new(other), self]
  end 
end 
a = A.new(10) 
2 + a 
#=> #<A:0x00007fb2942e55d8 @attr=12>

如果您希望2 + a返回Integer,则可以更改coerce提供的Array

def coerce(other) 
  [other,attr] 
end

a = A.new(5) 
2 + a 
#=> 7

这里发生的事情(简单来说)是Integer#+将查看它是否可以将自己添加到A的示例中。由于它不知道A是什么,因此它将调用coerce方法并使用返回值再次尝试相同的消息。
pseudo 是这样工作的

arg1 = 2 
arg2 = A.new(12) 
message = :+ 
begin
  arg1.public_send(message,arg2) 
rescue TypeError 
  arg1, arg2 = arg2.coerce(arg1)
  retry
end

相关问题