2013-07-25 106 views
1

這是一個紅寶石僧侶的練習,我無法圍繞一個特定的概念包裹我的頭。爲什麼變量=變量+1工作?

例如,"soup bowl" = "soup bowl" + 1將無效,那麼爲什麼@dishes_needed[a] = (@dishes_needed[a] || 0) + 1在下面的代碼中工作?是因爲它們是變量而不是對象?如果是這樣,爲什麼不代碼a = (a||0)+1工作時,我最初設置a = "Soup"

class Dish 
end 

class Soup < Dish 
end 
class IceCream < Dish 
end 
class ChineseGreenBeans < Dish 
end 

class DeliveryTray 
    DISH_BOWL_MAPPING = { 
    Soup => "soup bowl", 
    IceCream => "ice cream bowl", 
    ChineseGreenBeans => "serving plate" 
    } 

    def initialize 
    @dishes_needed = {} 
    end 

    def add(dish) 
    a = DISH_BOWL_MAPPING[dish.class] 
    @dishes_needed[a] = (@dishes_needed[a] || 0) + 1 
    end 

    def dishes_needed 
     return "None." if @dishes_needed.empty? 

     @dishes_needed.map { |dish, count| "#{count} #{dish}"}.join(", ") 
    end 
end 

d = DeliveryTray.new 
d.add Soup.new; d.add Soup.new 
d.add IceCream.new 

puts d.dishes_needed # should be "2 soup bowl, 1 ice cream bowl" 
+1

等號的RHS評估爲值,LHS評估爲可變參考 – texasbruce

回答

3

讓我們簡化@dishes_needed一部分,所以你可以理解的核心概念。 @dishes_needed是一個散列,@dishes_needed[a] = (@dishes_needed[a] || 0) + 1向散列添加一個鍵值對。

這是查看代碼更簡單的方法。這裏是DISH_BOWL_MAPPING哈希:

DISH_BOWL_MAPPING = { 
    Soup => "soup bowl", 
    IceCream => "ice cream bowl", 
    ChineseGreenBeans => "serving plate" 
    } 

DISH_BOWL_MAPPING哈希獲取某一個元素:

>> DISH_BOWL_MAPPING[Soup] 
=> "soup bowl" 

@dishes_needed是一個空哈希:

>> @dishes_needed = {} 
=> {} 

如果a = Soup,然後在這裏是怎麼了有問題的代碼行:

>> a = Soup 
=> Soup 
>> @dishes_needed[a] = (@dishes_needed[a] || 0) + 1 
=> 1 
>> @dishes_needed 
=> {Soup=>1} 

讓我們分解這是混亂的等式的右邊:

>> (@dishes_needed[a] || 0) + 1 
>> (@dishes_needed[Soup] || 0) + 1 
# @dishes_needed[Soup] is nil because Soup hasn't been added to the hash yet 
>> (nil || 0) + 1 
# nil || 0 evaluates to 0 because nil and false are falsey in Ruby 
>> (0) + 1 
>> 1 

隨後打電話@dishes_needed[Soup]計算爲1,現在的哈希已更新:

>> @dishes_needed[Soup] 
=> 1 

此說,鍵(湯)等於值加1(在這種情況下,該值尚未建立,所以它導致1)。

如果a = "Soup"那麼a = (a||0)+1的計算結果爲a = "Soup" + 1,您不能在Ruby中添加整數和字符串。如果將1轉換爲字符串,則表達式正確計算。

a = (a||0)+1.to_s 
1

在此代碼:

a = DISH_BOWL_MAPPING[dish.class] 
@dishes_needed[a] = (@dishes_needed[a] || 0) + 1 

a要麼將​​是從DISH_BOWL_MAPPING散列或nil的值之一的字符串,如果該鍵是不存在。如果是nil,那麼@dishes_needed[a]也將爲零,這使得(@dishes_needed[a] || 0)評估爲0,然後您將1添加到。這裏的關鍵概念是Hash#[]返回nil如果找不到密鑰(除非您已將默認設置爲別的,您不在這裏)。顯然,這裏的淨效應是,如果它已經存在,則增加@dishes_needed[a];如果它尚不存在,則將其設置爲1

對比,與:

a = "Soup" 
a = (a||0)+1 

這裏,a總是開始爲"Soup",所以(a||0)總是"Soup",你不能添加到1

2

我們不能將事物分成紅寶石變量和對象。這裏的一切都是一個對象。

關於你的代碼唯一需要理解的是+方法(是它的一個方法)將不會與字符串對象一起工作,因爲你正在嘗試這兩種情況。它在這種情況下起作用,因爲如果對象是NILL,則使用Fixnum對象0和+方法對Fixnum進行初始化。

希望我回答你。如果需要更多的澄清,請詢問。