假设我已经实现了Vector类。在C ++中,可以进行"缩放"通过在全局范围内重载operator *来实现自然数学表达式:
template <typename T> // T can be int, double, complex<>, etc.
Vector operator*(const T& t, const Vector& v);
template <typename T> // T can be int, double, complex<>, etc.
Vector operator*(const Vector& v, const T& t);
但是,当它转到Ruby时,由于没有输入参数,因此可以编写
class Vector
def *(another)
case another
when Vector then ...
when Numeric then ...
end
end
end
这允许Vector * Numeric,但不允许Numeric * Vector。有办法解决吗?
答案 0 :(得分:2)
[在我的回复中使用Numeric
而不是Numerical
。]
执行此操作的最常用方法是向coerce
添加Vector
方法。当Ruby遇到5 * your_vector
时,对5.*(your_vector)
的调用失败,然后调用your_vector.coerce(5)
。您的coerce
方法会传回两个项目,并会对这些项目重试*
方法。
从概念上讲,5.*(your_vector)
失败后会发生类似的事情:
first, second = your_vector.coerce(5)
first.*(second)
最简单的方法是将your_vector
作为第一项传递回来,将5
作为第二项传递回来。
def coerce(other)
case other
when Numeric
return self, other
else
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
end
end
这适用于可交换操作,但对于非交换操作则不太好。如果你有一个只需要*
工作的简单,自包含的程序,你就可以逃脱它。如果您正在开发库或需要更通用的内容,并且将5
转换为Vector
是有意义的,您可以在coerce
中执行此操作:
def coerce(other)
case other
when Numeric
return Vector.new(other), self
else
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
end
end
如果它具有语义意义,这是一个更强大的解决方案。如果它没有语义意义,您可以创建一个中间类型,您可以将Numeric
转换为知道如何与Vector
相乘的中间类型。这the approach that Matrix
takes。
作为最后的手段,您可以拔出大枪并使用alias_method
在*
上重新定义Numeric
来处理Vector
。我不打算为这种方法添加代码,因为做错会导致灾难,而且我还没有想到任何边缘情况。