我正在研究Bruce Tate的<七个七周语言,并尝试进行所有练习。有一个Tree练习,用户在其中更改仅初始化程序以接受哈希并从中创建树。我最初的尝试如下:
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
这很有效。但是,没有检查的代码也有效,即:
def initialize(hash={})
@node_name = hash.keys[0]
@children = []
hash.values[0].each do |k, v|
@children.push(Tree.new({k => v})
end
end
为什么不需要检查?看起来我会得到类似于null引用的东西(我来自.Net背景,所以它可能在ruby中被称为其他东西)。
这是我的完整代码:
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 :(得分:3)
如果您从此代码中删除if
条件:
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
如果您在不检查条件的情况下在其上运行each
循环,则会失败,因为each
上未定义nil
。
您的第二个条件hash.values[0] == {}
可能会被跳过。
这只是一个简短的方法,可以防止空哈希上的each
循环,因为循环对它没有影响。
hash = { foo: {} }
hash.values[0] # => {}
现在执行{}.each
对输出没有任何影响。
答案 1 :(得分:0)
如果您尝试在nil
上调用方法,则只会遇到异常 - 然后您将获得NoMethodError。由于您通过了有效的哈希,因此检查并不重要。如果您在创建nil
时明确地将new
作为参数传递给ruby_tree
,则会看到NoMethodError
此外,该行
hash.values[0].each do |k, v|
按照您的期望赢得了工作。调用hash.values
返回一个数组,而数组的迭代器只产生一个项目到块(数组中下一个位置的元素)。相反,您应该使用hash.each do |k, v|