ruby运算符重载问题
为了娱乐目的,我一直在使用ruby和opengl,我决定写一些3d矢量/平面/等级类来完成一些数学运算。
简化示例:
class Vec3 attr_accessor :x,:y,:z def *(a) if a.is_a?(Numeric) #multiply by scalar return Vec3.new(@x*a, @y*a, @z*a) elsif a.is_a?(Vec3) #dot product return @x*ax + @y*ay + @z*az end end end v1 = Vec3.new(1,1,1) v2 = v1*5 #produces [5,5,5]
这一切都很好,花花公子,但我也想写
v2 = 5*v1
这需要为Fixnum或Float或其他任何东西添加function,但我找不到重载或扩展fixnum的乘法而不完全替换它的方法。 ruby有可能吗? 有小费吗?
(显然,如果我需要的话,我可以按正确的顺序写下我的所有乘法)
使用强制是一种比猴子修补核心类更好的方法:
class Vec3 attr_accessor :x,:y,:z def *(a) if a.is_a?(Numeric) #multiply by scalar return Vec3.new(@x*a, @y*a, @z*a) elsif a.is_a?(Vec3) #dot product return @x*ax + @y*ay + @z*az end end def coerce(other) return self, other end end
如果你将v定义为v = Vec3.new
则以下内容将起作用: v * 5
和5 * v
coerce(self)返回的第一个元素成为操作的新接收者,第二个元素(other)成为参数,所以5 * v
完全等同于v * 5
我相信以下会做你想要的,虽然banister的建议使用coerce
而不是猴子修补Numeric
是一种首选的方法。 仅在必要时使用此方法(例如,如果您只希望某些二进制操作数是可传递的)。
Fixnum.class_eval do original_times = instance_method(:*) define_method(:*) do |other| if other.kind_of?(Vec3) return other * self else return original_times.bind(self).call(other) end end end