Ruby for Rails 最佳实践Ⅷ

第八章 控制流技术

一、条件代码执行

1. if 关键字及相关构造

if condition

  # code here, executed if condition uates to true

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

  # code executed if condition is true

else

  # code executed if condition is false

end

 

3. elsif:使得条件逻辑可以层叠,形成比 if 和 else 更多的层次

if condition1

  # code executed if condition1 is true

elsif condition2

  # code executed if condition1 is false

  # and condition2 is true

elsif condition3

  # code executed if neither condition1

  # nor condition2 is true, but condition3 is

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

  puts "Big number!"

end

也可以使用 unless 来实现

puts "Big number!" unless x <= 100

条件修饰语具有会话的风格。它们不需要使用 end。不能用它们来完成太多的工作(不能带 else 或者 elsif 分支),但是在需要一个简单的条件判断时,它们往往非常合适。

 

6. case 语句

print "Exit the program? (yes or no): "

answer = gets.chomp

         case answer

         when "yes"

           puts "Good-bye!"

           exit

         when "no"

           puts "OK, we'll continue"

         else

           puts "That's an unknown answer -- assuming you meant 'no'"

end

 

when 子句的匹配方法由 ===(三等号操作符)判断,即

if "yes" === answer

  puts "Good-bye!"

  exit

elsif "no" === answer

  puts "OK, we'll continue"

else

  puts "That's an unknown answer—assuming you meant 'no'"

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

  n = n + 1

  break if n > 9

end

 

使用 next 在没有完成本次循环的情况下跳到下一次循环

n = 1

loop do

  n = n + 1

  next unless n == 10

  break

end

 

2. 用 while 和 until 关键字实现条件循环

(1)while:在给定条件为真时循环执行代码

n = 1

while n < 11

  puts n

  n = n + 1

end

puts "Done!"

 

也可以把 while 子句放在循环的结束处,这时需要 begin/end 标记循环的头尾

n = 1

begin

  puts n

  n = n + 1

end while n < 11

puts "Done!"

 

(2)until:具有和 while 相同的用法,但是逻辑相反

n = 1

until n > 10

  puts n

  n = n + 1

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

  puts c

end

 

三、代码块、迭代器和 yield 关键字

1. 代码块:由任意多行 Ruby 代码构成,可以用大括号封装

object.method_name {

         # code inside block

}

也可以用 do/end 来封装

object.method_name do

         # code inside block

end

 

2. yield 关键字:如果在调用方法时提供了代码块,那么在该方法执行过程中可以将控制转移到该代码块(暂停方法的执行),执行代码块中的代码,最后再返回该方法继续执行

def demo_of_yield

  puts "Executing the method body..."

  puts "About to yield control to the block..."

  yield

  puts "Back from the block—finished!"

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|

         # code here

}

示例如下

def yield_an_arg

  puts "Yielding 10!"

  yield(10)

end

yield_an_arg {|x| puts "> Code block received this argument: #{x}" }

 

4. 从代码块返回值

def more_yielding

  puts "The code block shall multiply a number by 10."

  result = yield(3)

  puts "The result of this operation is #{result}."

end

more_yielding {|x| x * 10 }

 

5. 执行多个迭代

迭代:方法匿名调用代码块的过程

迭代器:任何匿名调用代码块的方法

使用代码块来执行温度转换方法

def temp_chart(temps)

  for temp in temps

    converted = yield(temp)

    puts "#{temp}\t#{converted}"

  end

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]

  puts x * 10

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)

        from -e:1

 

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

  result = 100 / n

rescue

  puts "Your number didn't work. Was it zero???"

  exit

end

puts "100/#{n} is #{result}."

 

指定想要营救的异常:rescue ZeroDivisionError

 

4. 显示抛出异常

可以给 raise 提供第二个参数,作为抛出异常时的消息字符串

def fussy_method(x)

  raise ArgumentError, "I need a number under 10" unless x < 10

end

fussy_method(20)

也可以在此例中使用 rescue

begin

  fussy_method(20)

rescue ArgumentError

  puts "That was not an acceptable number!"

end

 

5. 重新抛出异常

def reraiser(filename)

  file_handle = File.new(filename)

rescue Errno::ENOENT => e

  puts "Something's wrong with your filename...."

  raise 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

   or directory - some_non_existent_filename

   (Errno::ENOENT)

 

6. 创建异常类:通过从 Exception 或它的后代继承

class MyNewException < Exception

end

raise MyNewException, "some new kind of error has occurred!"

 

7. 异常及它们在 Rails 框架中的名字

ActiveController 库定义了 UnknownAction,  UnknownController, MissingTemplate 等异常,所有这些异常类都继承自中间级别的异常类 ActionControllerError,该类是 Ruby 内建的 StandardError类的子类。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值