ZetCode

Ruby 流程控制

最后修改于 2023 年 10 月 18 日

在本 Ruby 教程中,我们将讨论流程控制。 我们定义了几个关键词,使我们能够控制 Ruby 程序的流程。

条件语句和循环改变 Ruby 程序的流程。 条件语句是根据特定条件执行特定语句的关键字。 循环是多次执行的程序块。 当程序运行时,语句从源文件的顶部到底部逐个执行。

Ruby if 语句

if 关键字用于检查表达式是否为真。 如果为真,则执行一个语句。 语句可以是一个单独的语句,也可以是一个复合语句。 复合语句由块括起来的多个语句组成。 块是用 end 关键字括起来的代码。 then 关键字是可选的。

if_statement.rb
#!/usr/bin/ruby

num = gets.to_i

if num > 0 then

    puts "num variable is positive"
    puts "num variable equals to #{num}"
end

我们从用户那里读取一个数字。 如果该数字大于零,则我们向控制台打印两条消息。 如果不是,则什么也不做。

$ ./if_statement.rb
4
num variable is positive
num variable equals to 4

条件得到满足,消息被写入控制台。

我们可以使用 else 关键字来创建一个简单的分支。 如果 if 关键字后面的方括号内的表达式的计算结果为假,则会自动执行 else 关键字后面的语句。 代码块用 end 关键字括起来。

licence.rb
#!/usr/bin/ruby

age = 17

if age > 18

    puts "Driving license issued"
else

    puts "Driving license not permitted"
end

我们有一个年龄变量。 布尔表达式的计算结果为假,我们在控制台中得到“不允许驾驶执照”。

$ ./licence.rb
Driving license not permitted

我们可以使用 elsif 关键字创建多个分支。 elsif 关键字仅在先前的条件未满足时才测试另一个条件。 请注意,我们可以在测试中使用多个 elsif 关键字。

branches.rb
#!/usr/bin/ruby

print "Enter a number: "

num = gets.to_i

if num < 0

    puts "#{num} is negative"
elsif num == 0

   puts "#{num} is zero"
elsif num > 0

   puts "#{num} is positive"
end

我们有一个数值变量,我们测试它是否为负数、正数或是否等于零。 根据从用户那里读取的值,我们向控制台打印其中一条消息。

Ruby case 语句

case 语句是一个选择控制流程语句。 它允许变量或表达式的值通过多路分支控制程序执行的流程。 它比使用 ifelsif 语句的组合创建多个分支更简单。

我们有一个变量或一个表达式。 case 关键字用于将来自变量或表达式的值与值列表进行比较。 值列表用 when 关键字表示。 如果值匹配,则执行 when 之后的语句。 有一个可选的 else 语句。 如果未找到其他匹配项,则执行它。

domains.rb
#!/usr/bin/ruby

print "Enter top level domain: "

domain = gets.chomp

case domain
    when "us"
        puts "United States"
    when "de"
        puts "Germany"
    when "sk"
        puts "Slovakia"
    when "hu"
        puts "Hungary"
    else
        puts "Unknown"
end

在我们的程序中,我们有一个域变量。 我们从命令行读取该变量的值。 我们使用 when 语句来测试该变量的值。 有几个选项。 例如,如果该值等于“us”,则将“美国”字符串打印到控制台。

domain = gets.chomp

我们使用 gets 方法从用户那里获取输入。 输入还包括换行符。 使用 chomp 方法排除换行符。

$ ./domains.rb
Enter top level domain: hu
Hungary

我们在控制台中输入了“hu”字符串,程序响应“匈牙利”。

Ruby while、until 语句

while 语句是一个控制流程语句,它允许根据给定的布尔条件重复执行代码。 它在条件为真时执行代码。

while 关键字执行 end 关键字括起来的块内的语句。 每次表达式的计算结果为真时,都会执行这些语句。

while_statement.rb
#!/usr/bin/ruby

i = 0
sum = 0

while i < 10  do
   i = i + 1
   sum = sum + i
end

puts "The sum of 0..9 values is #{sum}"

在代码示例中,我们计算某个数字范围内值的总和。

while 循环有三个部分:初始化、测试和更新。 语句的每次执行称为一个循环。

i = 0
sum = 0

我们初始化 isum 变量。 i 用作计数器。

while i < 10  do
   ...
end

whiledo 关键字之间的表达式是第二阶段,即测试。 请注意,do 关键字是可选的。 主体中的语句一直执行到表达式的计算结果为假。

i = i + 1

这是 while 循环的最后一个阶段,第三阶段,更新。 我们递增计数器。 请注意,不正确地处理 while 循环可能会导致无限循环。

$ ./while_statement.rb
The sum of 0..9 values is 55

until 是一个控制流程语句,它在条件为假时执行代码。 循环在条件为真时停止。

until_statement.rb
#!/usr/bin/ruby

hours_left = 12

until hours_left == 0

    if hours_left == 1
        puts "There is #{hours_left} hour left"
    else
        puts "There are #{hours_left} hours left"
    end

    hours_left -= 1
end

在我们的示例中,我们有一个变量 hours_left。 我们开始倒计时。 在每个循环周期中,我们打印还剩下多少小时。 当变量等于零时,循环停止。

$ ./until_statement.rb
There are 12 hours left
There are 11 hours left
There are 10 hours left
There are 9 hours left
There are 8 hours left
There are 7 hours left
There are 6 hours left
There are 5 hours left
There are 4 hours left
There are 3 hours left
There are 2 hours left
There is 1 hour left

运行该示例,我们得到以下结果。

Ruby for 语句

当循环的循环次数在循环开始之前已知时,我们可以使用 for 语句。 for 循环与范围结合使用。 对于一个范围的每个元素,都会执行一个语句块。 语句用 end 关键字括起来。 do 关键字是可选的。

for_loop.rb
#!/usr/bin/ruby

for i in 0..9 do

    puts "#{i}"
end

在此示例中,我们向控制台打印数字 0..9。 在每个循环中,i 变量保存一个来自数字范围的值。 该值被打印到控制台。 .. 范围运算符创建一个数字列表,包括最后一个数字。

$ ./for_loop.rb
0
1
2
3
4
5
6
7
8
9

要使用 for 循环遍历元素数组,我们可以使用数组的 length 方法。

for_loop2.rb
#!/usr/bin/ruby

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter",
    "Saturn", "Uranus", "Neptune"]

for i in 0...planets.length

    puts planets[i]
end

在此示例中,我们有一个行星数组。 我们遍历数组并打印数组的每个元素。

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter",
    "Saturn", "Uranus", "Neptune"]

这是一个行星数组。

for i in 0...planets.length

length 方法返回数组的长度。 由于数组从 0 开始,因此最后一个索引为 n-1。 ... 范围运算符创建一个数字范围,排除最后一个高值。

puts planets[i]

我们打印数组中具有特定索引的元素。

$ ./for_loop2.rb
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

运行上述 Ruby 程序会产生此输出。

Ruby each 方法

在 Ruby 中,我们可以使用 each 方法来迭代数组的元素。 它接受两个参数。 一个元素和一个块。 该元素放在管道之间。 它是当前迭代的项目的占位符。 块是在每次迭代中执行的代码。

each_method.rb
#!/usr/bin/ruby

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter",
    "Saturn", "Uranus", "Neptune"]

planets.each do |planet|

    puts planet
end

在此示例中,我们使用 each 迭代器遍历一个行星数组。

planets.each do |planet|

    puts planet
end

each 迭代器是一个在 planets 数组上工作的方法。 planet 是迭代的当前项目的占位符。 我们可以把我们想要的任何字符放在那里。 我们可以使用 {} 字符代替 doend 关键字。

Ruby break、next 语句

break 语句可用于终止由 whileforcase 语句定义的块。

break_statement.rb
#!/usr/bin/ruby

while true

    r = 1 + rand(30)
    print "#{r} "

    if r == 22
        break
    end
end

puts

我们定义了一个无限 while 循环。 我们使用 break 语句跳出这个循环。 我们从 1 到 30 中选择一个随机值。 我们打印该值。 如果该值等于 22,我们结束无限 while 循环。

while true
   ...
end

这是一个无限循环。 while 循环的条件始终为真。 跳出这个无限循环的唯一方法是跳出。

r = 1 + rand(30)
print "#{r} "

我们计算一个从 1 到 30 的随机数并将其打印到控制台。

if r == 22
    break
end

如果该数字等于 22,我们中断循环。 while 循环终止。

$ ./break_statement.rb
20 14 6 26 30 12 2 10 18 29 28 11 30 26 20 22

我们可能会得到类似这样的结果。

next 语句用于跳过循环的一部分并继续循环的下一次迭代。 它可以与 forwhile 语句结合使用。

在以下示例中,我们打印一个无法被 2 整除而没有余数的数字列表。

next_statement.rb
#!/usr/bin/ruby

num = 0

while num < 100

    num += 1

    if (num % 2 == 0)
        next
    end

    print "#{num} "
end

puts

我们使用 while 循环迭代数字 1..99。

if (num % 2 == 0)
    next
end

如果表达式 num % 2 返回 0,则可以被 2 整除该数字。 执行 next 语句,并跳过循环的其余部分。 在我们的例子中,跳过了循环的最后一个语句,并且该数字未打印到控制台。 开始下一次迭代。

$ ./next_statement.rb
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39
41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77
79 81 83 85 87 89 91 93 95 97 99

这是程序的示例输出。

Ruby redo 语句

redo 语句重新启动循环的迭代,而不检查循环条件。 最后一个例子将是一个更复杂的例子。 它将演示 redo 语句和其他功能。

redo_statement.rb
#!/usr/bin/ruby

options = ["rock", "scissors", "paper"]

while true

    print <<TEXT
1 - rock
2 - scissors
3 - paper
9 - end game
TEXT

    val = gets.to_i

    r = rand(3) + 1

    if val == 9
        puts "End"
        exit
    end

    if ![1, 2, 3, 9].include?(val)
        puts "Invalid option"
        redo
    end

    computer = options[r-1]
    human = options[val-1]

    puts "I have #{computer}, you have #{human}"

    if val == r
        puts "Tie, next throw"
        redo
    end


    if val == 1 and r == 2
        puts "Rock blunts scissors, you win"

    elsif val == 2 and r == 1
        puts "Rock blunts scissors, you loose"

    elsif val == 2 and r == 3
        puts "Scissors cut paper, you win"

    elsif val == 3 and r == 2
        puts "Scissors cut paper, you loose"

    elsif val == 3 and r == 1
        puts "Paper covers rock, you win"

    elsif val == 1 and r == 3
        puts "Paper covers rock, you loose"

    end
end

我们有一个简单的石头剪刀布游戏。 在此代码示例中,我们使用 redo 语句、条件语句、随机数、数组和用户输入。

options = ["rock", "scissors", "paper"]

我们在选项数组中包含了游戏的所有可能性。 这三个词将在将消息打印到控制台时使用。

    print <<TEXT
1 - rock
2 - scissors
3 - paper
9 - end game
TEXT

我们使用 here文档语法将菜单打印到控制台。 here文档以 << 开头,后跟一个字符串。 相同的字符串关闭该结构;它必须左对齐。 这使我们能够一步打印多行。 每次游戏循环都会打印此菜单。

val = gets.to_i

r = rand(3) + 1

在这些代码行中,我们从终端读取一个值。 然后我们随机选择一个介于 1、2 和 3 之间的数字。 请注意,rand(3) 返回一个介于 0、1 和 2 之间的数字。 这就是我们添加 1 的原因。

if val == 9
    puts "End"
    exit
end

如果用户输入的等于 9,我们将“结束”打印到终端并结束游戏。 exit 方法终止程序。

if ![1, 2, 3, 9].include?(val)
    puts "Invalid option"
    redo
end

如果用户选择的值与菜单中提供的值不同,我们告知无效选项并重做循环。

computer = options[r-1]
human = options[val-1]

puts "I have #{computer}, you have #{human}"

这些数字被转换为字符串。 我们打印用户和计算机的选择。

if val == r
    puts "Tie, next throw"
    redo
end

如果双方都有相同的选项,则为平局。 我们开始一个新的游戏循环。 我们使用 redo 关键字。

if val == 1 and r == 2
    puts "Rock blunts scissors, you win"

elsif val == 2 and r == 1
    puts "Rock blunts scissors, you loose"
...

使用多个 ifelsif 分支,我们比较用户和计算机的选择。 我们决定谁是赢家。

$ ./redo_statement.rb
1 - rock
2 - scissors
3 - paper
9 - end game
3
I have paper, you have paper
Tie, next throw
1 - rock
2 - scissors
3 - paper
9 - end game
2
I have rock, you have scissors
Rock blunts scissors, you loose
1 - rock
2 - scissors
3 - paper
9 - end game
1
I have scissors, you have rock
Rock blunts scissors, you win
1 - rock
2 - scissors
3 - paper
9 - end game
9
End

这是一个示例输出。

在本 Ruby 教程中,我们讨论了控制流程结构。