2

Ruby 的流程控制

 3 years ago
source link: http://blog.danthought.com/programming/2014/12/27/ruby-control-structures/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Ruby 的流程控制

if else 的写法

if data
  data << x
else
  data = [x]
end

if elsif 的写法

if x == 1
  name = "one"
elsif x == 2
  name = "two"
elsif x == 3 then name = "three"
elsif x == 4; name = "four"
else
  name = "many"
end

if 语句的返回值来做为赋值

name = if x == 1 then "one"
       elsif x == 2 then "two"
       elsif x == 3 then "three"
       elsif x == 4 then "four"
       else              "many"
       end

if 简短写法

puts message if message # 输出 message,如果有定义 message

unless

unless 当表达式是 falsenil,就执行下面的内容,用法类似于 if,除了没有 elsif 这样的写法

unless condition
  code 
end

unless condition
  code
else
  code
end

code unless condition
case

if/elsif/else 的另一种写法

name = case x
       when 1
         "one"
       when 2 then "two"
       when 3; "three"
       else "many"
       end

需要注意一点,case 中的表达式怎么和 when 中值进行比较的,是通过 === 运算符来完成的,上面的写法实际就是按下面这种方式运行的

name = case
       when 1 === x then "one"
       when 2 === x then "two"
       when 3 === x then "three"
       else "many"
       end

Class 类中定义 === 方法来检测对象是否某个类的实例,所以就可以写如下的代码

puts case x
     when String then "string"
     when Numeric then "number"
     when TrueClass, FalseClass then "boolean"
     else "other"
     end

?: 是一种更简洁的条件表达式

def how_many_messages(n)
  "You have " + n.to_s + ( n == 1 ? " message." : " messages.")
end

while

while 基本的写法

x = 10
while x >= 0 do
  puts x
  x = x - 1
end

while 简洁的写法

x = 0
puts x = x + 1 while x < 10

until

until 基本的写法

x = 0
until x > 10 do
  puts x
  x = x + 1
end

until 简洁的写法

a = [1, 2, 3]
puts a.pop until a.empty?

for in

for in 循环每一次都调用对象的 each 方法得到值

hash = { :a => 1, :b => 2, :c => 3 }
for key,value in hash
  puts "#{key} => #{value}"
end

还比如直接用 each 来的帅

hash = { :a => 1, :b => 2, :c => 3 }
hash.each do |key, value|
  puts "#{key} => #{value}"
end

块就是跟在方法后面在 { }do end 中的代码块

1.upto(10) { |x| puts x }
1.upto(10) do |x|
  puts x
end

在定义方法的时候可以通过 yield 调用块,如下面的自定义方法

def sequence(n, m, c)
  i = 0
  while (i < n)
    yield m * i + c # 调用块,传递值给块
    i += 1
  end
end

在方法定义中可以通过 block_given? 来判断是否有块

def sequence(n, m, c)
  i, s = 0, []
  while (i < n)
    y = m * i + c
    yield y if block_given?
    s << y
    i += 1
  end
  s
end

块中最后一行表达式的值就是块的返回值,从上面的例子可以看到方法定义中可以利用 yield 调用获取到块的返回值来进行相应的操作

words.sort! { |x, y| y <=> x }

块中定义的变量的作用域就在块中

其他的流程控制的

return

return 对于无论嵌套的块有多深,总是将最近的包围的方法返回

def find(array, target)
  array.each_with_index do |element, index|
    return index if (element == target) # 找到了就作为 find 的返回值
  end
  nil # 没有找到,就返回 nil
end

break

break 会结束循环,执行循环块后的第一条语句

while (line = gets.chop) # 循环开始
  break if line == "quit" # 退出循环
  puts eval(line)
end
puts "Good bye" # 然后从这里继续执行

next 会结束当前这一步的循环执行,进行下一步的循环执行

while(line = gets.chop) # 循环开始
  next if line[0, 1] == "#" # 如果是注释符号,到下一步循环
  puts eval(line)
  # 然后从这里继续执行
end

redo 会重新执行当前的这一步循环

i = 0
while (i < 3) # 输出 "0123" 而不是 "012"
  # redo 执行后会从这里继续执行
  print i
  i += 1
  redo if i == 3
end

异常对象是 Exception 类的实例或其子类的实例。需要知道的是大多数的异常子类都是继承于 StandardError 类,这是 Ruby 程序需要处理的异常

Exception 类定义了两个方法来获取异常的相关信息

  • message 方法返回易于人阅读的异常信息
  • backtrace 方法返回异常是在什么地方开始的,以及方法调用的层级引用

调用 raise 创建异常,若只有一个字符串参数时,会创建一个新的 RuntimeError 对象,字符串参数就是异常的 message

def factorial(n)
  raise "bad argument" if n < 1
  return 1 if n == 1
  n * factorial(n - 1)
end

调用 raise 时,若第一个参数是类,并且该类有一个 exception 方法,raise 就会调用这个 exception 方法然后抛出此方法返回的异常对象,因为 Exception 类定义了 exception 方法,所以你可以将任何异常类作为 raise 的第一个参数,还可以添加第二个参数传递给 exception 方法作为异常的 message

raise RuntimeError, "bad argument" if n < 1

调用 raise 时,若第一个参数是异常对象,那就直接将异常对象抛出

raise RuntimeError.new("bad argument") if n < 1
raise RuntimeError.exception("bad argument") if n < 1

自定义异常

自定义异常类,通常继承 StandardError

class MyError < StandardError
end

捕获异常,下面写法中 rescue 捕获任何 StandardError 的异常,其他的异常会被忽略掉

begin
  # 任意的 Ruby 表达式
rescue
  # 如果有异常抛出,流程就会转到这里
end

rescue 中,全局变量 $! 代表被处理的异常对象,可以通过下面的方式来为异常对象指定一个变量名称

begin
  x = factorial(-1)
rescue => ex
  puts "#{ex.class}: #{ex.message}"
end

捕获特定类型的异常

begin
  x = factorial(1)
rescue ArgumentError => ex
  puts "Try again with a value >= 1"
rescue TypeError => ex
  puts "Try again with an integer"
end

如果在 rescue 语句又发生了异常,原来被捕获的异常会被抛弃,新的异常传播会从这里开始

在异常捕获时,else 中的语句在 begin end 语句运行没有出现异常的时候才会执行

在异常捕获时,ensure 中的语句都会执行,无论前面异常捕获语句中的代码发生了什么

一个典型的方法定义中使用异常语句

def method_name(x)
  # 任意的 Ruby 表达式
rescue 
  # 如果有异常抛出,流程就会转到这里
else
  # 如果没有异常抛出,流程就会转到这里
ensure
  # 无论有没有异常抛出,流程就会转到这里
end

rescue 的一种简洁用法,不能指定异常类名,只能捕获 StandardError 异常

y = factorial(x) rescue 0

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK