它被认为能够执行 point * 3 。
<code>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
</code>
输出:
<code>#<Point:0x336094 @x=1, @y=2>
#<Point:0x335fa4 @x=3, @y=6>
</code>
但是,
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
上调用。
现在,由于这个方法*
不知道如何将一个点乘以3,所以
point.coerce(3)
将被调用,并返回一个数组:
[point, 3]
然后再次对其应用*
,这是真的吗?
现在,我们已经理解了这一点,我们现在有了一个新的Point
对象,就像Point
类的实例方法*
所执行的那样。
问题是:
谁调用了point.coerce(3)
?是Ruby自动调用的,还是Fixnum
的*
方法内部通过捕获异常来调用的?或者当它不知道一个已知类型时,是否通过case
语句来调用coerce
?
coerce
总是需要返回一个由两个元素组成的数组吗?它可以没有数组吗?或者可以是由三个元素组成的数组吗?
规则是,原始操作符(或方法)*
将在元素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
减去Fixnum
的操作:
point = Point.new(100,100)
point - 20 #=> (80,80)
20 - point #=> (-80,-80)