0

Rubyでは、多くのcoerce()ヘルプを次の方法で実行できるようです。

def coerce(something)
  [self, something]
end

つまり、いつ

3 + rational

が必要な場合、Fixnum3はRationalの追加を処理する方法を知らないため、rational.coerce(3)を呼び出してRational#coerceにヘルプを要求し、この強制インスタンスメソッドは呼び出し元に次のように通知します。

# I know how to handle rational + something, so I will return you the following:
[self, something]
# so that now you can invoke + on me, and I will deal with Fixnum to get an answer

では、ほとんどのオペレーターがこのメソッドを使用できるが、(a --b)!=(b --a)の状況では使用できない場合はどうなるでしょうか。coerce()は、それがどの演算子であるかを認識し、それらの特殊なケースを処理するだけで、(a op b)==(b op a)である他のすべてのケースを処理するために単純な[self、something]を使用できますか?(opは演算子です)。

4

2 に答える 2

1

この質問に対する答えは、バックトレースを見ることでオペレーターを知ることができるということですが、そうすべきではありません。

これは、Rubyの強制メカニズムが設計された方法ではありません。前の質問で答えたように、演算子が何であれ、機能するcoerce2つの同等の値を返す必要があります。[a, b]a.send(operator, b)

于 2010-05-11T05:30:24.407 に答える
1

重要なのcoerceは、実行しようとしている操作を知らないことです。その目的は、議論をself共通の基盤に導くことです。さらに、同じ演算子は特定のクラスでは可換であり、他のクラスでは可換ではない可能性があるため(たとえば、)、可換性に基づく小さなNumeric#+エクスプロイトは実際には効果がありません。Array#+coerce

coerce意図しないことを実行するようにプッシュする代わりに、代わりに新しいクラス(たとえばScalarPoint、など)を作成し、それを使用してスカラー値をPoint:とインターフェイスさせる必要があります。

class ScalarPoint
  attr_reader :val

  def initialize(val)
    @val = val
  end

  def +(arg)
    case arg
    when Point:
      Point.new(@val + arg.x, @val + arg.y)
    when ScalarPoint:
      ScalarPoint.new(arg.val + @val)
    else
      raise "Unknown operand!"
    end
  end

  # define other operators, such as * etc

  def coerce(arg)
    return [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

class Point
  def coerce(arg)
    [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

など(注:コードはテストされていません)

于 2010-05-11T12:53:09.690 に答える