Float在Ruby中乘以Vector

时间:2014-09-01 23:52:02

标签: ruby

假设我已经实现了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。有办法解决吗?

1 个答案:

答案 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。我不打算为这种方法添加代码,因为做错会导致灾难,而且我还没有想到任何边缘情况。