據說,當我們有一個類Point
,並且知道如何像下面的執行point * 3
:在Ruby中,coerce()實際上是如何工作的?
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
不瞭解:
Point
不能被強迫Fixnum
(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
並在對象3
上調用。現在
,因爲這種方法*
不知道怎麼乘一個點,所以
point.coerce(3)
將被調用,並取回一個數組:
[point, 3]
然後*
是一次再次申請它,這是真的嗎?
現在,可以理解,我們現在有一個新的Point
對象,如Point
類的實例方法*
所執行的。
的問題是:
誰調用
point.coerce(3)
?它是自動的Ruby,還是方法Fixnum
捕捉異常內的一些代碼?或者是通過case
聲明,當它不知道其中一種已知類型時,則請致電coerce
?請問
coerce
總是需要返回2個元素的數組嗎?它可以不是陣列嗎?或者它可以是3個元素的數組?而原則運算符(或方法)
*
然後將在元素0上調用元素1的參數? (元素0和元素1是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
所以這是真的很難添加一些
Fixnum
的實例方法coerce
?它已經有很多在它的代碼,我們不能只是添加幾行,以增強它(但我們會永遠想?)在
Point
類coerce
是非常通用的,它與*
工作或+
,因爲它們是傳遞性的。如果不可傳遞的,比如如果我們定義點減Fixnum對象是什麼:point = Point.new(100,100) point - 20 #=> (80,80) 20 - point #=> (-80,-80)
這是一個很好的問題!我很高興我找到了它,因爲這一直困擾着我,直到現在,我不認爲它是可以解決的! – sandstrom 2011-10-06 17:49:40
一個很好的問題。感謝您的推薦。我敢肯定,這將節省很多工程師的困惑時間。 – VaidAbhishek 2012-10-09 22:04:47