Ruby_03_分支结构

Ruby_03_分支结构_第1张图片

Ruby_03_分支结构_第2张图片

Ruby 判断

Ruby 提供了其他现代语言中很常见的条件结构。

在这里,我们将解释所有的条件语句和 Ruby 中可用的修饰符

Ruby if...else 语句

语法

if conditional [then]
   code...
[elsif conditional [then]
    code...]...
[else
    code...]
end

if 表达式用于条件执行。
值 false 和 nil 为假,其他值都为真。(这个地方千万注意:ruby 中的数字 0 是真!!!),如下图所示
Ruby_03_分支结构_第3张图片
下面的正则匹配的是有N个  或者  没有 \w,其中\w代表的是数字或字母或下划线,但在Ruby中不包括汉字,
正则匹配成功的话,b = 0, 所以if b是成立的,因为在ruby中,0也是真,只有false和nil是假
Ruby_03_分支结构_第4张图片
请注意:Ruby 使用 elsif ,不是使用 else if 和 elif。
如果 conditional 为真,则执行 code
如果 conditional 不为真,则执行 else 子句中指定的 code
通常我们省略保留字 then
若想在一行内写出完整的 if 式,则必须以 then 隔开条件式和程式区块。
如下所示:
if a == 4 then a = 7 end


下面是实例及输出结果:

Ruby_03_分支结构_第5张图片

Ruby if 修饰符

语法

code if condition

如果 conditional 为真,则执行 code牛X

实例

#!/usr/bin/ruby

$debug=1
print "debug\n" if $debug


这将产生以下结果:

debug

Ruby_03_分支结构_第6张图片

Ruby unless 语句

语法

unless conditional [then]
   code
[else
   code ]
end

unless式和 if式作用相反,即如果 conditional 为假,则执行 code

如果 conditional 为真,则执行 else 子句中指定的 code牛X

实例

#!/usr/bin/ruby

x=1
unless x>2
   puts "x 小于 2"
 else
  puts "x 大于 2"
end

这将产生以下结果:

x 小于 2

Ruby_03_分支结构_第7张图片

Ruby unless 修饰符

语法

code unless conditional

如果 conditional 为假,则执行 code牛X

实例

Ruby_03_分支结构_第8张图片

Ruby case 语句

语法

case expression
[when expression [, expression ...] [then]
   code ]...
[else
   code ]
end

case先对一个 expression 进行匹配判断,然后根据匹配结果进行分支选择。

它使用 ===运算符比较 when 指定的 expression,若一致的话就执行 when 部分的内容。

通常我们省略保留字 then 。

若想在一行内写出完整的 when 式,则必须以 then 隔开条件式和程式区块。如下所示:

when a == 4 then a = 7 end

因此:

case expr0
when expr1, expr2
   stmt1
when expr3, expr4
   stmt2
else
   stmt3
end

基本上类似于:

_tmp = expr0
if expr1 === _tmp || expr2 === _tmp
   stmt1
elsif expr3 === _tmp || expr4 === _tmp
   stmt2
else
   stmt3
end

实例

Ruby_03_分支结构_第9张图片

Ruby 循环

Ruby 中的循环用于执行相同的代码块若干次。本章节将详细介绍 Ruby 支持的所有循环语句。

Ruby while 语句

语法

while conditional [do]
   code
end

或者

while conditional [:]
   code
end

当 conditional 为真时,执行 code

语法中 do 或 : 可以省略不写。

但若要在一行内写出 while 式,则必须以 do 或 : 隔开条件式或程式区块。

实例

Ruby_03_分支结构_第10张图片

Ruby while 修饰符

语法

code while condition

或者

begin 
  code 
end while conditional

当 conditional 为真时,执行 code

如果 while 修饰符跟在一个没有 rescue 或 ensure 子句的 begin 语句后面,code 会在 conditional 判断之前执行一次。???Excuse Me???

实例

Ruby_03_分支结构_第11张图片

Ruby until 语句

until conditional [do]
   code
end

当 conditional 为假时,执行 code

语法中 do 可以省略不写。但若要在一行内写出 until 式,则必须以 do 隔开条件式或程式区块。

实例

Ruby_03_分支结构_第12张图片

Ruby until 修饰符

语法

code until conditional

或者

begin
   code
end until conditional

当 conditional 为假时,执行 code

如果 until 修饰符跟在一个没有 rescue 或 ensure 子句的 begin 语句后面,code 会在 conditional 判断之前执行一次。???Excuse Me???

实例

Ruby_03_分支结构_第13张图片

Ruby for 语句

语法

for variable [, variable ...] in expression [do]
   code
end

针对 expression 中的每个元素分别执行一次 code

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

for i in 0..5
   puts "局部变量的值为 #{i}"
end

在这里,我们已经定义了范围 0..5。语句 for i in 0..5 允许 i 的值从 0 到 5(包含 5)。


以上实例输出结果为:

局部变量的值为 0
局部变量的值为 1
局部变量的值为 2
局部变量的值为 3
局部变量的值为 4
局部变量的值为 5

Ruby_03_分支结构_第14张图片

for...in 循环几乎是完全等价于:

(expression).each do |variable[, variable...]| code end

但是,for 循环不会为局部变量创建一个新的作用域。???Excuse Me???

语法中 do 可以省略不写。

但若要在一行内写出 for 式,则必须以 do 隔开条件式或程式区块。

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

(0..5).each do |element|
   puts "局部变量的值为 #{element}"
end


以上实例输出结果为:

局部变量的值为 0
局部变量的值为 1
局部变量的值为 2
局部变量的值为 3
局部变量的值为 4
局部变量的值为 5

Ruby_03_分支结构_第15张图片

Ruby break 语句

语法

break

终止最内部的循环。

如果在块内调用,则终止相关块的方法(方法返回 nil)

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

for i in 0..5
   if i > 2 then
      break
   end
   puts "局部变量的值为 #{i}"
end


以上实例输出结果为:

局部变量的值为 0
局部变量的值为 1
局部变量的值为 2

Ruby_03_分支结构_第16张图片

Ruby next 语句 (类似于continue)

语法

next

跳到最内部循环的下一个迭代。

如果在块内调用,则终止块的执行(yield 或调用返回 nil)。???Excuse Me???

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

for i in 0..5
   if i < 2 then
      next
   end
   puts "局部变量的值为 #{i}"
end


以上实例输出结果为:

局部变量的值为 2
局部变量的值为 3
局部变量的值为 4
局部变量的值为 5

Ruby_03_分支结构_第17张图片

Ruby redo 语句

语法

redo

重新开始最内部循环的该次迭代不检查循环条件

如果在块内调用,则重新开始 yield 或 call

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

for i in 0..5
   if i < 2 then
      puts "局部变量的值为 #{i}"
      redo
   end
end

这将产生以下结果,并会进入一个无限循环:

局部变量的值为 0
局部变量的值为 0
............................

Ruby_03_分支结构_第18张图片

Ruby retry 语句

语法

retry

如果 retry 出现在 begin 表达式的 rescue 子句中,

从 begin 主体的开头重新开始。???Excuse Me???

begin
   do_something # 抛出的异常
rescue
   # 处理错误
   retry  # 重新从 begin 开始
end

如果 retry 出现在迭代内、块内或者 for 表达式的主体内,则重新开始迭代调用。

迭代的参数会重新评估。(重置计数器???)

for i in 1..5
   retry if some_condition # 重新从 i == 1 开始
end

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

for i in 1..5
   retry if  i > 2
   puts "局部变量的值为 #{i}"
end

理论上,这个将会产生以下的结果,并会进入一个无限循环,但是:

局部变量的值为 1
局部变量的值为 2
局部变量的值为 1
局部变量的值为 2
局部变量的值为 1
局部变量的值为 2
............................

为啥报错???


Ruby 方法

Ruby 方法与其他编程语言中的函数类似。

Ruby 方法用于捆绑一个或多个重复的语句到一个单元中。

方法名应以小写字母开头

如果您以大写字母作为方法名的开头,Ruby 可能会把它当作常量,从而导致不正确地解析调用。

方法应在调用之前定义,否则 Ruby 会产生未定义的方法调用异常。

语法

def method_name [( [arg [= default]]...[, * arg [, &expr ]])]
   expr..
end

所以,您可以定义一个简单的方法,如下所示:

def method_name 
   expr..
end

您可以定义一个接受参数的方法,如下所示:

def method_name (var1, var2)
   expr..
end

您可以为参数设置默认值,如果方法调用时未传递必需的参数则使用默认值:

def method_name (var1=value1, var2=value2)
   expr..
end

当您要调用无参数的方法时,只需要使用方法名即可,如下所示:

method_name

但是,当您调用带参数的方法时,您在写方法名时还要带上参数,例如:牛X

method_name 25, 30

使用带参数方法最大的缺点是:调用方法时需要记住参数个数。哈哈~

例如,如果您向一个接受三个参数的方法只传递了两个参数,Ruby 会显示错误。

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

def test(a1="Ruby", a2="Perl")
   puts "编程语言为 #{a1}"
   puts "编程语言为 #{a2}"
end
test "C", "C++"
test


这将产生以下结果:

编程语言为 C
编程语言为 C++
编程语言为 Ruby
编程语言为 Perl

Ruby_03_分支结构_第19张图片

从方法返回值

Ruby 中的每个方法默认都会返回一个值。

这个返回的值是最后一个语句的值。例如:

def test
   i = 100
   j = 10
   k = 0
end

在调用这个方法时,将返回最后一个声明的变量 k。

Ruby return 语句

Ruby 中的 return 语句用于从 Ruby 方法中返回一个或多个值。

语法

return [expr[`,' expr...]]

如果给出超过两个的表达式,包含这些值的数组将是返回值。

如果未给出表达式,nil 将是返回值。

实例

return

return 12

return 1,2,3

看看下面的实例:

Ruby_03_分支结构_第20张图片

可变数量的参数

假设您声明了一个带有两个参数的方法,当您调用该方法时,您同时还需要记得传递两个参数。

但是,Ruby 允许您声明参数数量可变的方法。

让我们看看下面的实例:


在下面的这段代码中,您已经声明了一个方法 showGirl,接受一个参数 paramArr。

但是,这个参数是一个变量参数。

这意味着参数可以带有不同数量的变量。

所以上面的代码将产生下面的结果:

Ruby_03_分支结构_第21张图片

类方法???Excuse Me???

当方法定义在类定义外部时,方法默认标记为 private

另一方面,定义在类定义中的方法默认标记为 public。

方法默认的可见性 和  private 标记可通过模块(Module)的 public 或 private 改变。

当你想要访问类的方法时,您首先需要实例化类。

然后,使用对象,您可以访问类的任何成员。

Ruby 提供了一种不用实例化类即可访问方法的方式。

让我们看看如何声明并访问类方法:

class Girl
   def instance_method
   end
   def Girl.class_method
   end
end

我们已经知道类方法 class_method 是如何声明的。???Excuse Me???

它是通过在类名后跟着一个点号,点号后跟着方法名来声明的。

您可以直接访问类方法,如下所示:

Girl.class_method

如需访问该方法,您不需要创建类 Girl 的对象。

代码如下:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
#coding=utf-8

class Girl
	#使用类名,声明类方法
	def Girl.showCup(cup)
		puts "girl's cup is #{cup}"
	end
	#使用self,声明类方法
	def self.showAge(age)
		puts "girl's age is #{age}"
	end

	#第3种,使用<<特殊符号,凡是在它的范围内,以定义实例方法的形式定义的方法,都是类方法
	class << self
		def showName(name)
			puts "girl's name is #{name}"
		end
	end

	#第4种,instance_eval定义单例方法(Eigenclass Method或者Singleton Method)
	#反而class_eval定义实例方法(Instance Method)
	#???Excuse Me???
	Girl.instance_eval do
        def showBirthday(birthday)
            puts "girl's birthday is #{birthday}"
        end
    end
end
Girl.showCup("F")
Girl.showAge 13
Girl.showName "いりえ·さあや"
Girl.showBirthday "1993年11月15日"

运行效果如下:

Ruby_03_分支结构_第22张图片

Ruby alias 语句

这个语句用于为方法 或 全局变量起别名。

别名不能在方法主体内定义。

即使方法被重写,方法的别名也保持方法的当前定义。

为编了号的全局变量($1, $2,...)起别名 是被禁止的。

重写内置的全局变量可能会导致严重的问题。

语法

alias 方法别名 方法名
alias 全局变量别名 全局变量

实例

alias aliasMethod   originMethod
alias $aliasGlobalVariable    $&

在这里,我们已经为 originalMethod 定义了别名为 aliasMethod,

为 $& 定义了别名为 $aliasGlobalVariable

Ruby undef 语句

这个语句用于取消方法定义

undef 不能出现在方法主体内。

通过使用 undef 和 alias类的接口可以从父类独立修改 ???Excuse Me???

但请注意,在自身内部方法调用时,它可能会破坏程序。

语法

undef 方法名

实例

下面的实例取消名为 showGirlCup的方法定义:

undef showGirlCup


Ruby 

您已经知道 Ruby 如何定义方法以及您如何调用方法。

类似地,Ruby 有一个块的概念。

  • 块由大量的代码组成。
  • 您需要给块取个名称。
  • 块中的代码总是包含在大括号 {} 内。
  • 块总是从与其具有相同名称的函数调用。这意味着如果您的块名称为 test,那么您要使用同名的函数 test 来调用这个块。
  • 您可以使用 yield 语句来调用块

语法

block_name{
   statement1
   statement2
   ..........
}



在这里,您将学到如何使用一个简单的 yield 语句来调用块。

您也将学到如何使用带有参数的 yield 语句来调用块


在实例中,您将看到这两种类型的 yield 语句。

yield 语句

让我们看一个 yield 语句的实例:

Ruby_03_分支结构_第23张图片


您也可以传递带有参数的 yield 语句。下面是一个实例:

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-

def test
   yield 67
   puts "在 test 方法内"
   yield 520
end
test {|i| puts "#{i}在块内"}

这将产生以下结果:

67在块
 test 方法内
520在块

Ruby_03_分支结构_第24张图片

在这里,yield 语句后跟着参数。

您甚至可以传递多个参数。

在块中,您可以在两个竖线之间放置一个变量来接受参数,如|a|。

因此,在上面的代码中,yield 67    语句向 test 块传递值 67 作为参数。

现在,看下面的语句:

test {|i| puts "#{i}在块内"}

在这里,值 67 会在变量 i 中收到。

现在,观察下面的 puts 语句:

puts "#{i}在块内"

这个 puts 语句的输出是:

67在块


如果您想要向block块传递多个参数,那么 yield 语句如下所示:

yield a, b

此时,块如下所示:

test {|a, b| statement}

参数使用逗号分隔。

Ruby_03_分支结构_第25张图片

块和方法

您已经看到块和方法之间是如何相互关联的。

您通常使用 yield 语句 从 与其具有相同名称的 方法里面 调用块。

因此,代码如下所示:

#!/usr/bin/ruby

def test
  yield
end
test{ puts "Hello world"}

本实例是实现块的最简单的方式。

您使用 yield 语句调用 test 块。

Ruby_03_分支结构_第26张图片

但是如果方法的最后一个参数前带有 &,那么您可以向该方法传递一个块block且这个块可被赋给最后一个参数。

如果 * 和 & 同时出现在参数列表中,& 应放在后面。

#!/usr/bin/ruby

def test(&block)
   block.call
end
test { puts "Hello World!"}


这将产生以下结果:

Hello World!

Ruby_03_分支结构_第27张图片

BEGIN 和 END 块

每个 Ruby 源文件可以声明当文件被加载时要运行的代码块(BEGIN 块),以及程序执行完成要运行的代码块(END 块)。

#!/usr/bin/ruby

BEGIN { 
  # BEGIN 代码块
  puts "BEGIN 代码块"
} 

END { 
  # END 代码块
  puts "END 代码块"
}
  # MAIN 代码块
puts "MAIN 代码块"

一个程序可以包含多个 BEGIN 和 END 块。

BEGIN 块按照它们出现的顺序执行。

END 块按照它们出现的相反顺序执行。

当执行时,上面的程序产生产生以下结果:

BEGIN 代码块
MAIN 代码块
END 代码块


Ruby_03_分支结构_第28张图片

Ruby 模块(Module)

Ruby同JAVA一样只支持单继承,每个类只能有一个父类,

为了提高程序的灵活性ruby引入了 模块 ,为实现多重继承提供了可能。

模块可以说是类的一个补充,但是模块于类有两个不同:

1.模块不能拥有实例
2.模块不能被继承 

模块名必须是大写字母开头

Ruby_03_分支结构_第29张图片

模块(Module)是一种把方法、类和常量组合在一起的方式。

模块(Module)为您提供了两大好处。

  • 模块提供了一个命名空间和避免名字冲突。
  • 模块实现了 mix-in 装置 ???Excuse Me???

模块(Module)定义了一个命名空间,相当于一个沙盒,在里边您的方法和常量不会与其他地方的方法常量冲突。


模块类似与类,但又有以下不同:

  • 模块不能实例化
  • 模块没有子类
  • 模块只能被另一个模块定义 ???Exucse Me???Mix-in 就是将模块混合到类中。在定义类时使用include,从而在类中可以使用模块里的常量、方法等
  • 附:使用Mix-in 时,方法的查找顺序
    1.同继承关系一样,类自身已经定义了同名方法时,优先使用类自身的方法。 
    2.一个类中包含多个模块,优先使用最后一个包含的模块
    3.多级嵌套include时,查找顺序也是线性的。
    4.如果相同模块被包含两次以上(含两次),则第二次后的会被忽略。
    通过 类名.ancestors方法可以查看该类的继承关系和顺序。
module Identifier
   statement1
   statement2
   ...........
end

模块常量  命名与类常量命名类似,以大写字母开头。

方法定义看起来也相似:模块方法定义与类方法定义类似。

通过类方法,您可以在  类方法名称前面  放置模块名称和一个点号  来调用模块方法,

您可以使用模块名称 和 两个冒号来引用一个  常量

实例

#!/usr/bin/ruby

# 定义在 ruby_42.rb 文件中的模块

module GirlModule
   PI = 3.141592654
   def GirlModule.showCup(cup)
   # ..
   end
   def GirlModule.showAge(age)
   # ..
   end
end

我们可以定义多个函数名称相同但是功能不同的模块:

#!/usr/bin/ruby

# 定义在 ruby_43.rb 文件中的模块

module LoliModule
   VERY_SMALL = 0
   SMALL = 1
   def LoliModule.showCup(cup)
   # ...
   end
end

就像类方法,当您在模块中定义一个方法时,您必须指定在模块名称后跟着一个点号,点号后跟着方法名。

# 如果想校验类是否包含某个模块可以用如下方式: 
# 类名.include?(模块名)        返回true or false
puts Girl.include?(GirlModule)

Ruby_03_分支结构_第30张图片

Ruby require 语句

require 语句类似于 C 和 C++ 中的 include 语句以及 Java 中的 import 语句。

如果一个第三方的程序想要使用任何已定义的模块,则可以简单地使用 Ruby require 语句来加载模块文件:

语法

require filename

在这里,文件扩展名 .rb 不是必需的。

实例

在这里,我们可以使用 $LOAD_PATH << '.' 让 Ruby 知道必须在当前目录中搜索被引用的文件。

如果您不想使用 $LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件。

注意:在这里,文件包含相同的函数名称。

所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,而且我们可以使用模块的名称调用适当的函数。

模块1代码如下:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
#coding=utf-8

#定义在ruby_44_module01文件中的模块
module T_Module
    PI = Math::PI #52163/16604.0 #355/113.0 #22/7
    def T_Module.sin(x)
        res = Math.sin(x)
        puts "T_Module sin(#{x}) is #{res}"
    end

    def T_Module.cos(x)
        res = Math.cos(x)
        puts "T_Module cos(#{x}) is #{res}"
    end
end

模块2代码如下:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
#coding=utf-8

#定义在ruby_44_module02文件中的模块
module P_Module
    VERY_BAD = 0
    BAD = 1
    def P_Module.sin(x)
        res = Math.sin(x)
        puts "P_Module,sin(#{x}) is #{res}"
    end
end

主文件代码如下:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
#coding=utf-8

require '/Users/beyond/sg_ruby/ruby_44_module01.rb'
require '/Users/beyond/sg_ruby/ruby_44_module02.rb'

res = T_Module.sin(T_Module::PI/2)
puts res

res = T_Module.sin(T_Module::PI/6)
puts res

calc = P_Module.sin(P_Module::VERY_BAD)
puts calc

运行效果如下:

Ruby_03_分支结构_第31张图片

Ruby include 语句

您可以在类中嵌入模块

为了在类中嵌入模块,您可以在类中使用 include 语句:

语法

include modulename

如果模块是定义在一个单独的文件中,那么在嵌入模块之前使用 require 语句引用该文件是必需的。

实例

假设下面的模块写在ruby_45_module.rb 文件中。

module BeyondModule
	FIRST_DAY = "日曜日"
	def Beyond.showWeeks
		puts "月・火・水・木・金・土・日"
	end
	def Beyond.showYears
		puts "鼠,牛,虎,兎,龍(たつ),蛇,馬,羊(ひつじ),猿,鶏,犬,豚(いのしし)"
	end
end

现在,您可以在类中引用该模块,如下所示:

Ruby_03_分支结构_第32张图片

Ruby 中的 Mix-ins


当一个类可以从多个父类继承类的特性时,该类显示为多重继承。

Ruby 不直接支持多重继承,

但是 Ruby 的模块(Module)有另一个神奇的功能。

它几乎消除了多重继承的需要,提供了一种名为 mix-in 的装置。

Mix-ins 向您提供了一种完美的为类添加功能的控制方式。

但是,它们真正的强大在于当 mix-in 中的代码开始与使用它的类中的代码交互时。

让我们看看下面的示例代码,深入了解 mixin:

module A
   def a1
   end
   def a2
   end
end
module B
   def b1
   end
   def b2
   end
end

class Sample
include A
include B
   def s1
   end
end

samp=Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1

  • 模块 A 由方法 a1 和 a2 组成。
  • 模块 B 由方法 b1 和 b2 组成。
  • 类 Sample 包含了模块 A 和 B。
  • 类 Sample 可以访问模块AB的所有四个方法,即 a1、a2、b1 和 b2。    
  • 因此,您可以看到类 Sample 继承了两个模块,您可以说类 Sample 使用了多重继承或
 mix-in 

我们可以使用类.ancestor打印所有的继承关系

Ruby_03_分支结构_第33张图片

未完待续,下一章节,つづく


你可能感兴趣的:(#,Ruby,Ruby,分支结构)