2017-02-23 110 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|

相关问题