2016-03-15 71 views
3

的交換律在Ruby中,我在IRB搞亂了一圈,發現兩個代碼示例,應該工作一樣,但不乘法的紅寶石

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

不違反本的交換律乘法?

+7

乘法的交換性質是一個數學原理。 Ruby是一種編程語言。 *運算符不是乘號,它分別是String和Fixnum類的'*'方法的語法糖。它不會「違反」交換屬性,因爲它不受它的束縛,不僅僅是「印刷」方法受英語語法原理的約束。 –

回答

3

它確實違反了交換屬性,但這不一定是個問題,因爲交換屬性適用於數學中複雜的複數。原因"a" * 4在Ruby中不可交換,因爲在大多數編程語言中,是因爲給定的類型定義了它如何處理運算符。所以,你可以覆蓋*運營商爲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 

所以,如果你打電話給

"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通常可能有用,但在這種情況下,這是一個可怕的想法,我不建議這樣做,這只是一個很酷的概念證明。

+2

值得注意的是,這就是所有帶有運算符重載的編程語言的工作原理(至少我知道所有這些語言)。所以這不是Ruby特有的怪癖。並+1適當的深入解釋;-) – Carpetsmoker

0

不,它是一個優先事項和它們都是對象的事實。你在第二個版本中有效地做的是4 *(「a」)。在值爲4的Fixnum實例上調用參數「a」的方法'*'。因此不能強制字符串「a」。

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

除非涉及兩個數字,否則不是乘法。

0

在Ruby中,一切都是一個對象。 "a"String類的對象,而4Fixnum類的對象。所以偶數就是對象。

而對象可以有方法。

4有一個名爲*的方法,它將一個數字作爲參數並將該數字乘以4。此方法不接受字符串作爲參數;它將不會成功地將字符串強制轉換爲數字。 (這就是解釋你的錯誤信息的原因。)

"a"有一個完全不同的方法,稱爲*,它將一個數字作爲參數。該方法多次重複該字符串。

因此:

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

紅寶石,您還可以使用爲*方法更簡潔的語法:

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

但它是寫同樣的事情,只是以不同的方式。