Ruby 使用多个参数重载运算符
Ruby overloading operators with severals parameters
我有一个 class MoneyBox,它有两个字段(钱包和美分)。我需要用这些字段重载操作 +、- 和 *。如何正确实现这些带两个参数的运算符的重载?
class MoneyBox
attr_accessor :wallet, :cent
def initialize(wallet, cent)
@wallet = wallet
@cent = cent
end
def + (obj, obj_cent)
self.wallet = self.wallet + obj.wallet
self.cent = self.cent + obj_cent.cent
return self.wallet, self.cent
end
def - (obj, obj_cent)
self.wallet = self.wallet - obj.wallet
self.cent = self.cent - obj_cent.cent
return self.wallet, self.cent
end
def * (obj,obj_cent)
self.wallet = self.wallet * obj.wallet
self.cent = self.cent * obj_cent
return self.wallet, self.cent
end
end
应该是这样的:
Cash1 = MoneyBox.new(500, 30)
Cash2 = MoneyBox.new(100, 15)
puts " D1 = #{D1 = (Cash1-(Cash2*2))}" # 500,30 - 100,15*2 = 300,0
如果要重载运算符以接受两个参数,则不能使用典型的 x + y
语法。
相反,您必须使用 .+
,请参阅以下内容:
class Foo
def initialize(val)
@val = val
end
def +(a,b)
@val + a + b
end
end
foo = Foo.new(1)
foo.+(2,3)
# => 6
您的示例用法与方法定义不匹配。您想以编写表达式的方式使用您的对象,例如 Cash2 * 2
)。由于 Cash2
是 class MoneyBox 的常量,因此标量乘法的定义类似于
def * (factor)
self.class.new(wallet, cent * factor)
end
这是
的快捷方式
def * (factor)
MoneyBox.new(self.wallet, self.cent * factor)
end
您已经有一个 class 封装了钱包/美分对,并且操作也是成对执行的。为什么不利用它并使 +
、-
和 *
将(单个)MoneyBox
实例作为它们的参数,并将 return 结果作为另一个 MoneyBox
实例,例如:(算术运算符不应修改其操作数)
class MoneyBox
attr_accessor :wallet, :cent
def initialize(wallet, cent)
@wallet = wallet
@cent = cent
end
def +(other)
MoneyBox.new(wallet + other.wallet, cent + other.cent)
end
def -(other)
MoneyBox.new(wallet - other.wallet, cent - other.cent)
end
def *(other)
MoneyBox.new(wallet * other.wallet, cent * other.cent)
end
def to_s
"#{wallet},#{cent}"
end
end
用法示例:
cash1 = MoneyBox.new(500, 30)
cash2 = MoneyBox.new(100, 15)
puts "#{cash1} + #{cash2} = #{cash1 + cash2}"
# 500,30 + 100,15 = 600,45
puts "#{cash1} - #{cash2} = #{cash1 - cash2}"
# 500,30 - 100,15 = 400,15
puts "#{cash1} * #{cash2} = #{cash1 * cash2}"
# 500,30 * 100,15 = 50000,45
要将 wallet
和 cents
都乘以 2,您需要使用 MoneyBox.new(2, 2)
实例:
puts "#{cash1} - #{cash2} * 2 = #{cash1 - cash2 * MoneyBox.new(2, 2)}"
# 500,30 - 100,15 * 2 = 300,0
请注意运算符 precedence 仍然适用,因此结果计算为 cash1 - (cash2 * Money.new(2, 2))
。
如果您想直接乘以整数,即不显式创建 MoneyBox.new(2, 2)
实例,您可以通过添加条件将逻辑移至 *
,例如:
def *(other)
case other
when Integer
MoneyBox.new(wallet * other, cent * other)
when MoneyBox
MoneyBox.new(wallet * other.wallet, cent * other.cent)
else
raise ArgumentError, "expected Integer or MoneyBox, got #{other.class}"
end
end
这给你:
cash1 = MoneyBox.new(500, 30)
cash2 = MoneyBox.new(100, 15)
puts "#{cash1} - #{cash2} * 2 = #{cash1 - cash2 * 2}"
# 500,30 - 100,15 * 2 = 300,0
请注意,这仅定义 MoneyBox#*
而不会更改 Integer#*
,因此 2 * cash2
默认情况下 不 有效:
2 * cash2
# TypeError: MoneyBox can't be coerced into Integer
那是因为您在 2
上调用 *
,而 Integer
不知道如何处理 MoneyBox
实例。这可以通过在 MoneyBox
中实施 coerce
来解决:(仅适用于数字的东西)
def coerce(other)
[self, other]
end
这有效地将 2 * cash2
变成了 cash2 * 2
。
顺便说一句,如果你总是用一个整数调用 *
并且不需要实际乘以两个 MoneyBox
实例,它当然会变得更简单:
def *(factor)
MoneyBox.new(wallet * factor, cent * factor)
end
我有一个 class MoneyBox,它有两个字段(钱包和美分)。我需要用这些字段重载操作 +、- 和 *。如何正确实现这些带两个参数的运算符的重载?
class MoneyBox
attr_accessor :wallet, :cent
def initialize(wallet, cent)
@wallet = wallet
@cent = cent
end
def + (obj, obj_cent)
self.wallet = self.wallet + obj.wallet
self.cent = self.cent + obj_cent.cent
return self.wallet, self.cent
end
def - (obj, obj_cent)
self.wallet = self.wallet - obj.wallet
self.cent = self.cent - obj_cent.cent
return self.wallet, self.cent
end
def * (obj,obj_cent)
self.wallet = self.wallet * obj.wallet
self.cent = self.cent * obj_cent
return self.wallet, self.cent
end
end
应该是这样的:
Cash1 = MoneyBox.new(500, 30)
Cash2 = MoneyBox.new(100, 15)
puts " D1 = #{D1 = (Cash1-(Cash2*2))}" # 500,30 - 100,15*2 = 300,0
如果要重载运算符以接受两个参数,则不能使用典型的 x + y
语法。
相反,您必须使用 .+
,请参阅以下内容:
class Foo
def initialize(val)
@val = val
end
def +(a,b)
@val + a + b
end
end
foo = Foo.new(1)
foo.+(2,3)
# => 6
您的示例用法与方法定义不匹配。您想以编写表达式的方式使用您的对象,例如 Cash2 * 2
)。由于 Cash2
是 class MoneyBox 的常量,因此标量乘法的定义类似于
def * (factor)
self.class.new(wallet, cent * factor)
end
这是
的快捷方式def * (factor)
MoneyBox.new(self.wallet, self.cent * factor)
end
您已经有一个 class 封装了钱包/美分对,并且操作也是成对执行的。为什么不利用它并使 +
、-
和 *
将(单个)MoneyBox
实例作为它们的参数,并将 return 结果作为另一个 MoneyBox
实例,例如:(算术运算符不应修改其操作数)
class MoneyBox
attr_accessor :wallet, :cent
def initialize(wallet, cent)
@wallet = wallet
@cent = cent
end
def +(other)
MoneyBox.new(wallet + other.wallet, cent + other.cent)
end
def -(other)
MoneyBox.new(wallet - other.wallet, cent - other.cent)
end
def *(other)
MoneyBox.new(wallet * other.wallet, cent * other.cent)
end
def to_s
"#{wallet},#{cent}"
end
end
用法示例:
cash1 = MoneyBox.new(500, 30)
cash2 = MoneyBox.new(100, 15)
puts "#{cash1} + #{cash2} = #{cash1 + cash2}"
# 500,30 + 100,15 = 600,45
puts "#{cash1} - #{cash2} = #{cash1 - cash2}"
# 500,30 - 100,15 = 400,15
puts "#{cash1} * #{cash2} = #{cash1 * cash2}"
# 500,30 * 100,15 = 50000,45
要将 wallet
和 cents
都乘以 2,您需要使用 MoneyBox.new(2, 2)
实例:
puts "#{cash1} - #{cash2} * 2 = #{cash1 - cash2 * MoneyBox.new(2, 2)}"
# 500,30 - 100,15 * 2 = 300,0
请注意运算符 precedence 仍然适用,因此结果计算为 cash1 - (cash2 * Money.new(2, 2))
。
如果您想直接乘以整数,即不显式创建 MoneyBox.new(2, 2)
实例,您可以通过添加条件将逻辑移至 *
,例如:
def *(other)
case other
when Integer
MoneyBox.new(wallet * other, cent * other)
when MoneyBox
MoneyBox.new(wallet * other.wallet, cent * other.cent)
else
raise ArgumentError, "expected Integer or MoneyBox, got #{other.class}"
end
end
这给你:
cash1 = MoneyBox.new(500, 30)
cash2 = MoneyBox.new(100, 15)
puts "#{cash1} - #{cash2} * 2 = #{cash1 - cash2 * 2}"
# 500,30 - 100,15 * 2 = 300,0
请注意,这仅定义 MoneyBox#*
而不会更改 Integer#*
,因此 2 * cash2
默认情况下 不 有效:
2 * cash2
# TypeError: MoneyBox can't be coerced into Integer
那是因为您在 2
上调用 *
,而 Integer
不知道如何处理 MoneyBox
实例。这可以通过在 MoneyBox
中实施 coerce
来解决:(仅适用于数字的东西)
def coerce(other)
[self, other]
end
这有效地将 2 * cash2
变成了 cash2 * 2
。
顺便说一句,如果你总是用一个整数调用 *
并且不需要实际乘以两个 MoneyBox
实例,它当然会变得更简单:
def *(factor)
MoneyBox.new(wallet * factor, cent * factor)
end