七周七语言自习——Ruby第二天

原创
2014/02/02 21:42
阅读数 523

第二天的主要内容包括定义函数、数组和散列表、代码块和yield、类的定义和Mixin。

Ruby允许在类外定义函数,和Ruby中的其他一切一样,函数也是对象。数组和散列表提供了丰富的API,可以在各种场合使用。代码块(block)和yield是最具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" => {}
      }
  }
}

原文中的类是这样的:

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

由于下面访问方法中代码块中调用的格式为数组的调用方法,所以显然必须得将输入的散列表转化为数组,这就要每次递归调用初始化函数。改写之后的方法如下:

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 ...

可以将文件、行号、所在行内容都显示出来

展开阅读全文
加载中
点击加入讨论🔥(2) 发布并加入讨论🔥
2 评论
9 收藏
1
分享
返回顶部
顶部