Ruby块、模块、字符串、数组、哈希和日期&时间

Ruby 块

您已经知道 Ruby 如何定义方法以及您如何调用方法。类似地,Ruby 有一个块的概念。

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

在这里,您将学到如何使用一个简单的yield 语句来调用块。您也将学到如何使用带有参数的yield语句来调用块。在实例中,您将看到这两种类型的 yield语句。

yield 语句

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

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
def test
   puts "在 test 方法内"
   yield
   puts "你又回到了 test 方法内"
   yield
end
test {puts "你在块内"}

以上实例运行结果为:

在 test 方法内
你在块内
你又回到了 test 方法内
你在块内

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

实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
def test
   yield 5
   puts "在 test 方法内"
   yield 100
end
test {|i| puts "你在块 #{i} 内"}

以上实例运行结果为:

你在块 5 内
在 test 方法内
你在块 100

在这里,yield 语句后跟着参数。您甚至可以传递多个参数。
在块中,您可以在两个竖线之间放置一个变量来接受参数。
因此,在上面的代码中,yield 5 语句向 test 块传递值 5 作为参数。

现在,看下面的语句:

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

在这里,值 5 会在变量 i 中收到。现在,观察下面的 puts 语句:

puts "你在块 #{i} 内"

这个 puts 语句的输出是:

你在块5

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

yield a, b

此时,块如下所示:

test {|a, b| statement}

参数使用逗号分隔。

块和方法

您已经看到块和方法之间是如何相互关联的。您通常使用 yield 语句从与其具有相同名称的方法调用块。因此,代码如下所示:

#!/usr/bin/ruby
 
def test
  yield
end
test{ puts "Hello world"}

本实例是实现块的最简单的方式。您使用yield语句调用 test 块。

但是如果方法的最后一个参数前带有 &,那么您可以向该方法传递一个块,且这个块可被赋给最后一个参数。如果 * 和 & 同时出现在参数列表中,& 应放在后面。

实例

#!/usr/bin/ruby
 
def test(&block)
   block.call
end
test { puts "Hello World!"}

尝试一下 »
以上实例运行结果为:

Hello World!

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 代码块

模块常量命名与类常量命名类似,以大写字母开头。
方法定义看起来也相似:模块方法定义与类方法定义类似。
通过类方法,您可以在类方法名称前面放置模块名称和一个点号来调用模块方法,您可以使用模块名称和两个冒号来引用一个常量。

#!/usr/bin/ruby
 
# 定义在 trig.rb 文件中的模块
 
module Trig
   PI = 3.141592654
   def Trig.sin(x)
   # ..
   end
   def Trig.cos(x)
   # ..
   end
end

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

#!/usr/bin/ruby
 
# 定义在 moral.rb 文件中的模块
 
module Moral
   VERY_BAD = 0
   BAD = 1
   def Moral.sin(badness)
   # ...
   end
end

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

Ruby require 语句

require 语句类似于 CC++ 中的 include语句以及 Java中的 import语句。如果一个第三方的程序想要使用任何已定义的模块,则可以简单地使用 Ruby require 语句来加载模块文件:
语法

require filename

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

实例

$LOAD_PATH << '.'
 
require 'trig.rb'
require 'moral'
 
y = Trig.sin(Trig::PI/4)
wrongdoing = Moral.sin(Moral::VERY_BAD)

在这里,我们使用$LOAD_PATH << '.' 让 Ruby 知道必须在当前目录中搜索被引用的文件。
如果您不想使用$LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件。

注意:在这里,文件包含相同的函数名称。
所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,而且我们可以使用模块的名称调用适当的函数。

Ruby include 语句

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

include modulename

如果模块是定义在一个单独的文件中,那么在嵌入模块之前就需要使用 require 语句引用该文件。
实例
假设下面的模块写在 support.rb 文件中。

module Week
   FIRST_DAY = "Sunday"
   def Week.weeks_in_month
      puts "You have four weeks in a month"
   end
   def Week.weeks_in_year
      puts "You have 52 weeks in a year"
   end
end

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

#!/usr/bin/ruby
$LOAD_PATH << '.'
require "support"
 
class Decade
include Week
   no_of_yrs=10
   def no_of_months
      puts Week::FIRST_DAY
      number=10*12
      puts number
   end
end
d1=Decade.new
puts Week::FIRST_DAY
Week.weeks_in_month
Week.weeks_in_year
d1.no_of_months

这将产生以下结果:

Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

Ruby 中的 Mixins

在阅读本节之前,您需要初步了解面向对象的概念。
当一个类可以从多个父类继承的特性时,该类显示为多重继承
Ruby 不直接支持多重继承,但是 Ruby 的模块(Module)有另一个神奇的功能。
它几乎消除了多重继承的需要,提供了一种名为 mixin的装置。

Ruby 没有真正实现多重继承机制,而是采用成为mixin技术作为替代品。
将模块include到类定义中,模块中的方法就mix进了类中。
让我们看看下面的示例代码,深入了解 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 可以访问所有四个方法,即 a1、a2、b1 和 b2。
因此,您可以看到类 Sample 继承了两个模块,您可以说类 Sample 使用了多重继承或mixin

Ruby 字符串(String)

Ruby 中的 String 对象用于存储或操作一个或多个字节的序列。
Ruby 字符串分为单引号字符串(’)和双引号字符串("),区别在于双引号字符串能够支持更多的转义字符

单引号字符串

最简单的字符串是单引号字符串,即在单引号内存放字符串:

'这是一个 Ruby 程序的字符串'

如果您需要在单引号字符串内使用单引号字符,那么需要在单引号字符串使用反斜杠(\),这样 Ruby 解释器就不会认为这个单引号字符是字符串的终止符号:

'Won\'t you read O\'Reilly\'s book?'

反斜杠也能转义另一个反斜杠,这样第二个反斜杠本身不会解释为转义字符。
以下是 Ruby 中字符串相关的特性。

双引号字符串

双引号字符串中我们可以使用 #{} 井号和大括号来计算表达式的值:
字符串中嵌入变量:
实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
name1 = "Joe"
name2 = "Mary"
puts "你好 #{name1},  #{name2} 在哪?"

以上实例输出运行输出结果为:

你好 Joe,  Mary 在哪?

字符串中进行数学运算:

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
x, y, z = 12, 36, 72
puts "x 的值为 #{ x }"
puts "x + y 的值为 #{ x + y }"
puts "x + y + z 的平均值为 #{ (x + y + z)/3 }"

尝试一下 »
以上实例输出运行输出结果为:

x 的值为 12
x + y 的值为 48
x + y + z 的平均值为 40

Ruby 中还支持一种采用 %q%Q来引导的字符串变量
%q使用的是单引号引用规则,而 %Q双引号引用规则
后面再接一个(! [ { 等等的开始界定符和与 } ] )等等的末尾界定符。

跟在 qQ 后面的字符是分界符.
分界符可以是任意一个非字母数字的单字节字符.
如:[,{,(,<,!等,字符串会一直读取到发现相匹配的结束符为止.
实例

#!/usr/bin/ruby
# -*- coding: UTF-8 -*-
 
desc1 = %Q{Ruby 的字符串可以使用 '' 和 ""。}
desc2 = %q|Ruby 的字符串可以使用 '' 和 ""。|
 
puts desc1
puts desc2

尝试一下 »
以上实例输出运行输出结果为:

Ruby 的字符串可以使用 ''""Ruby 的字符串可以使用 ''""

转义字符

下标列出了可使用反斜杠符号转义的转义字符或非打印字符。

注意:
在一个双引号括起的字符串内,转义字符会被解析。
在一个单引号括起的字符串内,转义字符不会被解析,原样输出。

反斜杠符号十六进制字符描述
\a0x07报警符
\b0x08退格键
\cxControl-x
\C-xControl-x
\e0x1b转义符
\f0x0c换页符
\M-\C-xMeta-Control-x
\n0x0a换行符
\nnn八进制表示法,其中 n 的范围为 0.7
\r0x0d回车符
\s0x20空格符
\t0x09制表符
\v0x0b垂直制表符
\x字符 x
\xnn十六进制表示法,其中 n 的范围为 0.9、 a.f 或 A.F

字符编码

Ruby 的默认字符集是 ASCII,字符可用单个字节表示。如果您使用 UTF-8 或其他现代的字符集,字符可能是用一个到四个字节表示。
您可以在程序开头使用$KCODE改变字符集,如下所示:

$KCODE = 'u'

下面是 $KCODE 可能的值。

编码描述
aASCII (与 none 相同)。这是默认的。
eEUC。
nNone (与 ASCII 相同)。
uUTF-8。

字符串内建方法

我们需要有一个 String对象的实例来调用 String方法。下面是创建 String对象实例的方式:

new [String.new(str="")]

这将返回一个包含 str 副本的新的字符串对象。
现在,使用 str 对象,我们可以调用任意可用的实例方法。例如:
实例

#!/usr/bin/ruby
 
myStr = String.new("THIS IS TEST")
foo = myStr.downcase
 
puts "#{foo}"

这将产生以下结果:

this is test

下面是公共的字符串方法(假设 str 是一个 String 对象):
尝试下面的实例,解压各种数据。

"abc \0\0abc \0\0".unpack('A6Z6')   #=> ["abc", "abc "]
"abc \0\0".unpack('a3a3')           #=> ["abc", " \000\000"]
"abc \0abc \0".unpack('Z*Z*')       #=> ["abc ", "abc "]
"aa".unpack('b8B8')                 #=> ["10000110", "01100001"]
"aaa".unpack('h2H2c')               #=> ["16", "61", 97]
"\xfe\xff\xfe\xff".unpack('sS')     #=> [-2, 65534]
"now=20is".unpack('M*')             #=> ["now is"]
"whole".unpack('xax2aX2aX1aX2a')    #=> ["h", "e", "l", "l", "o"]

Ruby 数组(Array)

Ruby 数组是任何对象的有序整数索引集合。数组中的每个元素都与一个索引相关,并可通过索引进行获取。

数组的索引从 0 开始,这与 CJava中一样。一个负数的索相对于数组的末尾计数的。
也就是说,索引为 -1 表示数组的最后一个元素,-2 表示数组中的倒数第二个元素,依此类推。
Ruby数组可存储诸如 StringIntegerFixnumHashSymbol等对象,甚至可以是其他 Array 对象。
Ruby 数组不需要指定大小,当向数组添加元素时,Ruby数组会自动增长。

创建数组

有多种方式创建或初始化数组。一种方式是通过 new 类方法:

names = Array.new

您可以在创建数组的同时设置数组的大小:

names = Array.new(20)

数组 names 的大小或长度为 20 个元素。您可以使用 size 或 length 方法返回数组的大小:
实例

#!/usr/bin/ruby
 
names = Array.new(20)
puts names.size  # 返回 20
puts names.length # 返回 20

以上实例运行输出结果为:

20
20

您可以给数组中的每个元素赋值,如下所示:

#!/usr/bin/ruby
 
names = Array.new(4, "mac")
puts "#{names}"

以上实例运行输出结果为:

["mac", "mac", "mac", "mac"]

您也可以使用带有 new 的块,每个元素使用块中的计算结果来填充:

实例
#!/usr/bin/ruby
 
nums = Array.new(10) { |e| e = e * 2 }
 
puts "#{nums}"

尝试一下 »
以上实例运行输出结果为:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

数组还有另一种方法,[],如下所示:

nums = Array.[](1, 2, 3, 4,5)

数组创建的另一种形式如下所示:

nums = Array[1, 2, 3, 4,5]

在 Ruby 核心模块中可以有一个只接收单个参数的 Array 方法,该方法使用一个范围作为参数来创建一个数字数组:

#!/usr/bin/ruby
 
digits = Array(0..9)
 
puts "#{digits}"

以上实例运行输出结果为:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

数组内建方法

我们需要有一个 Array 对象的实例来调用 Array 方法。下面是创建 Array 对象实例的方式:

Array.[](...) [or] Array[...] [or] [...]

这将返回一个使用给定对象进行填充的新数组。
现在,使用创建的对象,我们可以调用任意可用的方法。例如:

#!/usr/bin/ruby
digits = Array(0..9)
num = digits.at(6)
puts "#{num}"

以上实例运行输出结果为:

6

尝试下面的实例,压缩各种数据。

实例
a = [ "a", "b", "c" ]
n = [ 65, 66, 67 ]
puts a.pack("A3A3A3")   #=> "a  b  c  "
puts a.pack("a3a3a3")   #=> "a\000\000b\000\000c\000\000"
puts n.pack("ccc")      #=> "ABC"

以上实例运行输出结果为:

a  b  c
abc
ABC

Ruby 哈希(Hash)

哈希(Hash)是类似 "key" => "value"这样的键值对集合。哈希类似于一个数组,只不过它的索引不局限于使用数字。
Hash 的索引(或者叫"键")几乎可以是任何对象。
Hash 虽然和数组类似,但却有一个很重要的区别:Hash 的元素没有特定的顺序。 如果顺序很重要的话就要使用数组了。

创建哈希

与数组一样,有各种不同的方式来创建哈希。
您可以通过 new类方法创建一个空的哈希:

months = Hash.new

您也可以使用 new 创建带有默认值的哈希,不带默认值的哈希是nil

months = Hash.new( "month" )

months = Hash.new "month"

当您访问带有默认值的哈希中的任意键时,如果键或值不存在,访问哈希将返回默认值:

#!/usr/bin/ruby
 
months = Hash.new( "month" )
 
puts "#{months[0]}"
puts "#{months[72]}"

以上实例运行输出结果为:

month
month
#!/usr/bin/ruby
 
H = Hash["a" => 100, "b" => 200]
 
puts "#{H['a']}"
puts "#{H['b']}"

以上实例运行输出结果为:

100
200

您可以使用任何的 Ruby 对象作为键或值,甚至可以使用数组,如下实例所示:

[1,"jan"] => "January"

哈希内置方法

如果需要调用 Hash方法,需要先实例化一个 Hash对象。下面是创建 Hash 对象实例的方式:

Hash[[key =>|, value]* ] or
Hash.new [or] Hash.new(obj) [or]
Hash.new { |hash, key| block }

这将返回一个使用给定对象进行填充的新的哈希。
现在,使用创建的对象,我们可以调用任意可用的方法。例如:

#!/usr/bin/ruby
 
$, = ", "
months = Hash.new( "month" )
 
months = {"1" => "January", "2" => "February"}
 
keys = months.keys
 
puts "#{keys}"

以上实例运行输出结果为:

["1", "2"]

Ruby 日期 & 时间(Date & Time)

Time 类在Ruby 中用于表示日期和时间。它是基于操作系统提供的系统日期和时间之上。该类可能无法表示 1970 年之前或者 2038 年之后的日期

创建当前的日期和时间

下面是获取当前的日期和时间的简单实例:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
 
time1 = Time.new
 
puts "当前时间 : " + time1.inspect
 
# Time.now 功能相同
time2 = Time.now
puts "当前时间 : " + time2.inspect

尝试一下 »
以上实例运行输出结果为:

当前时间 : 2015-09-17 15:23:14 +0800
当前时间 : 2015-09-17 15:23:14 +0800

获取 Date & Time 组件

我们可以使用 Time 对象来获取各种日期和时间的组件。请看下面的实例:

#!/usr/bin/ruby -w
# -*- coding: UTF-8 -*-
 
time = Time.new
 
# Time 的组件
puts "当前时间 : " + time.inspect
puts time.year    # => 日期的年份
puts time.month   # => 日期的月份(1 到 12)
puts time.day     # => 一个月中的第几天(1 到 31)
puts time.wday    # => 一周中的星期几(0 是星期日)
puts time.yday    # => 365:一年中的第几天
puts time.hour    # => 23:24 小时制
puts time.min     # => 59
puts time.sec     # => 59
puts time.usec    # => 999999:微秒
puts time.zone    # => "UTC":时区名称

以上实例运行输出结果为:

当前时间 : 2015-09-17 15:24:44 +0800
2015
9
17
4
260
15
24
44
921519
CST

Time.utc、Time.gm 和 Time.local 函数

这些函数可用于格式化标准格式的日期,如下所示:

# July 8, 2008
Time.local(2008, 7, 8)  
# July 8, 2008, 09:10am,本地时间
Time.local(2008, 7, 8, 9, 10)   
# July 8, 2008, 09:10 UTC
Time.utc(2008, 7, 8, 9, 10)  
# July 8, 2008, 09:10:11 GMT (与 UTC 相同)
Time.gm(2008, 7, 8, 9, 10, 11)

下面的实例在数组中获取所有的组件:

[sec,min,hour,day,month,year,wday,yday,isdst,zone]

尝试下面的实例:

#!/usr/bin/ruby -w
time = Time.new
values = time.to_a
p values

以上实例运行输出结果为:

[39, 25, 15, 17, 9, 2015, 4, 260, false, "CST"]

该数组可被传到 Time.utc 或 Time.local 函数来获取日期的不同格式,如下所示:

#!/usr/bin/ruby -w
 
time = Time.new
 
values = time.to_a
puts Time.utc(*values)

以上实例运行输出结果为:

2015-09-17 15:26:09 UTC

下面是获取时间的方式,从纪元以来的秒数(平台相关):

# 返回从纪元以来的秒数
time = Time.now.to_i  
 
# 把秒数转换为 Time 对象
Time.at(time)
 
# 返回从纪元以来的秒数,包含微妙
time = Time.now.to_f

时区和夏令时

您可以使用Time对象来获取与时区和夏令时有关的所有信息,如下所示:

time = Time.new
# 这里是解释
time.zone       # => "UTC":返回时区
time.utc_offset # => 0:UTC 是相对于 UTC 的 0 秒偏移
time.zone       # => "PST"(或其他时区)
time.isdst      # => false:如果 UTC 没有 DST(夏令时)
time.utc?       # => true:如果在 UTC 时区
time.localtime  # 转换为本地时区
time.gmtime     # 转换回 UTC
time.getlocal   # 返回本地区中的一个新的 Time 对象
time.getutc     # 返回 UTC 中的一个新的 Time 对象

格式化时间和日期

有多种方式格式化日期和时间。下面的实例演示了其中一部分:

#!/usr/bin/ruby -w
time = Time.new
 
puts time.to_s
puts time.ctime
puts time.localtime
puts time.strftime("%Y-%m-%d %H:%M:%S")

以上实例运行输出结果为:

2015-09-17 15:26:42 +0800
Thu Sep 17 15:26:42 2015
2015-09-17 15:26:42 +0800
2015-09-17 15:26:42

时间算法

您可以用时间做一些简单的算术,如下所示:

now = Time.now           # 当前时间
puts now
 
past = now - 10          # 10 秒之前。Time - number => Time
puts past
 
future = now + 10        # 从现在开始 10 秒之后。Time + number => Time
puts future
 
diff = future - now      # => 10  Time - Time => 秒数
puts diff

以上实例运行输出结果为:

2015-09-17 15:27:08 +0800
2015-09-17 15:26:58 +0800
2015-09-17 15:27:18 +0800
10.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值