第八章 控制流技术
一、条件代码执行
1. if 关键字及相关构造
if condition
end
也可以将整个 if 子句放在一行,为此需要在条件后面插入 then 关键字
if x > 10 then puts x end
也可以使用分号来替代换行
if x > 10; puts x; end
作为 Ruby 一个特殊规则,也可以使用冒号代替 then
if x > 10: puts x; end
2. else:可以在 if 语句中提供一个 else 分支
if condition
else
end
3. elsif:使得条件逻辑可以层叠,形成比 if 和 else 更多的层次
if condition1
elsif condition2
elsif condition3
end
4. unless:有时想使用否定 if 条件:如果某件事不是真的,那么执行给定的代码块
方法一:使用 not 关键字
if not (x == 1)
方法二:使用否定操作符!
if !(x == 1)
方法三:使用 unless
unless x == 1
5. 条件修饰语:可以把条件判断直接放在语句的后面作为修饰语
puts "Big number!" if x > 100
它和下面代码等价
if x > 100
end
也可以使用 unless 来实现
puts "Big number!" unless x <= 100
条件修饰语具有会话的风格。它们不需要使用 end。不能用它们来完成太多的工作(不能带 else 或者 elsif 分支),但是在需要一个简单的条件判断时,它们往往非常合适。
6. case 语句
print "Exit the program? (yes or no): "
answer = gets.chomp
end
when 子句的匹配方法由 ===(三等号操作符)判断,即
if "yes" === answer
elsif "no" === answer
else
end
因此 case/when 逻辑的本质是 object === other_object;而 object === other_object 的本质是 object ===(other_object)。
二、用循环重复动作
1. 用 loop 方法实现无条件循环,下面两段代码是等价的
loop { puts "Looping forever!" }
loop do puts "Looping forever!" end
对循环进行控制(break 停止循环)
n = 1
loop do
end
使用 next 在没有完成本次循环的情况下跳到下一次循环
n = 1
loop do
end
2. 用 while 和 until 关键字实现条件循环
(1)while:在给定条件为真时循环执行代码
n = 1
while n < 11
end
puts "Done!"
也可以把 while 子句放在循环的结束处,这时需要 begin/end 标记循环的头尾
n = 1
begin
end while n < 11
puts "Done!"
(2)until:具有和 while 相同的用法,但是逻辑相反
n = 1
until n > 10
end
(3)while 和 until 作为修饰语
和 if unless 一样,while 和 until 可以在语句的末尾用作修饰语
n = 1
n = n + 1 until n == 10
puts "We've reached 10!"
3. for/in 循环:基于值列表的循环
celsius = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
for c in celsius
end
三、代码块、迭代器和 yield 关键字
1. 代码块:由任意多行 Ruby 代码构成,可以用大括号封装
object.method_name {
}
也可以用 do/end 来封装
object.method_name do
end
2. yield 关键字:如果在调用方法时提供了代码块,那么在该方法执行过程中可以将控制转移到该代码块(暂停方法的执行),执行代码块中的代码,最后再返回该方法继续执行
def demo_of_yield
end
demo_of_yield { puts "> Control has been passed to the block!" }
该代码的输出如下
Executing the method body...
About to yield control to the block...
> Control has been passed to the block!
Back from the block—finished!
3.给代码块传递参数
可以通过 yield 将参数发送到代码
yield(x,y,z)
代码块接受参数的方法,不使用圆括号,而使用一对管道符号(||)
some_method {|a,b,c|
}
示例如下
def yield_an_arg
end
yield_an_arg {|x| puts "> Code block received this argument: #{x}" }
4. 从代码块返回值
def more_yielding
end
more_yielding {|x| x * 10 }
5. 执行多个迭代
迭代:方法匿名调用代码块的过程
迭代器:任何匿名调用代码块的方法
使用代码块来执行温度转换方法
def temp_chart(temps)
end
celsiuses = [0,10,20,30,40,50,60,70,80,90,100]
temp_chart(celsiuses) {|cel| cel * 9 / 5 + 32 }
6. Ruby 的代码块机制意味着:可以使用代码块来补足方法中没有完全定义的行为
我们可以使用同样的方法通过另外的方式转换温度:
fahrens = [32,62,92,122,152,182,212]
temp_chart(fahrens) {|fahr| (fahr - 32) * 5 / 9 }
7. 关于 for 的更多内容
for 的本质就是迭代器:for 是调用一个特殊的迭代器 each 的一种可选方式
下面两段代码是等价的
for x in [1,2,3,4,5]
end
与
[1,2,3,4,5].each {|x| puts x * 10 }
四、错误处理和异常
1. 异常是特殊类型的对象,它是 Exception 类或它的后代类的一个实例,抛出一个异常意味着:停止程序的正常执行,处理碰到的问题或者退出程序
要看看实际中的异常可以试一试:
F:\ruby_project>ruby -e '1./0'
Ruby 抛出一个异常
-e:1:in `/': divided by 0 (ZeroDivisionError)
2. 常见的异常
异常名 | 常见原因 | 怎样抛出 |
RuntimeError | 这是 raise 方法抛出的默认异常 | raise |
NoMethodError | 对象收到一个找不到对应方法的消息 | a = Object.new a.some_unknown_method_name |
NameError | 解释器碰到一个不能解析为变量或方法名的标识符 | a = some_random_identifier |
IOError | 读关闭的流(stream),写只读的流,或类似的操作 | STDIN.puts("Don't write to STDIN!") |
Errno::error | 与文件 IO 相关的一族错误 | File.open(-12) |
TypeError | 方法接收到它不能处理的参数 | a = 3 + "can't add a string to a number!" |
ArgumentError | 传递的参数的数目出错 | def m(x); end; m(1,2,3,4,5) |
3. 用 rescue 块来营救程序异常
print "Enter a number: "
n = gets.to_i
begin
rescue
end
puts "100/#{n} is #{result}."
指定想要营救的异常:rescue ZeroDivisionError
4. 显示抛出异常
可以给 raise 提供第二个参数,作为抛出异常时的消息字符串
def fussy_method(x)
end
fussy_method(20)
也可以在此例中使用 rescue
begin
rescue ArgumentError
end
5. 重新抛出异常
def reraiser(filename)
rescue Errno::ENOENT => e
end
注意:只要 rescue 子句是方法定义体的最后部分,就不喜欢显示地使用 being/end 分隔符;
方法自己扮演了异常块的 end 角色。
此例涉及的主要新技术是那个奇特的 rescue 行。=>e 构造将异常对象放入变量 e 中。
下面对该方法进行调用
reraiser("some_non_existent_filename")
输出以下内容
Something's wrong with your filename....
reraiser.rb:2:in `initialize': No such file
6. 创建异常类:通过从 Exception 或它的后代继承
class MyNewException < Exception
end
raise MyNewException, "some new kind of error has occurred!"
7. 异常及它们在 Rails 框架中的名字
ActiveController 库定义了 UnknownAction,