Ruby 中乘法的交换性质

Mic*_*ael 5 ruby

在 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)

这不违反乘法的交换性质吗?

Add*_*son 4

它确实违反了交换律,但这不一定是问题,因为交换律适用于数学中的复数。"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#*后来重新定义,这仍然有效。猴子补丁通常很有用,但在这种情况下这是一个糟糕的主意,我不建议这样做,这只是一个很酷的概念证明。

  • 值得注意的是,这就是所有具有运算符重载的编程语言的工作方式(至少是我所知道的所有语言)。所以这不是 Ruby 特有的怪癖。并+1以获得适当的深入解释;-) (2认同)