据说当我们有课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
吗?它已经有很多代码,我们不能只添加几行来增强它(但我们会想要吗?)coerce
类中的Point
非常通用,它可以与*
or一起使用,+
因为它们是可传递的。如果它不具有传递性,例如我们将 Point 减去 Fixnum 定义为:point = Point.new(100,100) point - 20 #=> (80,80) 20 - point #=> (-80,-80)