61

クラスがあり、次のようPointに実行する方法を知っていると言われています。point * 3

class Point
  def initialize(x,y)
    @x, @y = x, y
  end

  def *(c)
    Point.new(@x * c, @y * c)
  end
end

point = Point.new(1,2)
p point
p point * 3

出力:

#<Point:0x336094 @x=1, @y=2>
#<Point:0x335fa4 @x=3, @y=6>

しかしその後、

3 * point

理解されていません:

PointFixnum( TypeError)に強制することはできません

したがって、インスタンス メソッドをさらに定義する必要がありますcoerce

class Point
  def coerce(something)
    [self, something]
  end
end

p 3 * point

出力:

#<Point:0x3c45a88 @x=3, @y=6>

3 * pointだから と同じだと言われてい3.*(point)ます。つまり、インスタンス メソッド*は引数を取りpoint、 object を呼び出します3

さて、このメソッド*は点を掛ける方法がわからないので、

point.coerce(3)

が呼び出され、配列が返されます。

[point, 3]

そして*もう一度それに適用されます、それは本当ですか?

これで、これが理解され、クラスPointのインスタンス メソッドによって実行されるように、新しいオブジェクトが作成されました。*Point

質問は:

  1. 誰が呼び出すのpoint.coerce(3)ですか?それは自動的にRubyですか、それとも例外をキャッチしての*メソッド内のコードですか? Fixnumそれともcase、既知のタイプのいずれかがわからない場合に呼び出すステートメントによるものcoerceですか?

  2. coerce常に 2 つの要素の配列を返す必要がありますか? 配列ではありませんか?それとも、3要素の配列にすることができますか?

  3. そして、要素 1 の引数を使用して、元の演算子 (またはメソッド)*が要素 0 で呼び出されるという規則はありますか? (要素 0 と要素 1 は、 によって返される配列内の 2 つの要素coerceです。) 誰がそれをしますか? それはRubyによって行われますか、それともコードで行われますFixnumか? のコードで行うFixnum場合、強制を行うときに誰もが従うのは「慣例」ですか?

    したがって、次のようなこと*を行うコードである可能性があります。Fixnum

    class Fixnum
      def *(something)
        if (something.is_a? ...)
        else if ...  # other type / class
        else if ...  # other type / class
        else
        # it is not a type / class I know
          array = something.coerce(self)
          return array[0].*(array[1])   # or just return array[0] * array[1]
        end
      end
    end
    
  4. Fixnumでは、インスタンス メソッドに何かを追加するのは本当に難しいのcoerceでしょうか。すでに多くのコードが含まれており、数行を追加して機能を強化することはできません (ただし、そうしたいことはありますか?)

  5. coerceクラス内のはPoint非常に一般的であり、*または+それらが推移的であるために機能します。Point から Fixnum を引いたものを次のように定義した場合など、推移的でない場合はどうなるでしょうか。

    point = Point.new(100,100)
    point - 20  #=> (80,80)
    20 - point  #=> (-80,-80)
    
4

2 に答える 2

42

簡単な答え:方法Matrixを確認してください。

ここで、は基本的に同等のオブジェクトですが、クラスで操作を行う方法を知っていcoerceます。ライブラリでは、任意のオブジェクトからを構築し、そのクラスはおよびに対して操作を実行する方法を知っています。[equivalent_something, equivalent_self]equivalent_somethingsomethingPointMatrixMatrix::ScalarNumericMatrixVector

ポイントに対処するには:

  1. はい、直接 Ruby です (rb_num_coerce_binソース内の呼び出しを確認してください)。たとえば、Point#*認識できない引数が渡された場合、を呼び出して、その引数をcoerce自分自身に問い合わせます。Pointarg.coerce(self)

  2. はい、2 つの要素の配列でなければなりません。b_equiv, a_equiv = a.coerce(b)

  3. はい。Ruby は組み込み型に対してそれを行います。拡張可能にしたい場合は、独自のカスタム型に対しても行う必要があります。

    def *(arg)
      if (arg is not recognized)
        self_equiv, arg_equiv = arg.coerce(self)
        self_equiv * arg_equiv
      end
    end
    
  4. アイデアは、変更してはならないということですFixnum#*。引数が であるなどの理由で何をすべきかわからない場合は、Pointを呼び出して尋ねますPoint#coerce

  5. 演算子は常に正しい順序で呼び出されるため、推移性 (または実際には交換性) は必要ありません。coerce受信した引数を一時的に元に戻すのは呼び出しだけです。+、などの演算子の可換性を保証する組み込みのメカニズムはありません==...

誰かが公式ドキュメントを改善するための簡潔で正確かつ明確な説明を思い付くことができる場合は、コメントを残してください!

于 2010-05-10T01:38:31.420 に答える