在ruby中,我在irb中乱搞并发现两个代码样本应该相同但不会
"a" * 4 #this is "aaaa"
4 * "a" #this is "String can't be coerced into a Fixnum"
这是否违反了乘法的交换属性?
答案 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中运算符重载的好文章。
有趣的旁注:交换属性实际上并不适用于数学中的所有数字,Quaterions和Octonions都不是可交换的。
修改强>
如果您愿意,可以让*
运算符进行交换(但这不是一个好主意)。然后,您可以定义*
来交换被调用者和参数,如:
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"
但这只是写同一件事的另一种方式。