[Dive into Ruby] Ruby Control Flow 控制语句

10/8/2017 posted in  编程语言 comments

[Dive into Ruby] Ruby 的介绍 主要介绍了 Ruby 的一些特性,[Dive into Ruby] Ruby Basic 变量、常量以及对象 则介绍了关于对象、变量常量的一些知识,这一篇将主要介绍 Ruby 中的程序控制语句,这一部分是每个编程语言的重点,因此会介绍的比较的详细,也会有一些小技巧。

条件控制语句与循环控制语句

条件语句 if\unless and case

首先介绍一下几乎所有高级语言都有的控制语句, if-else
在 Ruby 中,if 判断语句跟其它语言没什么区别,如果满足一个条件,则进入一个代码块,否则进入另一个代码块,或者不执行任何操作。写起来也非常的通俗易懂。
需要注意的是,在 Ruby 中,只有falsenil这两种情况会导致条件不满足,也就是说,只要值不是false或者是nilif就是满足的。

  if condition then
    # block
  else
    # block
  end
  
  if x > 10 
    # block
  end
  
  if "this is a string"
    # runs into here
  end
  
  if 12
    # runs into here
  end
  
  if user = User.find_by(id: uid) # 这里涉及到函数的返回值问题,后面会继续讨论
    puts user.name
  end
  
  if obj.instance_of? Object
    # runs into here
  end

在这里, then 这个关键字是可以省略的,大多数情况下都没有必要加上,少数特殊情况下不加会导致有歧义,但是也都可以改写。
而如果程序只有if没有else的代码块,而且if的代码块中只有一句话,那么可以缩短成一行实现。

  do_sth if condition

如果是否定的语句,可以使用 if not,也可以使用另一个关键字unless,很直白的翻译成除非(如果不)。因此可以这样写。

  do_sth unless condition 
  
  # 等价于
  do_sth if not condition
  

通常使用 unless是在只有一个否定的代码块的时候,这个时候使用unless能够表达比if not更加清晰的逻辑,并且避免了逻辑非的运算。在有条件分支的时候,应该使用if-else的逻辑,避免将unlesselse 搭配(因为这样几乎毫无意义)。

Ruby 中还有一种表示条件的控制语句,叫 case,用法基本与 Java 中的Switch相似。

  arr = ["string", 19, nil]
  arr.each do |item|
    case item
    when String
      puts "It's a string"
    when Numeric
      puts "It's numeric"
    else
      puts "It's something not string nor number"
    end
  end

Notes:
值得注意的是, case-when 中的比较是一种比较广泛的比较,实际上使用的是===比较,除了比较值之外,还会比较两边是否正则匹配,右边的对象是否属于左边的类等等。因此,在case-when中是可以直接使用正则表达式的。

循环语句 while\until and more

ifunless的关系类似,whileuntil是一对互为否定的关系。until === while not,使用 unlessuntil的最主要目的是,使得程序更具有可读性,在看到代码的第一时刻就明白这段代码的条件所在。

  while condition do # do 可以省略
  
  end
  
  until condition do # do 可以省略
  
  end

在 Ruby 中,实现循环有多种方式,如 for 循环、loop循环、while/until循环、.each循环、.times循环等等。在不同的情况下使用不同的循环方式,能够提升程序的可读性。

例如,在需要某段代码执行指定次数的时候,使用 n.times循环会更加的直接,在需要依次访问数组的元素的时候,使用array.each,而在需要循环直到某个条件满足或不满足的时候,使用while\until循环。当然这些循环都是可以在这些场景下使用的,不同的场景使用不同的循环方式,主要是为了程序的可读性以及可理解性。

  3.times do 
    puts "hello"
  end
  
  students = ['Andy', 'Bob', 'Cindy']
  
  students.each do |stu|
    puts stu # 通过迭代器能够更加简单的使用每一次迭代的元素
  end
  
  file = File.new('path')
  while line=file.readline
    # runs until last line
  end

Ruby 中的for循环在迭代的时候,使用的其实是 .each 方法,因此直接用.each来迭代就好了。

循环控制语句

在循环中,有时候需要跳出当前循环,或者终止当前循环,那么就需要对应的控制语句来完成。
Ruby 中的循环控制语句有三个 breaknext还有redoredo 用到的非常少,因此暂时不管它。
break 在其它语言中也经常会见到,因此有基础的人也比较容易理解,即当执行到这个语句的时候,终止整个循环程序,进入与循环同一层次的另一段代码。而 next则没有这么极端,当执行到next的时候,当前的这次循环将会从这里被跳过,后面的语句不再执行,直接进行下一次循环。
照样来个简单的代码来说明一下。

  
  students = ['Andy', 'Bob', 'Cindy', 'Dave']
  
  students.each do |stu|
    if stu == 'Bob'
      break
    end
    puts stu
  end
  # 程序运行结果: 
  # Andy
  
  students.each do |stu|
    if stu == 'Bob'
      next
    end
    puts stu
  end
  # 程序运行结果: 
  # Andy
  # Cindy
  # Dave

是不是很好理解?

运算符优先级问题

在不使用括号的情况下,各种不同的运算符拥有不同的优先级,简单的例子如,乘除法总是拥有着比加减法更高的优先级,非运算拥有比与、或运算更高的优先级。Ruby 中的运算符非常的多,不同运算符之间的优先级排序表如下。
其中有一些需要特别注意,例如: 按位与(&)比按位或^拥有更高的优先级,逻辑与(&&)比逻辑或(||)拥有更高的优先级。

在 Ruby 中,逻辑运算除了与&&|| 以及非!三种运算符之外,还有更加可读的 and or 以及 not 运算符,后面三者在逻辑运算中起着与前面三者相同的作用,但是,注意这个但是,and or not 是拥有着更低的优先级的(仅高于控制语句),这意味着在同样的情况下,如果混用 &&not,是会搞出大事情的。

因此,通常情况下,能够使用逻辑运算符 &&\||\!的时候,尽量这样使用,一方面它们的优先级较高,可以避免出现很多的问题,另一方面,使用 and\or\not 不太适合加括号,很多时候并没有很方便。

Ruby operators in precedence order. 优先级降序排列

Method Operator Description
Y [] []= Element reference, element set
Y ** Exponentiation
Y ! ~ + - Not, complement, unary plus and minus (method names for the last two are +@ and -@)
Y * / % Multiply, divide, and modulo
Y + - Plus and minus
Y >> << Right and left ⇧
Y & Bitwise `and'
Y ^ Bitwise exclusive 'or' and regular 'or'
Y <= < > >= Comparison operators
Y <=> == === != =~ !~ Equality and pattern match operators (!= and !~ may not be defined as methods)
&& Logical 'and'
|| Logical 'or'
.. ... Range (inclusive and exclusive)
? : Ternary if-then-else
= %= { /= -= += = &= >>= <<= *= &&=
defined? Check if symbol defined
not Logical negation
or and Logical composition
if unless while until Expression modifiers
begin/end Block expression

关于 Ruby 中的条件以及循环语句就介绍到这里,下一篇会介绍 Ruby 中的方法以及类的概念。