次日的主要内容包括定义函数、数组和散列表、代码块和yield、类的定义和Mixin。node
Ruby容许在类外定义函数,和Ruby中的其余一切同样,函数也是对象。数组和散列表提供了丰富的API,能够在各类场合使用。代码块(block)和yield是最具Ruby风格的闭包方式。Ruby的类使用单继承,能够使用模块的方式集成其余方法。数组
练习ruby
1.有一个数组,包含16个数字,仅用each方法打印数组中的内容,一次打印4个数字。而后用可枚举模块的each_slice方法重作一遍。 闭包
仅用each这种表述可能有歧义,好像必须得使用条件语句才能实现。函数
A = (1..16).to_a #使用each i = 1 A.each do |a| if i % 4 == 0 puts a else print "#{a} " end i += 1 end #使用each_slice A.each_slice(4) do |g| puts g.join(" ") end
2.前面书中实现了一个有趣的树类Tree,有着简洁的用户接口,如今要改写一个新的初始化方法,接受散列表和数组嵌套的结构。写好后你能够接受这样的树:测试
{ "grandpa" => { "dad" => { "child1" => {}, "child2" => {} }, "uncle" => { "child3" => {}, "child4" => {} } } }
原文中的类是这样的:spa
class Tree attr_accessor :children, :node_name def initialize(name, children=[]) @children = children @node_name = name end def visit_all(&block) visit &block children.each { |c| c.visit_all &block } end def visit(&block) block.call self end end
因为下面访问方法中代码块中调用的格式为数组的调用方法,因此显然必须得将输入的散列表转化为数组,这就要每次递归调用初始化函数。改写以后的方法以下:code
class Tree attr_accessor :children, :node_name def initialize(tree={}) @node_name = tree.keys()[0] @children = [] tree[@node_name].each do |key, value| @children.push( Tree.new( { key => value } ) ) end end def visit_all(&block) visit &block children.each { |c| c.visit_all &block } end def visit(&block) block.call self end end
测试用的代码:对象
load 'Tree.rb' tree = Tree.new( { "grandpa" => { "dad" => { "child1" => {}, "child2" => {} }, "uncle" => { "child3" => {}, "child4" => {} } } } ) puts "Visiting a node" tree.visit { |node| puts node.node_name } puts puts "Visiting entire tree" tree.visit_all { |node| puts node.node_name }
我的感受用散列表初始化不如保持散列表的格式,改写访问方法。继承
3.写一个简单的grep程序。
拖Ruby超强大的ARGF的福,这个实现起来易如反掌,两行:
tar = ARGV.shift ARGF.each_with_index { |l, i| puts "#{ARGF.filename} #{i} : #{l}" if /#{tar}/.match(l) }
运行的时候使用
ruby grep.rb tar file1 file2 ...
能够将文件、行号、所在行内容都显示出来