据说,当我们有一个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
不理解:
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
是非常通用的,它与*
或+
一起使用,因为它们是可传递的.如果它不是可传递的,比如我们定义Point减go Fixnum为:point = Point.new(100,100) point - 20 #=> (80,80) 20 - point #=> (-80,-80)