EasyTime - Ruby学习笔记
自我介绍
切换风格
订阅我的Blog
博客日历
文章归档...
最新发表...
博客统计...
网站链接...
资源
===========================================================
第七章 表达式(4-3)
===========================================================

第七章 表达式(4-3)

Case 表达式

Ruby case 表达式非常强大,就像多个if的固化物一样。它有两种风格。


第一种风格特别像多个if语句:它让你列出一些条件并执行第一个条件为true的语句。例如,闰年必须可被400除,或可被4除而不可被100除。

leap = case

when year % 400 == 0: true

when year % 100 == 0: false

else year % 4 == 0

end

第二种风格的case语句或许更常用。你在case语句的顶部指定一个目标,然后每个when子句列出一或多个比较。

case input_line

when "debug"

dump_debug_info

dump_symbols

when /ps+(w+)/

dump_variable($1)

when "quit", "exit"

exit

else

print "Illegal command: #{input_line}"

end

if一样,case返回最后执行的语句的结果,如果你的条件和后面的语句都在一行,你也需要加一个then关键字。

kind = case year

when 1850..1889 then "Blues"

when 1890..1909 then "Ragtime"

when 1910..1929 then "New Orleans Jazz"

when 1930..1939 then "Swing"

when 1940..1950 then "Bebop"

else "Jazz"

end

if语句,你也可以使用冒号:来代替then关键字。

kind = case year

when 1850..1889 : "Blues"

when 1890..1909 : "Ragtime"

when 1910..1929 : "New Orleans Jazz"

when 1930..1939 : "Swing"

when 1940..1950 : "Bebop"

else "Jazz"

end

case操作数用when关键字后面的比较表达式与目标(关键字case后面的表达式)进行比较。这个测试使用comparison===target。只有一个类定义了===语义(所有内建类都定义了===),那个类的对象就可以被用在case表达式中。

例如,正则表达式定义===为简单的模式匹配。

case line

when /title=(.*)/

puts "Title is #$1"

when /track=(.*)/

puts "Track is #$1"

when /artist=(.*)/

puts "Artist is #$1"

end

Ruby类是类Class的实例,它的定义===用来测试参数是不是类或它的超类的一个实例。所以(abandoning the benefits of polymorphism and bringing the gods of refactoring down around your ears), 你可以测试对象的类。

case shape

when Square, Rectangle

# ...

when Circle

# ...

when Triangle

# ...

else

# ...

end

循环

不要告诉他人,Ruby支持原始的灵巧的内建循环结构。

while循环根据它的条件的真假来执行0次或者多次语句,比如,下面程序将一直运行,直到输入被打断。

while line = gets

# ...

end

util循环与之相反;知道条件为真,才停止操作。

until play_list.duration > 60

play_list.add(song_list.pop)

end

ifunless一样,whileuntil也可以用作语句修饰句。

a = 1

a *= 2 while a < 100

a -=10 until a < 100

a => 98

89页的布尔表达式一节中,我们说过range也可以作为布尔表达式,当一些事件发生时返回true然后保持这个true直到下一个事件发生。这个机制多用于循环中,在下面的例子中,我们从一个包含从firsttenth的数字的文本文件中读取数据,但是只打印从以third开头的行,直到遇到fifth开头的行为止。

file = File.open("ordinal")

while line = file.gets

puts(line) if line =~ /third/ .. line =~ /fifth/

end

produces:

third

fourth

fifth

你可以看到用Perl写上面例子时两者的轻微差别。

file = File.open("ordinal")

while file.gets

print if ~/third/ .. ~/fifth/

end

produces:

third

fourth

fifth

这儿有些隐藏在背后的行为:gets将读入的最后行赋值给全局变量$_~操作符完成与$_的正则表达式的匹配操作,然后不带参数的print打印$_。这种代码是Ruby社区的公认风格。

布尔表达式中的range元素本身也可以是个表达式。它们在布尔表达式每次被计算时都会被求值。例如,下面代码使用了变量$.来包含当前输入的行数,并显示在/eig//nin/之间的行号一到三。

File.foreach("ordinal") do |line|

if (($. == 1) || line =~ /eig/) .. (($. == 3) || line =~ /nin/)

print line

end

end

produces:

first

second

third

eighth

ninth

这里有一点需要注意,当whileuntil用作语句修饰句的时候,如果它们修饰的语句以begin开头,end结尾的块,块内这段代码将总会执行,而不管后面的条件。

print "Hellon" while false

begin

print "Goodbyen"

end while false

produces:

Goodbye

迭代器

如果你读了前面几节,你可能会有些灰心。”Ruby有基本的内建循环结构,它说。不要失望,亲爱的读者,这是个好消息。Ruby不需要任何内建循环,因为所有的东西都由Ruby的迭代器实现。

例如,Ruby没有for循环,至少没有CC++Java的那种。代替的是,Ruby使用定义在各种内建类中定义的方法,它们提供相同的功能,而且更少有错误。

让我们看看一个例子:

3.times do

print "Ho! "

end

produces:

Ho! Ho! Ho!

这可以轻易地避免off-by-one 错误;这个循环将执行3次。除了times,整数可以调用downto,和upto在指定范围内循环,还可使用step循环所有数字。例如,传统的从09的循环(类似i=0; i < 10; i++)可写成下面这样:

0.upto(9) do |x|

print x, " "

end

produces:

0 1 2 3 4 5 6 7 8 9

一个从012,步长为3的循环如下:

0.step(12, 3) {|x| print x, " " }

produces:

0 3 6 9 12

用于数组和其它容器的迭代的each方法也可以用来循环。

[ 1, 1, 2, 3, 5 ].each {|val| print val, " " }

produces:

1 1 2 3 5

如果一个类支持了each方法,那么在模块Enumerable(文档在433页,总结在113-113)中的方法也可以直接使用。比如,File类提供了each方法,依次返回一个文件的每一行。使用Enumerable中的grep方法,我们可以只迭代符合条件的行。

File.open("ordinal").grep(/d$/) do |line|

puts line

end

produces:

second

third

最后也是最简单的,Ruby提供了一个内建的最基本的迭代器loop

loop {

# block ...

}

loop迭代器一直调用给定的block(或者你调用了break跳出循环,后面会讲到)。

For ... In

前面我们说道Ruby支持的最基本循环是whileuntil,而for指的什么呢?for几乎只是一块语法糖。当你这样写时

for song in songlist

song.play

end

Ruby将会把它翻译为如下:

songlist.each do |song|

song.play

end

for循环和each形式的唯一区别是它们体内定义的局部变量的作用域。这个讨论在99页。

你可以在支持each的类上使用for方法进行迭代,比如Array或者Range

for i in ['fee', 'fi', 'fo', 'fum']

print i, " "

end

for i in 1..3

print i, " "

end

for i in File.open("ordinal").find_all {|line| line =~ /d$/}

print i.chomp, " "

end

produces:

fee fi fo fum 1 2 3 second third

一旦你的类支持了each方法,你就可以使用for来进行遍历。

class Periods

def each

yield "Classical"

yield "Jazz"

yield "Rock"

end

end

periods = Periods.new

for genre in periods

print genre, " "

end

produces:

Classical Jazz Rock

my4java 发表于:2006.04.03 16:58 ::分类: ( Ruby Programmer 2nd ) ::阅读:(857次) :: 评论 (0) :: 引用 (0)

发表评论
标题

在此添加评论

称呼

邮箱地址(可选)

个人主页(可选)

authimage