2017-02-23 107 views
1

我正在通過Bruce Tate的七週的七種語言,並試圖完成所有練習。有一個Tree練習,用戶只需將初始化程序更改爲接受散列並從中創建樹。我最初的嘗試如下:爲什麼這個ruby代碼不會拋出異常?

def initialize(hash={}) 
    if !hash.keys[0].nil? 
    @node_name = hash.keys[0] 
    @children = [] 
    if !(hash.values[0].nil? or hash.values[0] == {}) 
     hash.values[0].each do |k, v| 
     @children.push(Tree.new({k => v}) 
     end 
    end 
    end 
end 

This works。但是,沒有檢查的代碼也是可行的,例如:

def initialize(hash={}) 
    @node_name = hash.keys[0] 
    @children = [] 
    hash.values[0].each do |k, v| 
    @children.push(Tree.new({k => v}) 
    end 
end 

爲什麼不需要檢查?看起來像我會得到像空引用的東西(我來自.Net背景,所以它可能被稱爲別的在紅寶石)。

這裏是我的全碼:

if !(hash.values[0].nil? or hash.values[0] == {}) 
    hash.values[0].each do |v| 
    k = hash.key(v) 
    @children.push(Tree.new({k => v}) 
    end 
end 

你可以在這種情況下得到異常:

hash = {} 
hash.values  # => [] 
hash.values[0] # => nil 

class Tree 
    attr_accessor :children, :node_name 

    def initialize(hash={}) 
     @node_name = hash.keys[0] 
     @children = [] 
     hash.values[0].each do |k, v| 
     @children.push(Tree.new({k => v}) 
     end 
    end 

    def visit_all(&block) 
    visit &block 
    children.each{|c| c.visit_all &block} 
    end 

    def visit(&block) 
    block.call self 
    end 
end 


ruby_tree = Tree.new({"grampa" => { "dad" => { "son1" => {}, "son2" => {}}, "uncle" => { "nephew1" => {}, "nephew2" => {"youngun1" => {}}}}}) 

puts "Visiting a node" 
ruby_tree.visit {|node| puts node.node_name} 
puts 

puts "visiting entire tree" 
ruby_tree.visit_all {|node| puts node.node_name} 
+0

一件小事:你可以寫'@children = hash.values [0] .map {| k,v | Tree.new(k => v)}'。當Ruby是一個參數時,Ruby允許你寫一個沒有大括號的散列。 –

+0

爲了完整起見,Ruby中沒有空引用。永遠。任何引用將始終是有效的對象。 –

+0

啊。那麼在最壞的情況下,這將是一個Nil對象的NoSuchMerhod? – tjcertified

回答

2

如果從這個代碼中刪除if條件如果你沒有檢查條件就運行each循環,它會失敗因爲each未在nil上定義。

您的第二個條件hash.values[0] == {}可能會被跳過。

這只是一個簡短的截斷,以防止each循環上的空散列作爲循環它將沒有任何效果。

hash = { foo: {} } 
hash.values[0]  # => {} 

現在做{}.each將不會對輸出產生影響。

0

如果您嘗試調用nil上的方法,則只會發生異常 - 那麼您將得到一個NoMethodError。既然你已經通過了有效的哈希,那麼檢查並不重要。如果你明確地傳遞作爲參數nilnew當您創建ruby_tree,你會看到一個NoMethodError

此外,該行

hash.values[0].each do |k, v| 

像您期望的將無法正常工作。調用hash.values會返回一個Array,而Arrays的迭代器只會生成一個到該塊的元素(該元素位於數組中的下一個位置)。相反,你應該使用hash.each do |k, v|

相關問題