Ruby中

时间:2016-03-15 01:32:55

标签: ruby

在ruby中,我在irb中乱搞并发现两个代码样本应该相同但不会

"a" * 4     #this is "aaaa"
4 * "a"     #this is "String can't be coerced into a Fixnum"

这是否违反了乘法的交换属性?

4 个答案:

答案 0 :(得分:3)

它确实违反了交换属性,但这不一定是个问题,因为交换属性适用于数学中复杂的复数。在大多数编程语言中,"a" * 4在Ruby中不可交换的原因是因为给定的类型定义了它如何处理运算符。因此,您可以覆盖*String类的Fixnum运算符(但在实践中这是一个非常糟糕的主意):

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

所以如果你打电话

"a" * 4

然后它会打印"The method was called on an instance of String",因为这相当于"a".*(4)

但是这个:

4 * "a"

会打印"The method was called on an instance of Fixnum",因为4 * "a"等同于4.*("a")

Here是关于Ruby中运算符重载的好文章。

有趣的旁注:交换属性实际上并不适用于数学中的所有数字,QuaterionsOctonions都不是可交换的。

修改

如果您愿意,可以让*运算符进行交换(但这不是一个好主意)。然后,您可以定义*来交换被调用者和参数,如:

class Fixnum
    def *(other)
        other * self
    end
end

这样,当你有4 * "a"时,它实际上会这样做:"a" * 4。即使稍后重新定义String#*,这仍然有效。 Monkey patching通常很有用,但在这种情况下,这是一个糟糕的主意,我不建议这样做,它只是一个很好的概念证明。

答案 1 :(得分:2)

"a" * 4 # repeat 'a' 4 times
4 * "a" # multiply 4 times the string 'a'

除非涉及两个数字,否则不是乘法。

答案 2 :(得分:0)

不,这是优先级的组合,它们都是对象。你在第二版中实际做的是4。*(“a”)。在Fixnum实例上使用参数“a”调用方法'*',值为4.因此字符串“a”不能被强制。

答案 3 :(得分:0)

在Ruby中,一切都是对象。 "a"是类String的对象,而4是类Fixnum的对象。所以偶数也是对象。

对象可以有方法。

4有一个名为*的方法,它将一个数字作为参数,并将4乘以该数字。此方法不接受字符串作为参数;尝试将字符串强制转换为数字会失败。 (这就是解释你的错误信息的原因。)

"a"有一个名为*的完全不同的方法,它以一个数字作为参数。此方法多次重复该字符串。

因此:

4.*(4)    # =>16
"a".*(4)  # => "aaaa"

Ruby还允许您对*方法使用更简洁的语法:

4 * 4     # =>16
"a" * 4   # => "aaaa"

但这只是写同一件事的另一种方式。