ruby条件控制结构

天涯浪子 提交于 2020-03-02 14:05:49

 

一、比较语句

大部分和其他的语言一样,这里注意<=>、

 

条件语句

如下几种形式

  • if
  • if ..else.. end
  • if..elsif..else..end
  • unless(if not)
  • case..when
  • z

注意在ruby中只有nil和false为假。

x=1
if x==1
    puts 1
elsif x==2
    puts 2
else 
    puts  3
end

注意是elsif,不是elseif。与c相比,多了个end

 

但Ruby的case语句和C/C++的格式差异很大:

case 被判断项
  when 比较值 then 代码
  when 比较值 then 代码
  else 代码
end
    def [](index)
        case index
            when 0, -2 then @x
            when 1,-1  then @y
            when :x,"x" then @x
            when :y,"y" then @y
            else nil
        end
    end

p[0],p[-2]都返回x

例如,下面两段代码是等价的,但使用case的代码更加清晰:

if var < 60
  print "failed/n"
elsif var < 70
  print "passed/n"
elsif var < 80
  print "good/n"
elsif var < 90
  print "great/n"
else
  print "excellent/n"
end
case var
  when 0..59 then print "failed/n"
  when 60..69 then print "passed/n"
  when 70..79 then print "good/n"
  when 80..89 then print "great/n"
  else print "excellent/n"
end

  

case具有两种形式,下面的是一种,
name =case 
    when x==1 then "one"
    when x==2 then "two"
    else "many"
    end
puts name
你可以用一个换行符或分号(分号ruby1.9不适用)替代那个跟在when从句后面的关键字when:
 name =case 
    when x==1 
        "one"
    when x==2  
        "two"
    else "many"
    end
puts name

case语句中的else从句是可选的,如果没有为true的when从句,而且存在一个else从句,那么位于else和end之间的代码将被执行。这块代码中最后执行的表达式的值将被作为整个case语句的值。如果没有为true的when从句,而且没有else从句,那么就不会执行任何代码,而且case语句的返回值为nil。

case 语句中的一个when从句可以包含多个表达式(用逗号分隔),只要有一个为true就会执行。在简单形式的case语句中,逗号作用不大,就好像一个||操作符一样:
case
when x == 1, y == 0 then "x is one or y is zero" # Obscure syntax
when x == 2 || y == 1 then "x is two or y is one" # Easier to understand
end

目前为止,展示的case比较简单,实际上case的功能比这个强大的多。在大部分例子中,每个when从句的左侧都是一样的。在case的常用形式里,我们将这些when从句的左侧提取出来,与case本身关联在一起:

name = case x
        when 1 #just the value compare to x
            "one"
        when 2 then "two"
        when 3; "three"
        else "many"
        end
puts name

理解case语句重点在于,搞清楚when从句的值如何与case关键字后的表达式的值相比较的。这个比较使用的是===操作符。
===是条件相等性操作符(case equality)。对于许多类来说,比如先前提到的fixnum类,===操作符的行为是和==是一样的。但某些特定的类也重定义了该方法,用于实现一些有趣的行为:Class类将===定义为测试其右侧操作数是否为左侧操作数所命名的类的一个实例;Range类将===定义为测试其右侧操作数是否位于左侧操作数的范围之内。Regexp类将测试是否为匹配指定的模式。在Ruby1。9里,Symbol类将===定义为测试符号或字符串的相等性。基于这些对条件相等性操作符的定义,我们可以编写一个下面比较有趣的case语句:

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

 

# Compute 2006 U.S. income tax using case and Range objects
tax = case income
when 0..7550
income * 0.1
when 7550..30650
755 + (income-7550)*0.15
when 30650..74200
4220 + (income-30655)*0.25
when 74200..154800
15107.5 + (income-74201)*0.28
when 154800..336550
37675.5 + (income-154800)*0.33
else
97653 + (income-336550)*0.35
end

 

# Get user's input and process it, ignoring comments and exiting
# when the user enters the word "quit"
while line=gets.chomp do # Loop, asking the user for input each time
case line
when /^\s*#/ # If input looks like a comment...
next # skip to the next line.
when /^quit$/i # If input is "quit" (case insensitive)...
break # exit the loop.
else # Otherwise...
puts line.reverse # reverse the user's input and print it.
end
end

A when clause can have more than one expression associated with it. Multiple expressions
are separated by commas, and the === operator is invoked on each one. That is,
it is possible to trigger the same block of code with more than one value:

def hasValue?(x) # Define a method named hasValue?
case x # Multiway conditional based on value of x
when nil, [], "", 0 # if nil===x || []===x || ""===x || 0===x then
  false # method return value is false
else # Otherwise
  true # method return value is true
end
end

case与c++中switch区别:
c++中switch可以穿越多个后续的case从句不断执行,直到到达switch语句的末尾,或者遇到一个break或return语句才会结束。ruby的case语句不允许穿越的。
在java和c等编译性语言中,与每个case标签相关联的表达式必须是编译时常量,而不能是任意的运行时表达式,这常常使编译器能够用一个非常快速的查询表(lookup table)来实现switch语句,在ruby中没有这样的限制,case语句的性能相当于一个具有多个elsif从句的if语句的性能

三元操作符

def how_many_messages(n) #handle  singular/plural
    "you  have" + n.to_s + (n==1 ? " message. " : " messages. ")
end
how_many_messages 1

注意:

  "you  have" + n.to_s +(n==1 ? " message. " : " messages. ")

画红线的地方要有空格,否则错误:

F:/ruby/rubySource/ControllStrutrue.rb:44: warning: ambiguous first argument; put parentheses or even spaces
F:/ruby/rubySource/ControllStrutrue.rb:44: syntax error, unexpected tUPLUS, expecting keyword_end
"you have" + n.to_s +(n==1 ? " message. " : " messages. ")

循环迭代语句

x.times

 

x.updo,x.downto,x.step(limit,steplength)

 

在大多数语言里,if条件式是一个语句,但在ruby中,一切都是表达式,包括哪些通常被称为语句的控制结构。一个if语句的返回值就是被执行的代码中最后一个表达式的值;如果没有执行任何代码,那么返回值就是nil。

作为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
puts name

 unless和if相反,不能接elsif。

作为修饰符的if(if as a modifier)
采用if的普通语句形式时,ruby语法要求结尾必须有一个end。对于那些简单的、只有一行代码的条件式来说,这显得有些笨拙。这只是一个语法分析问题,解决之道就是将if语句本身作为分界符,将代码和条件式隔离开。这种情况下,我们通常不写成这样:
if exp then code end
而是写成:
code if exp
此时,if被称为语句(或表达式)修饰符。虽然条件式是后编写的,但他是先被求值的。如果不为false或nil,那么对应代码执行,否则,代码将不会执行,而且这个修饰表达式的返回值为nil。显而易见,这种语法不允许任何else从句

 (python可以,如:

>>> x=1
>>> name= x if x==1 else 5
>>> name
1
>>> name= x if x==5 else "hello"
>>> name
'hello'
>>>

:循环语句

while and until
Ruby’s basic looping statements are while and until. They execute a chunk of code
while a certain condition is true, or until the condition becomes true. For example:
x = 10 # Initialize a loop counter variable
while x >= 0 do # Loop while x is greater than or equal to 0
  puts x # Print out the value of x
  x = x - 1 # Subtract 1 from x
end # The loop ends here

# Count back up to 10 using an until loop
x = 0 # Start at 0 (instead of -1)
  until x > 10 do # Loop until x is greater than 10
  puts x
  x = x + 1
end # Loop ends here

 

作为修饰符的while和until

 

如果一个循环体仅包含一个ruby表达式,那么你可以将while和until作为修饰符置于该表达式之后,以一种非常紧凑的形式来表达该循环,比如:
x = 0 # Initialize loop variable
puts x = x + 1 while x < 10 # Output and increment in a single expression
在这种修饰符语法中,while关键字分隔了循环体和循环条件,从而省却了do(或换行符)和end关键提。
until也可以作为修饰符。
请注意:while和until作为修饰符时,他们必须和那些被他们所修饰的循环体处在同一行中

 

for in循环

The for loop, or for/in loop, iterates through the elements of an enumerable object
(such as an array). On each iteration, it assigns an element to a specified loop variable
and then executes the body of the loop. A for loop looks like this:
for var in collection do
   body
end
var is a variable or a comma-separated list of variables. collection is any object that
has an each iterator method. Arrays and hashes define the each method, and many other
Ruby objects do, too. The for/in loop calls the each method of the specified object. As
that iterator yields values, the for loop assigns each value (or each set of values) to the
specified variable (or variables) and then executes the code in body. As with the while
and until loops, the do keyword is optional and may be replaced with a newline or
semicolon.

注意:do关键字是可选的,可以被newline或分号替代

当然,这么写没错:

for key,value in hash do
    puts "#{key}=>#{value}"
end

for循环对each迭代器方法的依赖意味着它非常像迭代器,比如,上面的例子可以写成这样:
hash = {:a=>1, :b=>2, :c=>3}
hash.each do |key,value|
puts "#{key} => #{value}"
end
循环的for版本和each版本之间的唯一差别在于,跟在一个迭代器之后的代码块会定义一个新的变量作用域,我们将在后面讨论迭代器的相关细节。

 

迭代器和可枚举对象(Iterators and enumerable objects)

虽然while,until和for循环是ruby语言的核心部分之一,但是通常情况下我们更倾向是使用一个特殊的方法来编写循环,那就是迭代器,迭代器是ruby最为重要的特性之一,下面是一些新手入门常用的例子:
3.times{ puts "hell"}
data.each {|x| puts x}
[1,2,3].map{|x| x*x}
factorial=1
2.upto(n) {|x| factorial*=x}

The times, each, map, and upto methods are all iterators, and they interact with the
block of code that follows them. The complex control structure behind this is yield.
The yield statement temporarily returns control from the iterator method to the method
that invoked the iterator. Specifically, control flow goes from the iterator to the block
of code associated with the invocation of the iterator. When the end of the block is
reached, the iterator method regains control and execution resumes at the first statement
following the yield. In order to implement some kind of looping construct, an
iterator method will typically invoke the yield statement multiple times. Figure 5-1
illustrates this complex flow of control. Blocks and yield are described in detail in
§5.4 below; for now, we focus on the iteration itself rather than the control structure
that enables it.

Iterators that Don’t Iterate。 “期待一个关联代码块的方法”

chars = "hello world".tap {|x| puts "original object: #{x.inspect}"}
.each_char .tap {|x| puts "each_char returns: #{x.inspect}"}
.to_a .tap {|x| puts "to_a returns: #{x.inspect}"}
.map {|c| c.succ } .tap {|x| puts "map returns: #{x.inspect}" }
.sort .tap {|x| puts "sort returns: #{x.inspect}"}

 

each迭代器并不是那些传统的“数据结构”(数组,hash等)类的专利,ruby的IO类也定义了一个each迭代器,他可以把那些从输入/输出对象中读取出来的文本行传递尽量,因此在ruby中你可以像下面这样处理一个文件的行:

filename="F:/ruby/rubySource/data.txt"
 
File.open(filename) do |f| #open named file,pass as f
    f.each { | line | print line}
end

大多数定义了each方法的类都包含Enumerable模块,它定义了许多更特殊的迭代器,而他们都是基于each方法来实现的,each_with_index就是这些有用的迭代器其中之一。先前的例子,我们可以给每行添加一个行号:

File.open(filename) do |f| #open named file,pass as f
    f.each_with_index { | line,number | print "#{number}:#{line}" }
end

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!