在 ruby 中,我在 irb 中乱搞,发现两个代码示例应该工作相同但不
"a" * 4 #this is "aaaa"
4 * "a" #this is "String can't be coerced into a Fixnum"
Run Code Online (Sandbox Code Playgroud)
这不违反乘法的交换性质吗?
它确实违反了交换律,但这不一定是问题,因为交换律适用于数学中的复数。"a" * 4与大多数编程语言一样,Ruby 中的原因是不可交换的,因为给定的类型定义了它如何处理运算符。因此,您可以覆盖and类*的运算符(但这在实践中是一个非常非常糟糕的主意):StringFixnum
class String
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of String"
end
end
end
class Fixnum
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of Fixnum"
end
end
end
Run Code Online (Sandbox Code Playgroud)
所以如果你打电话
"a" * 4
Run Code Online (Sandbox Code Playgroud)
然后它会打印,"The method was called on an instance of String"因为这相当于"a".*(4)
但是这个:
4 * "a"
Run Code Online (Sandbox Code Playgroud)
会打印,"The method was called on an instance of Fixnum"因为4 * "a"相当于4.*("a")
这是一篇关于 Ruby 中运算符重载的好文章。
有趣的旁注:交换律实际上并不适用于数学中的所有数字,四元数和八元数都不可交换。
编辑
如果您愿意,您可以使*运算符可交换(但这将是一个坏主意)。然后,您可以定义*交换被调用者和参数,如下所示:
class Fixnum
def *(other)
other * self
end
end
Run Code Online (Sandbox Code Playgroud)
这样,当你拥有4 * "a"它时,它实际上会执行以下操作:"a" * 4。即使String#*后来重新定义,这仍然有效。猴子补丁通常很有用,但在这种情况下这是一个糟糕的主意,我不建议这样做,这只是一个很酷的概念证明。