[翻译]Ruby教程9——控制流

控制流

这章的教程我们将讨论控制流。


条件和循环改变了Ruby程序的流程。条件式是执行条件语句下面的特定语句。循环是执行多次的代码块。程序开始后,语句从源文件顶部到底部一行一行的执行。


if语句


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


#!/usr/bin/ruby

num = gets.to_i

if num > 0 then

puts “num variable is positive”
puts “num variable equals to #{num}”
end

输入一个数字,如果这个数字大于0则打印两条消息,否则什么也不做。


$ ./simpleif.rb

4

num variable is positive

num variable equals to 4


条件为真并且消息在终端上打印了。




我们可以使用else关键字不创建一个简单的分支。如果if关键字后的表达式求值为假,那么else后面的语句将自动执行。这些代码使用end关键字闭合起来。


#!/usr/bin/ruby

age = 17

if age > 18

puts “Driving licence issued”
else

puts “Driving licence not permitted”
end

这里创建了一个age变量,布尔表达式求值为假,因此在终端上打印”Driving licence not permitted”。


$ ./licence.rb

Driving licence not permitted


我们可以使用elsif关键字创建多个分支。仅当前一个条件不为真时elsif关键字才会测试另一个条件。注意我们可以使用多个elsif关键字。


#!/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

创建一个数字变量判断它是正数、负数还是0。根据输入值的不同将打印不同的消息。


case语句


case语句是一个程序控制流语句。它允许一个变量或者表达式的值控制程序的执行流程。相比ifelsif它创建多分支更简单。


我们创建一个变量或者表达式。case关键字用于针对一个列表的值测试这个变量或者表达式的值。这个列表的值是使用when关键字呈现出来。如果值匹配,那么when关键字后面的语句将执行。有一个可选的else语句,如果没有匹配的它将执行。


#!/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

这个程序中我们创建了一个domain变量,它的值从命令行读取。使用when语句测试这个变量的值。这有些选项。如果值等于”us”则打印”United States”字符串。


domain = gets.chomp

我们使用gets方法获取一个输入值。使用chomp方法去掉换行符。


$ ./domains.rb

Enter top level domain: hu

Hungary


我们输入”hu”,程序返回”Hungary”。


while、until语句


while语句是一个控制流语句允许代码多次执行。当的条件为真时代码将执行。


while关键字执行使用end闭合的代码块语句。每次表达式为真时这些语句将执行。


#!/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

初始化变量isumi用于计数。


while i < 10  do

end

whiledo之间的表达式是第二阶段,测试。注意do关键字是可选的。,内部的语句将会执行直到表达式的值为假。


i = i + 1

这是循环的第三阶段——更新。我们增加计数值。注意不当的处理会导致死循环。


$ ./while.rb

The sum of 0..9 values is 55


This is the output of the example.




当条件为假时until控制流语句将执行。当条件为真时循环停止。


#!/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。我们开始计数,每次循环打印还有几个小时。当变量值等于0时循环停止。


$ ./until.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


程序运行的结果。


for语句


当循环次数是已知时,我们可以使用for语句。for循环使用in接着一个范围。对这个范围的每个元素都执行代码块的语句。这些语句使用end关键字闭合。do关键字是可选的。


#!/usr/bin/ruby

for i in 0..9 do

puts “#{i}”
end

这个例子中我们打印了0到9的数。每次循环i变量保存了这个范围的一个数,这个数将在终端上打印。


$ ./forloop.rb

0

1

2

3

4

5

6

7

8

9


例子运行结果。




要遍历一个数组的元素可以使用数组的length方法。


#!/usr/bin/ruby

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

for i in 0…planets.length

puts planets[i]
end

这个例子中我们创建了一个数组planets,我们遍历这个数组打印这个数组的每个元素。


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

planets数组。


for i in 0…planets.length

length方法返回数组的长度。数组从0开始,最后一个索引是n-1。


puts planets[i]

打印数组指定的一个元素。


$ ./planets2.rb

Mercury

Venus

Earth

Mars

Jupiter

Saturn

Uranus

Neptune


程序的运行结果。


each方法


在Ruby中我们可以使用each方法遍历数组的每个元素。它接受两个参数。一个元素和一个代码块。元素放在管道之间,它保存了当前循环的数据项。代码块是每次要执行的内容。


#!/usr/bin/ruby

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

planets.each do |planet|

puts planet
end

这个例子我们使用each迭代器遍历planets数组。


planets.each do |planet|

puts planet
end

each迭代器是planets数组的一个方法。planet保存了此次迭代的数据项。我们可以使用任何我们想使用的字符。我们可以使用{}代替doend关键字。


break、next语句


break语句用于终止whilefor或者case的代码块语句。


#!/usr/bin/ruby

while true

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

if r == 22
break
end
end

puts

我们定义了一个无限循环,使用break语句退出这个循环。我们选择1到30的数,打印它。如果等于22则结束while循环。


while true

end

这是一个无限循环,while的条件总是为真。退出无限循环的唯一方法是使用break


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

计算从1到30的随机数,并将其打印。


if r == 22
break
end

如果数等于22,结束循环。


$ ./break.rb

20 14 6 26 30 12 2 10 18 29 28 11 30 26 20 22


可能的输出结果。




next语句用于跳过此次循环,继续下次循环。它可与forwhile联合使用。


接下来的例子我们打印不能被2整除的数一列表。


#!/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

如果这个数可以被2整除,next语句将执行,循环的其余将跳过。


$ ./next.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


程序的输出结果。


redo语句


redo语句重新开始循环而不检查循环的条件式。下面的例子有点复杂,它展示了redo语句和其它的一些特性。


#!/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

这是一个简单的Rock-paper-scissors游戏。这个例子中我们用到了redo语句、条件式、随机数、数组和输入。


options = [“rock”, “scissors”, “paper”]

定义了游戏可能用到的选项数组。这三个词在打印消息时会用到。


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

使用定界符在终端上打印一个菜单。菜单在每次游戏循环时都打印。


val = gets.to_i

r = rand(3) + 1

这几行代码从终端输入一个值,然后选择一个1、2、3的随机数。


if val == 9
puts “End”
exit
end

如果输入为9,打印’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”


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


$ ./redo.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教程我们谈论了结构控制流。




原文地址: http://zetcode.com/lang/rubytutorial/flowcontrol/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程8——表达式

表达式

在这章的教程将介绍Ruby的表达式。


表达式是由操作数和操作符构成的。表达式的操作符表明了对操作数应用什么操作。表达式中操作符的求值顺序由操作符的优先级和结合律决定的。


操作符是一个特殊的符号表明了要执行的确切操作。编程语言中的操作符取自数学运算。程序员使用数据,操作符用于处理数据。操作数是操作符的参数。


以下表格中按优先级展示Ruby的操作符(高优先级在前):



















































































分类 符号
解析,访问操作符 :: .
数组操作符 [] []=
求幂
非,反,一元加、减 ! ~ + -
乘、除、模 / %
加、减 + -
移位 << >>
位与 &
位或、逻辑或 ^ |
关系运算 > >= < <=
相等、模式匹配 <=> == === != =~ !~
逻辑与 &&
逻辑或 ||
范围操作符 .. …
三目运算 ?:
分配操作 = += -= = = /= %= &= |= ^= <<= >>= ||= &&=
否定 not
逻辑或、与 or and


同一行的操作符具有相同的优先级。


一个操作符通常有两个操作数。那些只有一个操作数的操作符称为一元操作符。有两个操作数的称为二元操作符。有一个三元操作符(?:)有三个操作数。


操作符可能用于不同的上下文。例如+操作符,从上面的表格可知它能用于不同情况。数字求和、连接字符串、作为数字的符号。我们称这个操作符被重载了。


正负号操作符


有两个正负号操作符,+和-,用于指定或者修改值的符号。


#!/usr/bin/ruby

puts +2
puts -2

+和-指明了值的符号。加号表明是正数,通常可省略。




接下来的例子我们使用减号。


#!/usr/bin/ruby

a = 1

puts a
puts -(a)
puts -(-(a))

减号改变了值的符号。


$ ./sign.rb

1

-1

1


输出结果。


分配操作符


分配操作符=将一个值分配给一个变量。变量是这个值的点位符。数学运算中=操作符有不同的意义。在方程式中=是相等操作,左边的值等于右边的值。


x = 1
puts x # prints 1

这里分配的一个数字给x变量。


x = x + 1
puts x # prints 2

前一个表达式中数学运算中是行不通的。但是在程序中是合法的。这个表达式是将x变量加1,右边等于2,并把2赋值给x。


3 = x;

这个语法是错误的,我们不能组值分配字面符。


解析,成员访问操作符


有两个操作符具有最高的优先级,这意味着它们总是先求解。


#!/usr/bin/ruby

class MyMath
Pi = 3.1415926535
end

module People
Name = “People”
end

puts MyMath::Pi
puts People::Name

第一个例子展示了::命名空间解析操作符。它可以访问一个定义在其它类或模块里的常量、模块或者类。它用于提供命名空间,这样方法和类的名字就不会与其他作者的类冲突了。


class MyMath
Pi = 3.1415926535
end

module People
Name = “People”
end

这里创建了一个模块的一个类,分别定义了一个常量。


puts MyMath::Pi
puts People::Name

我们使用::操作符访问它们的常量。


$ ./resolution.rb

3.1415926535

People


resolution.rb脚本的输出结果。




点(.)操作符是成员访问,用于调用对象的方法。


#!/usr/bin/ruby

class Person

def initialize name, age
@name = name
@age = age
end

def info
“#{@name} is #{@age} years old”
end

end

p = Person.new “Jane”, 17
puts p.info

puts “ZetCode”.reverse

这个例子中我们创建了两个对象,一个是用户定义的,一个是预定义的。我们对这些对象使用点操作符。


p = Person.new “Jane”, 17
puts p.info

在这行使用点操作符调用了两个方法:new和info。


puts “ZetCode”.reverse

字符串是内建对象,具有一个reverse方法。


$ ./memberaccess.rb

Jane is 17 years old

edoCteZ


输出结果。


字符串连接


Ruby中+操作符同样可以用于字符串连接。在不同上下文中操作符作用不同,我们称这个为重载。


#!/usr/bin/ruby

puts “Return “ + “of “ + “the “ + “King”
puts “Return “.+”of “.+ “the “.+”King”

我们将三个字符串连接在一起。


puts “Return “ + “of “ + “the “ + “King”

我们使用+操作符连接字符串。


puts “Return “.+”of “.+ “the “.+”King”

+操作符也是Ruby的一个方法。我们可以使用访问操作符(.)来调用它。


$ ./catstrings.rb

Return of the King

Return of the King


catstrings.rb程序的运行结果。


增、减操作符


Ruby中没有如下操作。

x++;



y–;


这些是C语言的增、减操作。


如果你熟悉Java、C、C++,你可能了解这些操作符。但是这些在Ruby中无效的。同样在Python中也没有。


算术操作符


下面的表格是Ruby中的算术操作符。



































符号名字
+
-
/
%
**

下面的例子中我们使用了算术操作符。


#!/usr/bin/ruby

a = 10
b = 11
c = 12

puts a + b + c
puts c - a
puts a b
puts c / 3
puts c % a
puts c a

在前面的例子我们使用了加、减、乘、除和取余操作。这些与数学上的是相同的。


puts c % a

%操作符是取余或者求模。


$ ./arithmetic.rb

33

2

110

4

2

61917364224


输出结果。




接下来展示整数和浮点数除法的区别。


#!/usr/bin/ruby

puts 5 / 2

puts 5 / 2.0
puts 5.0 / 2
puts 5.to_f / 2

上面的例子我们将两个数相除。


puts 5 / 2

这个表达式中的操作数都是整数,我们进行的是整数相除。结果返回的也是整数。


puts 5 / 2.0
puts 5.0 / 2
puts 5.to_f / 2

如果其中一个或两个是浮点数,我们进行的是浮点数相除。


$ ./division.rb

2

2.5

2.5

2.5


division.rb程序的运行结果。




Ruby有其他方式进行除运算。这些都是有效的方法调用。


#!/usr/bin/ruby

puts 5.div 2.0
puts 5.fdiv 2
puts 5.quo 2
puts 5.0.quo 2.0

上面例子中我们使用了divfdivquo方法。


puts 5.div 2.0

div总是进行整数除,即使操作数是浮点数。


puts 5.fdiv 2

fdiv总是进行浮点数除法。


puts 5.quo 2
puts 5.0.quo 2.0

quo方法进行精确的除法。如果操作数是浮点数则返回浮点数,否则是有理数。


$ ./otherdivision.rb

2

2.5

5/2

2.5


布尔操作符


Ruby中有以下布尔操作符。























符号 名字
&& 逻辑与
|| 逻辑或
!


布尔操作符处理真假值。Ruby中有额外的布尔操作符,andor&not。它们操作是相同的,只是优先级低一些。与Perl语言不同,这需要一个低优先级的布尔操作符。


#!/usr/bin/ruby

x = 3
y = 8

puts x == y
puts y > x

if y > x then
puts “y is greater than x”
end

许多表达式的结果都是一个布尔值。布尔值用于条件语句。


puts x == y
puts y > x

返回布尔值的相关操作符。这两行打印为false和true。


if y > x then
puts “y is greater than x”
end

仅当月if条件为真时if里的语句才会执行。x > y返回true,因此”y is greater than x”会在终端上打印。




下面的例子展示逻辑与操作符。


#!/usr/bin/ruby

puts true && true
puts true && false
puts false && true
puts false && false

与操作只有在操作数都为true才返回true。


$ ./andoperator.rb

true

false

false

false


只有一个表达式的结果为true。




逻辑或操作符当有一个操作数为true则返回true。


#!/usr/bin/ruby

puts true || true
puts true || false
puts false || true
puts false || false

如果有一边是true,操作的结果就是true。


$ ./oroperator.rb

true

true

true

false


三个表达式结果为true。




非操作进行真假反转。


#!/usr/bin/ruby

puts !0
puts !1
puts !true
puts !false

puts ! (4<3)
puts ! “Ruby”.include?(“a”)

这个例子展示了非操作符的用法。


$ ./not.rb

false

false

false

true

true

true


输出结果。




||&&操作符是短路求值(short circuit evaluated)。短路求值意味着只有在第一个参数不足以确定表达式的值时第二个参数才会进行求值。短求值主要用于提高执行效率。


用一个例子解释。


#!/usr/bin/ruby

def one
puts “Inside one”
false
end

def two
puts “Inside two”
true
end

puts “Short circuit”

if one && two
puts “Pass”
end

puts “##############################”

if two || one
puts “Pass”
end

在例子中定义了两个方法,用于在布尔操作中作为操作数。我们将看到它们是否被调用了。


if one && two
puts “Pass”
end

第一个方法返回false,短路求值不会计算第二个方法。一旦一个操作数是false,那么这个逻辑的结果总是false。


puts “##############################”

if two || one
puts “Pass”
end

第二种情况我们使用||操作符,并且第一个操作数为tow方法。这里同样没有必要对第二个操作数求值,只要第一个操作数为true,那么逻辑或总是为true。


$ ./shortcircuit.rb
Short circuit
Inside one
##############################
Inside two
Pass

shortcircuit.rb程序的运行结果。


关系操作符


关系操作符用于值的比较,其总是返回布尔值。



























符号含义
<小于
<=小于等于
>大于
>=大于等于

关系操作符又称为比较操作符。


#!/usr/bin/ruby

p 3 < 4
p 3 > 5
p 3 >= 3

表达式3 < 4返回true,因为3小于4。表达式3 > 5返回false,因为3不大于5。


位操作符


人类用的是十进制数字,计算机原生的是二进制数。二进制、八进制、十进制和十六进制只是数字的符号。位操作符针对的是二进制数。



































符号 含义
~ 按位取反
^ 按位异或
& 按位与
| 按位与或
<< 左移位
>> 右移位


位操作在高级语言中很少使用。


#!/usr/bin/ruby

puts ~ 7 # prints -8
puts ~ -8 # prints 7

puts 6 & 3 # prints 2
puts 3 & 6 # prints 2

puts 6 ^ 3 # prints 5
puts 3 ^ 6 # prints 5

puts 6 | 3 # prints 7
puts 3 | 6 # prints 7

puts 6 << 1 # prints 12
puts 1 << 6 # prints 64

puts 6 >> 1 # prints 3
puts 1 >> 6 # prints 0

上面的例子中展示了这6个位操作符。


puts ~ 7   # prints -8
puts ~ -8 # prints 7

按位取反是将1变为0,0变为1。将操作会将数字7所有的位都反转,同样包括符号位。如果再次反转所有的位即会得到数字7。


puts 6 & 3  # prints 2
puts 3 & 6 # prints 2

按位与是将两个数进行逐位与操作,只有两个数对应位的都为1结果才为1。


puts 6 ^ 3  # prints 5
puts 3 ^ 6 # prints 5

按位异或是将两个数进行逐位异或操作,只要其中一个数(但不是全部)对应位的为1结果就为1。


puts 6 | 3  # prints 7
puts 3 | 6 # prints 7

按位或是将两个数进行逐位或操作,只要其中一个数对应位的为1结果就为1。


puts 6 << 1  # prints 12
puts 1 << 6 # prints 64

puts 6 >> 1 # prints 3
puts 1 >> 6 # prints 0

移位操作符是按位进行右移或左移,也称为算术移位。


复合分配操作符


复合分配操作符是由两个操作符构成。它们是简写操作符。


#!/usr/bin/ruby

a = 0

a = a + 1
a += 1
puts a


b = 0

b = b - 8
b -= 8
puts b

+=-=操作符是一个简写的操作符。它们的可读性没有全写的好,但是有经验的程序员经常使用它们。


a = a + 1
a += 1

这两行的操作是一样的,都是将变量a加1。


其他的一些复合操作符。


-=   *=  =  /=   %=   &=   |=   <<=   >>=

操作符优先级


操作符的优先级表明了先对哪个操作符进行求值。优先级避免了表达式的二义性。


这个表达式的结果是多少?28还是40?


3 + 5 5


跟数学相同,乘法优先级高于加法,加些结果为28。


(3 + 5) 5


我们可以使用括号来改变优先级。括号里的表达式总是最先求值。


#!/usr/bin/ruby

puts 3 + 5 5
puts (3 + 5)
5

puts ! true | true
puts ! (true | true)

这个例子展示了一些表达式,其结果依赖于操作符优先级。


puts 3 + 5  5

这行打印28,因为乘法操作优先级高于加法。


puts ! true | true

这里非操作优先级更高。最后返回为true。


$ ./precedence.rb

28

40

true

false


结合律


有时优先级不能决定表达式的结果。还有另一条规则称为结合律。它决定相同优先级的求值顺序。


9 / 3 3


这个的结果是多少?9还是1?乘、除和取模操作是从左到右结合的。因此结果为9。


数学运算、布尔、关系和位操作都是从左向右结合的。


另外赋值操作是右结合。


a = b = c = d = 0
print a, b, c, d # prints 0000

复合分配操作是从右向左结合的。


j = 0
j *= 3 + 1
puts j

你可能期望结果为1,但是实际上结果为0。由于结合律,右边表达式先求值再应用复合分配操作。


范围操作符


Ruby有两个范围操作符,用于创建一个范围对象。通常是数字或者字母的范围。


..范围操作符(两个点)创建一个包含的范围。操作符(三个点)创建一个非包含的范围,较大的值不包含在其中。


#!/usr/bin/ruby

p (1..3).to_a
p (1…3).to_a

p (‘a’ .. ‘l’).to_a

这个例子中我们使用范围操作符创建了数字范围和字母范围。


p (1..3).to_a
p (1…3).to_a

这两行都是使用范围操作符创建了两个范围,然后转换为数据。第一个范围的值为1,2,3;第二个为1和2.


p (‘a’ .. ‘l’).to_a

这里使用..操作符创建一个’a’到’l’的数组。


$ ./range.rb

[1, 2, 3]

[1, 2]

[“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”, “i”, “j”, “k”, “l”]


输出结果。


三元运算术


三元运算术是一个条件操作。如果我们需要根据条件表达式从两个值选择一个时这是一个方便的操作。


cond-exp ? exp1 : exp2


如果cond-exp为真则返回exp1,否则返回exp2


#!/usr/bin/ruby

age = 32

adult = age >= 18 ? true : false

if adult then
puts “Adult”
else
puts “Not adult”
end

许多国家成年是基于你的年龄。是否成年即为是否超过了一定年龄。这种情况适合于三元操作。


adult = age >= 18 ? true : false

首先对赋值符右转进行求值,它的值将赋给adult变量。


$ ./ternary.rb

Adult


32年已经成年了。


计算素数


我们将计算素数。


#!/usr/bin/ruby

nums = (4..50).to_a

puts “Prime numbers:”

print “2 3 “

nums.each do |i|

not_prime = false

(2..Math.sqrt(i).ceil).each do |j|
not_prime = true if i % j == 0
end

print i, “ “ unless not_prime

end

puts

上面的例子中我们用到了一些操作符。


nums = (4..50).to_a

我们将从这些数中计算哪些是素数。


print “2 3 “

我们路过2和3,因为它们都是素数。


not_prime = false

not_prime标志表明选择的数不是素数。我们假设选择的数是素数,直到被证明不是为止。


(2..Math.sqrt(i).ceil).each do |j|
not_prime = true if i % j == 0
end

当取模的结果为0表示这个数不是素数。


print i, “ “ unless not_prime

如果not_prime标志没有设置则打印这个数。




上面例子展示了一些操作符。实际上有更简单方法计算素数。Ruby中有一个计算素数的模块。


#!/usr/bin/ruby

require ‘prime’

Prime.each(50) do |i|
print i, “ “
end

puts

使用Ruby的prime模块计算素数。


require ‘prime’

导入prime模块。


Prime.each(50) do |i|
print i, “ “
end

计算到50的素数。


$ ./primes.rb

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47


结果输出了2到50之间的素数。


这章的教程介绍了表达式。




原文地址: http://zetcode.com/lang/rubytutorial/expressions/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程7——字符串

字符串

在这部分的教程将详细的介绍字符串。


字符串是计算机语言中最重要的数据类型之一,这就是为什么我们决定要用一整章来介绍字符串。


字符串是序列化的unicode字符。它是一种数据类型存储了序列化的值,它的元素通常代表的是根据字符编码的字符。当一个字符串在代码中以字面量出现,它也称为字符串文本。


第一个例子


在Ruby中字符串文本是以单引号或者双引号引起来的。


#!/usr/bin/ruby

# first.rb

puts ‘Python language’
puts “Ruby language”

这个例子有两个字符串,第一个是用单引号,另一个是用双引号。


$ ./first.rb

Python language

Ruby language


程序输出。


使用引号


如果我们想要显示引号该怎么做,直接引用?这有两种方法实现。


#!/usr/bin/ruby

puts “There are many stars”
puts “He said, \”Which one is your favourite?\””

puts ‘There are many stars’
puts ‘He said, “Which one is your favourite?”‘

我们使用()字符将引号转义。通常双引号是用于划定字符串的范围,然后被转义之后它原始的意义就没有了。它在字符串中被作为一个正常的字符。第二种方法是混合使用单引号和双引号。


$ ./quotes.exe

There are many stars.

He said, “Which one is your favourite?”


输出结果。


转义序列


转义符是特殊的字符,在字符串中有特殊的含意。


#!/usr/bin/ruby

puts “one two three four”
puts “one\ntwo\nthree\nfour”

最常用一个的转义符是换行符\n。它在许多编程语言中都有效。换行符之后的字符将出现在新的一行。


$ ./newline.rb

one two three four

one

two

three

four


以上脚本的输出结果中换行符之后的字符在新的一行。




rbt是正常的字符,当前面加上\字符后就具有特殊意义了。


#!/usr/bin/ruby

puts “ bbb\raaa”
puts “Joan\b\b\bane”
puts “Towering\tinferno”

这个例子中我们用到了三个不同的转义字符。


puts “   bbb\raaa”

回车符\r控制之后的字符回到行首。之前打印到终端上的字符串会被处理。这个转义字符会将aaa字符位于bbb之前,输出为aaabbb


puts “Joan\b\b\bane”

\b是退格控制符,它会删掉前一个字符。这个字符串将在终端上打印‘Jane’而不是‘Joan’


puts “Towering\tinferno”

最后\t转义符是用于两个词之间制表空格的。


$ ./escapes.rb

aaabbb

Jane

Towering inferno


例子的输出结果。




反斜杠\是用于创建转义符的特殊字符。当需要打印反斜杠时,则在它前面加上另一个反斜杠。这意味着转义过了可以打印。在Ruby中单引号和双引号用于划定字符串范围的,想要打印它们同样也需要在前面加上\


#!/usr/bin/ruby

puts “The special character \“
puts “The special character \’”
puts “The special character \””

这个例子中我们在终端上打印了这三个字符。


$ ./specials.rb

The special character \

The special character ‘

The special character “


输出结果。


访问字符串的元素


在Ruby中我们可以使用方括号[]来访问字符串的元素。在括号内可以使用字符串、范围索引。


#!/usr/bin/ruby

msg = “Ruby language”

puts msg[“Ruby”]
puts msg[“Python”]

puts msg[0]
puts msg[-1]

puts msg[0, 3]
puts msg[0..9]
puts msg[0, msg.length]

这个例子的代码展示了我们可以访问字符串的一部分。


msg = “Ruby language”

这里是我们将要访问的字符串。


puts msg[“Ruby”]

这行代码我们测试字符串‘Ruby’是否是msg的子串。如果是将返回该字符串。


puts msg[0]

可以通过索引来访问这个字符串的字符。编号是从0开始的,也就是说0号索引是第1个字符。msg[0]返回字符串的第一个字符R


puts msg[-1]

这里我们访问最后一个字符。-1代表了最后一个索引。


puts msg[0, 3]

两个用逗号分隔的索引返回了从第1个索引开始到第2个索引的字符,不包括第2个索引。


puts msg[0..9]

范围操作符也可以完成同样操作。这里我们打印前10个字符。


puts msg[0, msg.length]

这行返回全部的字符。msg.length返回字符串的长度。


$ ./access.rb

Ruby


R

e

Rub

Ruby langu

Ruby language


输出结果。


多行字符串


许多编程语言要创建多行字符串需要额外的努力,在Visual Basic中尤其如此。但是在Ruby中却是很容易。


#!/usr/bin/ruby

puts “I hear Mariachi static on my radio
And the tubes they glow in the dark
And I’m there with her in Ensenada
And I’m here in Echo Park


puts %/
Carmelita hold me tighter
I think I’m sinking down
And I’m all strung out on heroin
On the outskirts of town/

puts <<STRING

Well, I’m sittin’ here playing solitaire
With my pearl-handled deck
The county won’t give me no more methadone
And they cut off your welfare check
STRING

这个例子中我们使用了Carmelita歌曲的歌词。我们展示了使用三种方法打印多行字符串。可以使用双引号;可以使用%字符创建多行字符串,用%后面的字符将字符串包围住;最后我们使用定界符,这和语法是使用<<接着一些字符串,用这个字符串包围住多行字符。它必须左对齐。


变量替换


变量替换是将字符串的变量替换成它们的值。为了将变量替换成值,这个变量在字符串需要放在#{}之间。


#!/usr/bin/ruby

name = “Jane”
age = 17

puts “#{name} is #{age} years old”

这个例子中我们替换了字符串中的两个变量:nameage


$ ./interpolation.rb

Jane is 17 years old




也可以替换表达式。


#!/usr/bin/ruby

x = 5
y = 6

puts “The product of #{x} and #{y} is #{xy}”

这是一个表达式替换的例子。


$ ./interpolation2.rb

The product of 5 and 6 is 30


运行例子脚本。




这是另一种替换变量的方法。类似于Python 2.x所支持的替换。


#!/usr/bin/ruby

name = “Jane”
age = 17

message = “%s is %d years old” % [name, age]
puts message

以上是一个例子。


message = “%s is %d years old” % [name, age]

使用之前先创建一个字符串。%s%d是格式化字符,分别表示字符串和数字。值由%字符后面的方括号提供。


字符串连接


字符串连接是从多个字符串创建一个字符串。


#!/usr/bin/ruby

lang = “Ruby” + “ programming” + “ languge”
puts lang

lang = “Python” “ programming” “ language”
puts lang

lang = “Perl” << “ programming” << “ language”
puts lang

lang = “Java”.concat(“ programming”).concat(“ language”)
puts lang

Ruby提供多种方法连接字符串。


lang = “Ruby” + “ programming” + “ languge”

在计算机语言中加法操作符是最常用的一种。Perl和PHP是用的点操作符(.)。


lang = “Python” “ programming” “ language”

Ruby自动连接多个后续的字符串。


lang = “Perl” << “ programming” << “ language”

另一种方法是使用<<操作符。


lang = “Java”.concat(“ programming”).concat(“ language”)

每个字符串字面符实际上都是一个对象。我们可以对Ruby对象调用很多方法。对于字符串对象可以调用concat方法连接两个字符串。它返回最后的结果对象,再对其调用另一个方法。这样我们就将这些方法链接起来了。


$ ./concatenate.rb

Ruby programming languge

Python programming language

Perl programming language

Java programming language


输出结果。


冻结字符串


在Java或者C#中字符串是不可变的,这意味着不能修改已存在的字符串。只能通过已存在的字符串创建一个新的。在Ruby中字符串同样也是不可修改的。


Ruby中字符串对象有一个freeze方法,可以使它们不可变。


#!/usr/bin/ruby

msg = “Jane”
msg << “ is “
msg << “17 years old”

puts msg

msg.freeze

#msg << “and she is pretty”

这个例子我们演示了字符串是可变的。然后在调用freeze方法之后我们就不能再作修改了。如果我们取消掉注释将会得到’can’t modify frozen string’错误信息。


字符串比较


在编程中字符串比较是件平常的事情。我们可以使用==操作符或者eql?方法来比较两个字符串,如果相等返回true,否则false


#!/usr/bin/ruby

puts “12” == “12”
puts “17” == “9”
puts “aa” == “ab”

puts “Jane”.eql? “Jan”
puts “Jane”.eql? “Jane”

这个例子的代码我们比较了一些字符串。


puts “12” == “12”

这两个是相等的,这行返回true。


puts “aa” == “ab”

第一个字符是相等,然后比较下一个字符。它们不同,因此返回false。


puts “Jane”.eql? “Jan”

eql?方法用于比较两个字符串。所有对象都内建了eql?方法。这个方法将另一个要比较的字符串作为参数传入。


$ ./comparing.rb

true

false

false

false

true


程序输出结果。




Ruby中有一个“飞船(spaceship)”操作符<==>。这个操作符来自Perl,与以上两个比较方法不同,它不是返回truefalse,而是返回1、0或者-1。取决于左参数和右参数的关系。如果左参数大于右参数则返回1;如果左参数小于右参数则返回-1;如果相等返回0。什么才是一个字符大于另一个字符呢?字符在表中是有序的,在表中每个字符有一位位置。当比较字符时实际比较它们在表中的位置。例如ASCII表,字符ab的前面,因此a<==>b返回-1,因为左参数的位置小于右参数b


#!/usr/bin/ruby

puts “a” <==> “b”
puts “b” <==> “a”
puts “a” <==> “a”

使用“飞船”操作符比较字符串。


$ ./spaceship.rb

-1

1

0


输出结果。




有可能比较字符串不管大小写。在Ruby中有casecmp方法。这个方法与飞船操作符相同。


#!/usr/bin/ruby

puts “Jane”.casecmp “Jane”
puts “Jane”.casecmp “jane”
puts “Jane”.casecmp “Jan”

以上是一个例子。


puts “Jane”.casecmp “Jane”
puts “Jane”.casecmp “jane”

这两行返回结果都是0.因为我们不考虑字符的大小写。


$ ./case.rb

0

0

1


输出结果。


字符串对象


Ruby是面向对象语言。对象是面向对象程序的基本代码块。字符串也是对象。对象由数据和方法组成。在面向对象程序中,创建对象并且相互通信。


#!/usr/bin/ruby

website = “google.com”
puts website

website = String.new “zetcode.com”
puts website

以上例子我们展示了两个创建字符串的基本方法。


website = “google.com”

这里是使用字符串字面量创建了一个website字符串变量。


website = String.new “zetcode.com”

这是标准创建字符串对象的方法。然而第一和更常用,因为它更简洁,并且在计算机语言中更普遍。




#!/usr/bin/ruby

puts “zetcode”.upcase
puts “zetcode”.size
puts “zetcode”.reverse

这个例子中我们对字符串字面量调用了三个方法。如果是熟悉Java或者C的人可能会困惑。在Ruby中调用方法时字符串字面量会转化为一个字符串对象。


$ ./stringobject2.rb

ZETCODE

7

edoctez


输出结果。


字符串方法


Ruby字符串对象有一些有用的方法。如我们见到过的concat或者eql?


#!/usr/bin/ruby

word = “Determination”

puts “The word #{word} has #{word.size} characters”

puts word.include? “tion”
puts word.include? “tic”

puts

puts word.empty?
word.clear
puts word.empty?

创建一个字符串变量,展示了四个字符串的方法。


puts “The word #{word} has #{word.size} characters”

size方法返回字符串的长度。


puts word.include? “tion”

include?方法判断一个字符串是否为子串。这里返回的是true。


puts word.empty?
word.clear

empty?方法检查字符串是否为空。返回一个布尔值。clear方法清空字符串。


$ ./basicmethods.rb

The word Determination has 13 characters

true

false


false

true


输出结果。




接下来的例子介绍字符串大小写的方法。


#!/usr/bin/ruby

ruby = “Ruby programming language”

puts ruby.upcase
puts ruby.downcase
puts ruby.capitalize
puts ruby.swapcase

Ruby中有四个与大小写相关的方法。upcase方法将字符串全转为大写并返回一个新对象;downcase方法是将字符串全转为小写并返回一个新对象;capitalize方法是将字符串的首字母大写并返回一个新的对象。最后swapcase方法是将大小写反转并返回一个新对象。


$ ./rubylang.rb

RUBY PROGRAMMING LANGUAGE

ruby programming language

Ruby programming language

rUBY PROGRAMMING LANGUAGE


输出结果。




接下来展示两个Ruby字符串的方法:start_with?end_with?。这两个方法都是返回布尔值。它们判断一个字符串是否分别以另一个字符串开头或结尾。


#!/usr/bin/ruby

ws1 = “zetcode.com”
ws2 = “www.gnome.org”

puts ws1.start_with? “www.”
puts ws2.start_with? “www.”

puts

puts ws1.end_with? “.com”
puts ws2.end_with? “.com”

这是一个上述方法的例子。


puts ws1.start_with? “www.”

这里检查一个字符串是否以“www.”开头。如果不是则在终端打印false。


puts ws1.end_with? “.com”

检查字符串ws1是否以”.com”结尾。如果是则在终端打印true。


$ ./startend.rb

false

true


true

false


输出结果。




接下来我们介绍inspect方法。这个方法返回被引号包围原始的字符串,对于特殊字符不处理。对于想要检查字符串由哪些字符组成的比较有用。


#!/usr/bin/ruby

msg = “Jane\t17\nThomas\t23”

puts msg
puts msg.inspect

inspect方法的一个例子。


msg = “Jane\t17\nThomas\t23”

这个字符串有一些特殊的字符。


puts msg
puts msg.inspect

第一种情况,字符串中的制表符和换行符被解释了。第二种情况我们得到了一个原始格式的字符串。


$ ./inspectmethod.rb
Jane 17
Thomas 23
“Jane\t17\nThomas\t23”

输出结果。




chomp方法是将字符串尾部的分隔符去掉并返回一个新对象。默认的分隔符是换行符(\n)。


#!/usr/bin/ruby

print “Are you sure to download? (Yes/No) “

response = gets

if (response.downcase == “yes”)
puts “Downloaded”
else
puts “Download cancelled”
end

puts response.inspect

上面的脚本我们从用户输入一些内容,然后再返回给用户。


$ ./chomp.rb

Are you sure to download? (Yes/No) Yes

Download cancelled

“Yes\n”


这个脚本没有正确的工作。原因很清晰,由inspect返回了。用户输入的内容以回车键结尾,因此换行符也被包含其中了。”Yes”与”Yes\n”不相等。要使用脚本正确运行,我们使用chomp方法移除掉换行符。


#!/usr/bin/ruby

print “Are you sure to download? (Yes/No) “

response = gets

if (response.downcase.chomp == “yes”)
puts “Downloaded”
else
puts “Download cancelled”
end

puts response.inspect

这个是正确的脚本。


if (response.downcase.chomp == “yes”)

这里我们在比”Yes”比较之前对输入内容进行了处理。


$ ./chomp.rb

Are you sure to download? (Yes/No) Yes

Downloaded

“Yes\n”


现在脚本正确工作了。


格式化字符串


Ruby中有格式化说明符。格式化说明符决定了如何显示一个字符串。它以%字符开始。格式化说明符放在单引号或者双引号内。


格式化说明符有以下字段。


%[flags][field width][precision]conversion specifier


方括号内的字段是可选的。


转换说明符表明数据将如何进行转换。


#!/usr/bin/ruby

puts “There are %d oranges in the basket.” % 12
puts “There are %d oranges and %d apples in the basket.” % [12, 10]

这是一个格式化说明符的例子。


puts “There are %d oranges in the basket” % 12

当我们在字符串中使用%d,我们在这个位置将期望一个数字。d是十进制数的转换说明符。这个数据在%字符后面给出。


puts “There are %d oranges and %d apples in the basket” % [12, 10]

当我们在一个字符串中使用多个格式化说明符时,每个都以%开始。多个值放在[]之间并以逗号分隔。


$ ./formatspecifiers.rb

There are 12 oranges in the basket.

There are 12 oranges and 10 apples in the basket.


输出结果。




接下来的例子我们介绍一些基本的转换符。


#!/usr/bin/ruby

puts “There are %d apples.” % 5
puts “I can see %i oranges.” % 3
puts “The width of iPhone 3G is %f mm.” % 62.1
puts “This animal is called a %s” % “rhinoceros.”

我们使用了整数、浮点数和字符串的转换符。


puts “There are %d apples.” % 5
puts “I can see %i oranges.” % 3

di都是用于整数。


puts “The width of iPhone 3G is %f mm.” % 62.1

f用于浮点数。默认浮点数有6个小数。


puts “This animal is called a %s” % “rhinoceros.”

s用于字符串。


$ ./basicspecifiers.rb

There are 5 apples.

I can see 3 oranges.

The width of iPhone 3G is 62.100000 mm.

This animal is called a rhinoceros.


输出结果。




接下来是一个实践的例子。


#!/usr/bin/ruby

website = “zetcode.com”

website.each_char do |c|
print “#{c} has ASCII code %d\n” % c.ord
end

这个例子我们记遍历字符串的所有字符并在终端上打印它的ASCII值。


website.each_char do |c|
print “#{c} has ASCII code %d\n” % c.ord
end

each_char方法将website字符串中的每个字符传给代码块,一个字符是一次循环。当前的字符保存在这是c中。我们使用ord方法获取字符的ASCII值。


$ ./character.rb

z has ASCII code 122

e has ASCII code 101

t has ASCII code 116

c has ASCII code 99

o has ASCII code 111

d has ASCII code 100

e has ASCII code 101

. has ASCII code 46

c has ASCII code 99

o has ASCII code 111

m has ASCII code 109


输出结果。




数字有多种显示形式。


#!/usr/bin/ruby

# decimal
puts “%d” % 300

# hexadecimal
puts “%x” % 300

# octal
puts “%o” % 300

# binary
puts “%b” % 300

# scientific
puts “%e” % (5/3.0)

上面的例子中我们打印数字的十进制、十六进制、八进制、二进制和科学记数的形式。


# hexadecimal
puts “%x” % 300

x转换符用于将数字转为十六进制格式。


# binary
puts “%b” % 300

b转换符用于将数字转为二进制格式。


$ ./various.rb

300

12c

454

100101100

1.666667e+00


输出结果。




精度是格式化说明符的一个字段。它指明了后面小数点的位数。它对于整数、小数和字符串有不同的意义。当用于整数时表明了最少打印多少个数字。如果数字个数少于精度则前面用0补全。对于整数精度默认为1,表示前面没有0.当用于浮点数时表示小数点后显示多少个数字。最后,用于字符串时精度表示多少个字符会打印。


#!/usr/bin/ruby

puts ‘Height: %f %s’ % [172.3, ‘cm’]
puts ‘Height: %.1f %s’ % [172.3, ‘cm’]

puts “%d” % 16
puts “%.5d” % 16

puts “%s” % “zetcode”
puts “%.5s” % “zetcode”

这个例子中我们使用了精度字段。


puts ‘Height: %f %s’ % [172.3, ‘cm’]
puts ‘Height: %.1f %s’ % [172.3, ‘cm’]

172.3是一个浮点数。如果没有指定精度则会显示6个小数。这里将会显示5个0.第二行的.1是精度,它将小数个数减为1。的


puts “%d” % 16
puts “%.5d” % 16

对于整数默认精度为1。第二行中我们指明了精度为.5,这将会在16前面加上3个0。


puts “%s” % “zetcode”
puts “%.5s” % “zetcode”

第一行会打印所有的字符串。第二行仅打印5个,有两个字符将抛弃。


$ ./precision.rb

Height: 172.300000 cm

Height: 172.3 cm

16

00016

zetcode

zetco


输出结果。




宽度字段表示数据最小要显示的宽度。它是一个数字,并且在小数点之前。如果输出比较短,则会被用空格填充,且右对齐。如果宽度前面有减号则会左对齐。如果输出比宽度长则会完整输出。


#!/usr/bin/ruby

puts “%d” % 1
puts “%d” % 16
puts “%d” % 165
puts “%d” % 1656
puts “%d” % 16567

puts “%10d” % 1
puts “%10d” % 16
puts “%10d” % 165
puts “%10d” % 1656
puts “%10d” % 16567

第一种情况打印5个数字没有指明宽度。输出的宽度即为数字的位数。第二种情况指明宽度为10。则每个都最少输出10字符的长度,数字右对齐。


puts “%d” % 1
puts “%d” % 16

打印两个数字,输出的宽度分别为1、2个字符。


puts “%10d” % 1
puts “%10d” % 16

这里宽度都为10个字符。这两个数被填充了8、9个空格。


$ ./fieldwidth.rb
1
16
165
1656
16567
1
16
165
1656
16567

我们发现第二种情况数字是右对齐的。




标志修饰符修改了模式的行为。


#标志分别在二进制、八进制各十六进制前加上0b、0和0x。它会给小数加上小数点,即使这个小数人被精度限制了。


#!/usr/bin/ruby

puts “%#b” % 231
puts “%#x” % 231
puts “%#o” % 231

puts “%.0e” % 231
puts “%#.0e” % 231

puts “%.0f” % 231
puts “%#.0f” % 231

这个例子我们使用了#标志。


puts “%#b” % 231
puts “%#x” % 231
puts “%#o” % 231

十进制数231分别以二进制、八进制和十六进制打印。#标志会给它们加上前缀。


puts “%.0e” % 231
puts “%#.0e” % 231

这个.0限制了小数个数。然后使用#标志后小数点会显示,即使没有小数值。


$ ./flags1.rb

0xe7

0b11100111

0347

2e+02

2.e+02

231

231.


输出结果。




+标志会给正数加上正号。对于二进制、十六进制和八进制的负数会加上负号并使用它的绝对值。


#!/usr/bin/ruby

puts “%d” % 231
puts “%+d” % 231
puts “%d” % -231
puts “%+d” % -231

puts “%b” % -231
puts “%o” % -231
puts “%x” % -231

puts “%+b” % -231
puts “%+o” % -231
puts “%+x” % -231

一个演示+标志符的例子。


puts “%d” % 231
puts “%+d” % 231

通常正数的符号会被忽略掉。如果想要显示正数的符号可以使用+标志符。


puts “%d” % -231
puts “%+d” % -231

+标志符对负数没有影响,输出结果还是一样的。


puts “%b” % -231
puts “%o” % -231
puts “%x” % -231

二进制、八进制和十六进制的数有它们自己生成负数的方法。


puts “%+b” % -231
puts “%+o” % -231
puts “%+x” % -231

如果我们对负数指定了+标志,我们将数字转为不同的格式并加上负号。没有专门的方式表示负数。


$ ./flags2.rb

231

+231

-231

-231

..100011001

..7431

..f19

-11100111

-347

-e7


输出结果。




这里介绍0标志和-标志。0标志会用0代替空格来填充数字。-标志会将输出左对齐。


#!/usr/bin/ruby

puts “%010d” % 1
puts “%010d” % 16
puts “%010d” % 165
puts “%010d” % 1656
puts “%010d” % 16567

puts “%-10d” % 1
puts “%-10d” % 16
puts “%-10d” % 165
puts “%-10d” % 1656
puts “%-10d” % 16567

以上是一个例子。


puts “%010d” % 1
puts “%010d” % 16

数字会用0填充。


puts “%-10d” % 1
puts “%-10d” % 16

数字个数比宽度短,且会左对齐。


$ ./fieldwidth2.rb

0000000001

0000000016

0000000165

0000001656

0000016567

1

16

165

1656

16567


输出结果。




标志符用于精度和宽度。当我们使用符号时精度和宽度将作为一个参数。


#!/usr/bin/ruby

puts “%.
f” % [3, 1.1111111]
puts “%0d” % [10, 2]
puts “%0
.f” % [10, 3, 1.1111]

使用了标志的的例子。


puts “%.f” % [3, 1.1111111]

这里使用作为精度,则第一个数字3是精度的参数。它只为显示1.1111111的3个小数。


puts “%0d” % [10, 2]

这行的代码我们使用标志作为宽度。我们必须在[]之间加上宽度。第一个数字是宽度,第十个数字是要转换的值。


puts “%0.f” % [10, 3, 1.1111]

*标志可以同时用于宽度和精度。这样我们就必须都在[]中指明。


$ ./flags3.rb

1.111

0000000002

000001.111


输出结果。


这章的教程介绍的Ruby的字符串。




原文地址: http://zetcode.com/lang/rubytutorial/strings/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程6——数据类型

数据类型

在这一章的教程中我们开始讨论数据类型。


所有类别的计算机程序,包括电子表格、文本编辑器、计算器和聊天软件都使用数据。现代计算机语言中各种数据类型是必不可少的。一种数据类型是一些可操作的值的集合。


Ruby中有一些数据类型,这些类型都是基于类的。以下是Ruby中公认的数据类型:



  • 布尔(Booleans)

  • 符号(Symbols)

  • 数字(Numbers)

  • 字符串(Strings)

  • 数组(Arrays)

  • 哈希(Hashes)


下面的例子中我们展示Ruby中所有重要的数据类型。


#!/usr/bin/ruby

h = { :name => “Jane”, :age => 17 }

p true.class, false.class
p “Ruby”.class
p 1.class
p 4.5.class
p 3_463_456_457.class
p :age.class
p [1, 2, 3].class
p h.class

我们将它们的类型名打印出来,类型是用于创建对象的模块。


p true.class, false.class

truefalse对象展示的布尔类型。


p “Ruby”.class

这个是字符串。


p 1.class
p 4.5.class
p 3_463_456_457.class

这些是数字。


p :age.class

这个是符号标志,Ruby的一种特殊数据类型。


p [1, 2, 3].class
p h.class

这是两个容器,数组和哈希表。


$ ./types.rb

TrueClass

FalseClass

String

Fixnum

Float

Bignum

Symbol

Array

Hash


这个程序列出了属于Ruby的类型。


布尔值


在我们的世界里存在着对偶关系。天与地、水与火、男与女、爱与恨。这些就是我们自然中的“布尔”。在Ruby里,布尔类型只有一种,具有两个值:true(真)与false(假)。布尔是一种基本的数据类型,它在计算机程序中非常普遍。


高兴的父母等待着孩子的诞生。他们可能会给孩子取个名字。如果是男孩就叫John,如果是女孩就叫Victoria。


#!/usr/bin/ruby

# kid.rb

bool = [true, false]

male = bool[rand(2)]


if male
puts “We will use name John”
else
puts “We will use name Victoria”
end

在这个程序中我们使用随机数来模拟这种情况。


bool = [true, false]

我们创建一个名为bool的变量,它是一个数组包含了两个布尔值。这个数组是使用方括号创建的。


male = bool[rand(2)]

我们使用rand()方法生成一个随机数。这个方法返回0或1。返回的数用于数组的索引。


if male
puts “We will use name John”
else
puts “We will use name Victoria”
end

根据male变量我们打印一条信息。如果maletrue则名字选择John,否则选择Vactoria。类似is/else的结构控制语句是根据布尔值来选择的。


$ ./kid.rb

We will use name Victoria

$ ./kid.rb

We will use name Victoria

$ ./kid.rb

We will use name John

$ ./kid.rb

We will use name John

$ ./kid.rb

We will use name John


程序运行多次的结果如上。


符号标志


符号标志代表其他对象。使用符号标志而不是字符串,是因为可能保存一些资源。一个符号标志是Symbol类的一个实例对象。符号标志通常是在标识符的前面加上冒号,比如 :name。一些对象具有to_sym方法,用于将这些对象转化为符号标志。


Ruby的符号标志在程序运行时是不可改变的。它通常用于当作哈希表的键,因为一个键不需要完整的字符串功能。


#!/usr/bin/ruby

p :name
p :name.class
p :name.methods.size
p “Jane”.methods.size

p :name.object_id
p :name.object_id
p “name”.object_id
p “name”.object_id

第一个例子展示了符号标志的基本操作。


p :name
p :name.class

在终端上打印一个符号标志和它的类型。符号标志的类型是Symbol


p :name.methods.size
p “Jane”.methods.size

比较字符串实例与符号标志实例分配的方法数量。字符串的方法数是符号标志的两位多。


p :name.object_id
p :name.object_id
p “name”.object_id
p “name”.object_id

相同的符号标志具有相同的id,相同的字符串的id却不同。


$ ./symbols.rb

:name

Symbol

79

162

10328

10328

77344750

77344730


程序输出结果。




符号标志也可以作为常量标志,类似于C/C++中的枚举类型。


#!/usr/bin/ruby

light = :on

if light == :on
puts “The light is on”
else
puts “The light is off”
end

light = :off

if light == :on
puts “The light is on”
else
puts “The light is off”
end

电灯不是开就是关。对于这两种情况定义了符号标志。


light = :on

灯是开的。


if light == :on
puts “The light is on”
else
puts “The light is off”
end

程序的逻辑依赖于light变量的状态。




符号标志通常在哗然容器中作为键。这比字符串更加有效。


#!/usr/bin/ruby

domains = {:sk => “Slovakia”, :no => “Norway”, :hu => “Hungary”}

puts domains[:sk]
puts domains[:no]
puts domains[:hu]

在这个脚本中创建了一个名为domains的哈希表。它的键全是符号标志。


puts domains[:sk]
puts domains[:no]
puts domains[:hu]

在哈希表中键是用于访问值的。接下来我们打印出这个哈希表的值。


$ ./symbols3.rb

Slovakia

Norway

Hungary


以上是例子的输出结果。




Ruby解释器将内部引用存储为符号标志。


#!/usr/bin/ruby

class Being

def initialize
@is = true
end

def say
“I am being”
end
end

b = Being.new

p b.method :say
p b.instance_variable_get :@is

定义了一个Being类。该类有一个自定义实例变量@is和一个方法say。这两个实体在Ruby中保存为符号标志。


p b.method :say

method方法用于在b对象在查找给定名字的方法。我们查找的是:say符号。


p b.instance_variable_get :@is

使用instance_variable_get检查@is是不是b对象的一个实例变量。在内部变量存储为:@is符号。


$ ./symbols4.rb



true


输出结果。




所有的符号都存储在符号表中。下一个例子我们来看看这个表。Symbol类的all_symbols方法返回了一个数组包含这个表的全部符号。


#!/usr/bin/ruby

def info
“info method”
end

@v = “Ruby”
@@n = “16”

p Symbol.all_symbols.include? :info
p Symbol.all_symbols.include? :@v
p Symbol.all_symbols.include? :@@n

在这个Ruby脚本中创建了一个方法、一个实例变量和一个类变量。我们检查这些实体是否存储在符号表中。


p Symbol.all_symbols.include? :info

检查:info符号是否在符号表中。这行返回的是true


$ ./symbols5.rb

true

true

true


三个符号都在符号表中。


整数


整数是实数的一个子集。它没有分数或者小数。整数属于集合Z = {…, -2, -1, 0, 1, 2, …} 。这个集合是无限的。


在计算机语言中,整数是原始的数据类型。实际中计算机仅支持整数的一个子集,因为计算机的能力有限。整数用于统计离散的实体。我们有3、4、6个人,但是不能有3.33个人。我们有3.33千克。


在Ruby中整数是Fixnum或者Bignum类的实例对象。不同于其他语言,如Java或者C,在Ruby中整数是一个对象。这两种类型的大小不同。Fixnum类型的整数有一些限制,这些限制与机器有关。Bignum的值表示范围比Fixnum大。如果一些操作超出了Fixnum的范围,它会自动的转换成Bignum。程序员通常不需要关心整数的类型。


#!/usr/bin/ruby

p -2
p 121
p 123265
p -34253464356
p 34867367893463476

p 1.class
p 23453246.class
p 234532423563456346.class
p 2345324235632363463456456346.class

p 5 / 2
p 5.div 2

这个例子中我们处理的一些整数。


p -2
p 121
p 123265
p -34253464356
p 34867367893463476

这是一些不同大小的正数和负数。


p 1.class
p 23453246.class
p 234532423563456346.class
p 2345324235632363463456456346.class

打印出这些数的类型。前两个整数是Fixnum类型,其余两个是Bignum类型。


p 5 / 2
p 5.div 2

这两行展示的整数的相除。当两个数相除时我们使用了相除操作符/方法,结果也是一个整数。


$ ./integers.rb

-2

121

123265

-34253464356

34867367893463476

Fixnum

Fixnum

Bignum

Bignum

2

2


例子的输出结果。




在Ruby中整数可以有不同的表现符号。十进制、十六进制、八进制和二进制数都是可用的。十六进制数以0x字符开头,八进制以0字符开头,二进制以0b字符开头。


#!/usr/bin/ruby

puts 122
puts 0x7a
puts 0172
puts 0b1111010

这个例子中我们打印了十进制数122的所有表现形式。


$ ./inotations.rb

122

122

122

122


以上是输出结果。




我们使用整数的话,那么就是用于处理离散的实体。也许我们用于统计苹果的数量。


#!/usr/bin/ruby

baskets = 16
apples_in_basket = 24

total = baskets apples_in_basket

puts “There are total of #{total} apples”

在这个程序中我们使用整数统计苹果的总数。


$ ./apples.rb

There are total of 384 apples


以上是程序的输出。




大数字读起来比较困难。如果我们有一个数245342395423452,我们发现很难快速的将它读出来。计算机之外大的数字是用空格或者逗号分隔开来。为了可读性,Ruby允许数字包含下划线。Ruby解释器会忽略整数中的下划线。


#!/usr/bin/ruby

p 23482345629
p 23_482_345_629

p 23482345629 == 23_482_345_629

这个例子演示了下划线的使用。


p 23482345629 == 23_482_345_629

这行展示了两个数据是相等的。


$ ./underscore.rb

23482345629

23482345629

true


例子的输出结果。


浮点数


在计算中浮点数表示实数。实例意味着连续的数量,如:重量、高度和速度。Ruby中小数是Float或者BigDecimal类对象。BigDecimal类是Ruby的核心类,是Ruby标准库的一部分。此外我们还可以使用Rational对象。


我们需要理解数字是不业精确的。Ruby的官方文档清楚地说道浮点数对象表示的是不精确的实数。


#!/usr/bin/ruby

p 15.4
p 0.3455
p -343.4563

p 12.5.class
p -12.5.class
p (5.0 / 2).class

p 5.fdiv 2
p 12.to_f

上面的这个例子我们使用了浮点数。


p 15.4
p 0.3455
p -343.4563

这里我们打印三个小数的值。小数包含了小数点字符。


p 12.5.class
p -12.5.class
p (5.0 / 2).class

以上展示的数字的类型,全都是浮点数。最后一个整数与浮点数相除结果为浮点数。


p 5.fdiv 2
p 12.to_f

这里我们创建浮点数除法fdiv和转换方法to_f来创建浮点数。


$ ./decimals.rb

15.4

0.3455

-343.4563

Float

Float

Float

2.5

12.0


以上为转出结果。




一个小数默认最多只显示小数点后16个数字。我们可以使用sprintf或者printf方法来控制浮点数的格式。


#!/usr/bin/ruby

p 1/3.0
p 1.fdiv 2

puts sprintf “%.4f” % (1/3.0)
puts sprintf “%.7f” % (5/3.0)

格式化小数。


p 1/3.0
p 13.fdiv 4
p 1.fdiv 2

第一行打印的小数在小数点后有16个数字。第二行打印的有两个。第三行打印的有一个。


puts sprintf “%.4f” % (1/3.0)
puts sprintf “%.7f” % (5/3.0)

这里我们使用sprintf方法控制小数点后面的数字个数。sprintf方法的格式说明符是精确的。它是一个数字接着%符号。f是一个转换说明符,表示处理的是一个浮点数。


$ ./formatfloat.rb

0.3333333333333333

3.25

0.5

0.3333

1.6666667


以上是输出结果。




Ruby支持使用科学的记数法来表示一个浮点数。这也称为指数记数法,它是将非常大或者非常小的数转换成正常的小数形式。


#!/usr/bin/ruby

p 1.2e-3
p 0.0012

p 1.5E-4
p 0.00015

这个例子展示了两个使用科学记数表示的小数。


$ ./scientific.rb

0.0012

0.0012

0.00015

0.00015


这是以上程序的输出。




前面我们主说过浮点数的值稍微有些不精确。在很多计算中,普通的浮点小数已经足够精确了,如:我们的体重是60kg还是60.000024kg并不重要。对于其他计算,包括科学和工程应用,精确度是非常重要的。


Ruby有一个BigDecimal标准库。这个类对于非常大或者非常精准的浮点数提供了任意的精度。


#!/usr/bin/ruby

require ‘bigdecimal’

sum = 0

1000.times do
sum = sum + 0.0001
end

p sum


sum = BigDecimal.new(“0”)

1000.times do
sum = sum + BigDecimal.new(“0.0001”)
end

puts sum.to_s(‘F’)
puts sum.to_s(‘E’)

在这个例子中我们比较了FloatBigDecimal的精度。


require ‘bigdecimal’

BigDecimal类必须导入。


sum = 0

1000.times do
sum = sum + 0.0001
end

p sum

通过循环对一个很小的浮点数求和。最后会出现一点误差。


sum = BigDecimal.new(“0”)

1000.times do
sum = sum + BigDecimal.new(“0.0001”)
end

然后再对BigDecimal做同样的事情。


puts sum.to_s(‘F’)
puts sum.to_s(‘E’)

sum浮点数打印为工程记数形式。


$ ./bigdecimal.rb

0.10000000000000184

0.1

0.1E0


输出结果表示BigDecimalFloat更精确。




如果一个短路运动员100m跑9.87s,那么他的时速是多少?


#!/usr/bin/ruby

distance = 0.1
time = 9.87 / 3600

speed = distance / time

puts “The average speed of a sprinter is #{speed} km/h”

这个例子必需使用浮点数。


distance = 0.1

100m等于0.1km。


time = 9.87 / 3600

9.87s等于9.87/6060 h。


speed = distance / time

要计算速度,我们用距离除以时间。


$ ./speed.rb

The average speed of a sprinter is 36.4741641337386 km/h


以上是speed.rb脚本的输出。


有理数


Ruby支持有理数。有理数是一个确切的数。使用有理数可以避免舍入错误。Ruby中有理数是Rational类的对象。我们可以使用某些对象的to_r方法来创建有理数。


有理数可以用于表示两个整数相除的分数,a/b(b!=0)。如果b为1,每个整数都是一个有理数。


#!/usr/bin/ruby

puts 2.to_r
puts “23”.to_r
puts 2.6.to_r

p Rational 0
p Rational 1/5.0
p Rational 0.5

这个例子展示了一些有理数。


puts 2.to_r

变量我们使用to_r方法将整数2转化为有理数2/1。


p Rational 0.5

使用Rational方法创建一个有理数》


$ ./rational.rb

2/1

23/1

5854679515581645/2251799813685248

(0/1)

(3602879701896397/18014398509481984)

(1/2)


例子的输出结果。


空值


Ruby有一个特殊的值nil。它表示空值。nilNilClass类的单实例,仅有一个nil


#!/usr/bin/ruby

puts nil
p nil

p $val

p [1, 2, 3][4]

p $val1 == $val2

nil的一个例子。


puts nil
p nil

在终端上打印nil的值。puts方法打印空字符串,p方法打印‘nil’字符串。


p $val

当我们引用一个没有定义的全局变量时会返回nil值。


p [1, 2, 3][3]

这行代码我们引用了一个3元素数组的第4个元素,结果返回nil。Ruby中的许多方法对于无效的值都返回nil


p $val1 == $val2

这行返回true,这实际上是因为nilNilClass的单实例对象。


$ ./nilvalue.rb


nil

nil

nil

true


输出结果。


字符串


字符串在计算机程序代表文本数据。Ruby字符串是一个序列化的unicode字符。字符串是String的一个对象。字符串的字面量是字符加上双引号或者单引号。


字符串是一个非常重要的数据类型。它需要专门用一章来介绍。这里我们仅包含一个小例子。


#!/usr/bin/ruby

p “Ruby”
p ‘Python’

p “Ruby”.size
p “Ruby”.upcase

p 23.to_s

这个例子中我们使用了Ruby的字符串。我们使用p方法是为了在输出中看到数据类型。


p “Ruby”
p ‘Python’

在终端中打印两个字符串的字面值。第一个字面量是使用双引号,第二个是单引号。


p “Ruby”.size
p “Ruby”.upcase

这两行调用了两个字符串的方法。size方法返回字符串的长度,在这里是4个字符。upcase方法是将字符串转为大写。


p 23.to_s

to_s方法是将整数转为字符串。


$ ./strings.rb

“Ruby”

“Python”

4

“RUBY”

“23”


在输出中我们看到字符串是在引号内。这就是我们使用p方法的结果,printputs方法都不会带上引号。


数组和哈希表


数组和哈希表是对象的集合。他们将对象集合在一起。


数组是对象的有序集合。哈希表是键-值对的集合。我们将会用单独的一章来介绍数组和哈希表。以下仅是一个预览的例子。


#!/usr/bin/ruby

nums = [1, 2, 3, 4]

puts “There are #{nums.size} items in the array”

nums.each do |num|
puts num
end


domains = { :de => “Germany”, :sk => “Slovakia”,
:us => “United States”, :no => “Norway” }

puts domains.keys
puts domains.values

这是一个Ruby数组和哈希表的例子。


nums = [1, 2, 3, 4]

puts “There are #{nums.size} items in the array”

nums.each do |num|
puts num
end

这里创建一个有4项内容的数组。第二行统计了这个数组数据项的数量,并合并到了消息中。随后我们使用each方法将每个元素打印在终端上。


domains = { :de => “Germany”, :sk => “Slovakia”,
:us => “United States”, :no => “Norway” }

puts domains.keys
puts domains.values

创建了Ruby的哈希表,然后打印它的键和值。


$ ./arrayshashes.rb

There are 4 items in the array

1

2

3

4

de

sk

us

no

Germany

Slovakia

United States

Norway


例子的输出结果。


类型转换


我们经常是一次使用多种数据类型。在编程中从一种数据类型转换为其他类型是很平常的。类型转换或者类型的引用会将一个实体从一个类型转换成另一个类型。有两种类型转换的方式:隐式和显式。隐式类型转换又称为强制转换,是被编译器自动的转换。Ruby只有显式转换。


Ruby有内建的转换方法。如:to_ito_s或者to_f。内核模块有一些公共的方法用来转换,如IntergerString或者Float。这些方法还要与Ruby的类混淆。


#!/usr/bin/ruby


p Array(1..6)
p Complex 6
p Float 12
p Integer “34”
p Rational 6
p String 22

这里我们展示了内核模块的转换方法。


$ ./convertmethods.rb

[1, 2, 3, 4, 5, 6]

(6+0i)

12.0

34

(6/1)

“22”


例子的输出结果。




#!/usr/bin/ruby

p “12”.to_i
p 12.5.to_i
p nil.to_i

p 12.to_f
p “11”.to_f
p nil.to_f

以上例子我们展示了数字的转换。一些对象具有to_ito_f方法将对象转换成整数和浮点数。


p “12”.to_i
p 12.5.to_i
p nil.to_i

这里我们将字符串、小数和nil转换成整数。


p 12.to_f
p “11”.to_f
p nil.to_f

这三行将整数、字符串和nil转换成小数。


$ ./conversions.rb

12

12

0

12.0

11.0

0.0


例子的输出结果。




第二个例子展示了一些字符串的转换。


#!/usr/bin/ruby

p “12”.to_i
p “13”.to_f
p “12”.to_r
p “13”.to_c

p “Jane”.to_sym

v = “Ruby Python Tcl PHP Perl”.split
p v.class

上面的例子中我们将字符串转换为不同类型的对象。


p “12”.to_i
p “13”.to_f
p “12”.to_r
p “13”.to_c

这里将字符串转换成整数、小数、有理数和复数。


p “Jane”.to_sym

将字符串变为符号标志。


v = “Ruby Python Tcl PHP Perl”.split
p v.class

使用字符串的split方法将字符串转换成数组。


$ ./stringconv.rb

12

13.0

(12/1)

(13+0i)

:Jane

Array


输出结果。




下面的小例子展示了数组哈希表的转换。


#!/usr/bin/ruby

h = {:de => “Germany”, :sk => “Slovakia”}
p h.to_a

a = [:de, “Germany”, :sk, “Slovakia”,
:hu, “Hungary”, :no, “Norway”]
p Hash[a]

这个例子的代码我们创建了一个哈希表并转换成数组,创建一个数组并转换成哈希表。


h = {:de => “Germany”, :sk => “Slovakia”}
p h.to_a

哈希表转换为数组使用to_a方法。


a = [:de, “Germany”, :sk, “Slovakia”,
:hu, “Hungary”, :no, “Norway”]
p Hash[
a]

将数组转换成哈希表。在这里的上下文中使用了星号操作符。这个风格来自Perl。它将一个数组分割成多个变量。


$ ./h2a.rb

[[:de, “Germany”], [:sk, “Slovakia”]]

{:de=>”Germany”, :sk=>”Slovakia”, :hu=>”Hungary”, :no=>”Norway”}


输出结果。


这章在教程覆盖了数据类型和它们的转换。




原文地址: http://zetcode.com/lang/rubytutorial/datatypes/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程5——对象

Ruby中的对象

在这章的教程中我们将简要的介绍下Ruby语言对象的概念。更多的内容将会在面向对象的章节中学习。由于Ruby的许多特性可以会使新手们迷惑,尤其是已经学习过其他编程语言的,因此才编写了这个关于对象的预备章节。


Ruby是一门面向对象的编程语言。这意味着我们可以在Ruby语言中使用对象。对于语言程序员来说Ruby程序就是一些字符流。这些符号就是Ruby的关键字、操作符、变量符号和字面量。从语言的角度来看Ruby程序是由对象组成的。这些对象在Ruby脚本程序执行进程来创建和修改。


有两种类型的对象:内置对象和自定义对象。内置对象是所有程序员都可以使用的预定义对象。它们由Ruby语言的内核或者变量库提示。自定义对象是由应用程序开发者在他们的应用程序域中创建的。


所有的对象都必须在使用之前创建。我们把创建对象叫做对象实例化。对象是由数据和方法组成,数据是对象静态的部分,方法是动态的形式。对象的修改以及与其他对象通信都是通过方法进行的。


#!/usr/bin/ruby
puts “Ruby language”

以上是一个简单的Ruby脚本。如果我们熟悉Pascal或者C之类的程序语言,我们可以看到一个名为puts的关键字或者是一个函数和一个字符串参数“Ruby language”


看起来有点不同,Ruby是一门纯面向对象语言。“Ruby language”确实是一个字符串,常见的一种数据类型。但是它也是一个对象。与所有的对象一样,我们可以调用它们的方法。这与其他的语言有点不同。puts是一个方法。方法是定义在一个对象中的函数。方法是不能独自存在的。实际上puts方法是Kernel模块的一部分。


#!/usr/bin/ruby
Kernel.puts “Ruby language”
Kernel.puts “Ruby language”.size

在以上的脚本中我们写了两行代码。


Kernel.puts “Ruby language”

Kernel是可以省略的,在第一个例子中我们调用puts方法就没有使用Kernel。这样可以少打些字节约时间。实际上它是对于Kernel.puts这个正式调用的简写。正如在C#中的Console.writeln和Java中的System.println。因此方法必须与一个对象相关联,或者如果是类方法就必须与类相关联。


Kernel.puts “Ruby language”.size

在这行代码中我们在终端上打印了“Ruby language”这个字符串的长度。对于有其他编程语言经验的程序员来说可能会困惑。在其他语言中字符串是一个原始数据类型,不能修改,并且没有自己的方法。在Ruby中字符串是一个完整的对象,有自己的方法。size方法其中一个,用于返回这个字符串的长度。


$ ./simple2.rb

Ruby language

13


以上是这个例子的输出。




接下来的例子我们看看整数。与字符串相似一个数字也是一个对象。


#!/usr/bin/ruby
puts 6.object_id
puts 6.even?
puts 6.zero?
puts 6.class

这个例子中我们定义了一个数字6。然后调用了一些这个数字的方法。


puts 6.object_id

这里6是一个对象,object_id是一个方法。这个方法返回了与这个对象相关联的id号。每个对象都拥有一个id号。如果我们要在对象上调用一个方法,就必须在他们之间加点号。


puts 6.even?
puts 6.zero?

这里我们对6这个对象调用了两个方法。如果一个数是偶数,那么even?返回true;如果一个数等于0,那么zero?返回true。注意这两个方法都是以问号能结尾的。在Ruby中约定了如果一个方法返回值是布尔类型,那么方法名以问号结尾。


puts 6.class

class方法告诉我们当前正在处理的这个对象是什么类型的。在这里6是一个Fixnum类型。


$ ./objectnumber.rb

13

true

false

Fixnum


以上是这个例子的输出结果。


创建对象


我们之前提到了在Ruby是对象使用之前必须先创建。对象可以被隐式创建或者显式创建。使用字面量符号创建对象是隐式创建;使用new关键字创建对象是显式创建。自定义对象都是显式创建的。自定义对象必须是从某个特定的类创建的。类是对象的模块,一个类可以创建多个对象。


#!/usr/bin/ruby
class Being
end

puts 67
puts “ZetCode”

s = String.new “ZetCode”
puts s

# n1 = Fixnum.new 67
# puts n1

b = Being.new
puts b

这个例子演示了Ruby中的对象创建。


class Being
end

这里是一个名为Being的对象模块。对象模块使用class关键字创建。自定义对象模块通常放在代码文件的顶部,或者分开放在另外的文件中。


puts 67
puts “ZetCode”

这两行代码我们用到了两个对象。Fixnum类型的67String类型的“ZetCode”67“ZetCode”是使用字面符号创建了。字面符号是一个文本,表示了一个类型的特定值。这两个对象是Ruby解释器幕后创建的。在源代码中Ruby的一些对象是使用他们特定的字面符号创建的。


s = String.new “ZetCode”
puts s

这是正式的方法创建字符串对象。它与之前的隐式创建是等价的。


# n1 = Fixnum.new 67
# puts n1

不是所有的内置对象都可以使用new方法来创建。以上代码就不能编译通过。Fixnum对象只能通过字面符号来创建。


b = Being.new
puts b

这里我们创建了自定义对象的一个实例。puts方法输出了这个对象的简短描述。


$ ./ocreation.rb

67

ZetCode

ZetCode

#<Being:0x9944d9c>


以上是输出结果。




继续介绍一些正式的对象创建。


#!/usr/bin/ruby

s1 = String.new “Ruby”
puts s1.size
puts s1.downcase

a1 = Array.new
a1.push 1, 2, 3
puts a1.include? 3
puts a1.empty?

r1 = Range.new 1, 6
puts r1.class
puts r1.include? 4

在这个例子中,我们创建三个内建对象并且调用了几个它们的方法。


s1 = String.new “Ruby”
puts s1.size
puts s1.downcase

创建一个字符串对象,并且调用了它的两个方法。size方法返回这个字符串的长度。downcase方法将这个字符串转为小写。


a1 = Array.new
a1.push 1, 2, 3
puts a1.include? 3
puts a1.empty?

这里创建了一个数组,并往其中添加了三个数字。然后调用了两个数组的方法。include?方法用于检查一个特定的值(在这个例子中是3)是否在数组内。empty?方法返回一个布尔类型的值表明这个数组是否为空。


r1 = Range.new 1, 6
puts r1.class
puts r1.include? 4

创建了一个Range类型的实例对象。它包含了1到6的数字。class方法返回这个对象的类型名称。在这个例子中include?方法检查数字4是否在这个范围内。


$ ./formal.rb

4

ruby

true

false

Range

true


这个例子的运行输出结果。


对象字面符


前面提到了一些内建对象可以使用对象字面符创建。接下来的例子展示了一些对象字面符。


#!/usr/bin/ruby

4.times { puts “Ruby” }

puts “Ruby”.size
puts “Ruby”.downcase

puts [1, 2, 3].include? 3
puts [1, 2, 3].empty?

puts :name.class
puts :name.frozen?

puts (1..6).class
puts (1..6).include? 4

在这个例子中我们使用字面符创建了FixnumStringsArraysSymbolsRanges对象。


4.times { puts “Ruby” }

我们可以直接对一个整数字面符号调用方法。这行代码将在终端上打印4次”Ruby”字符串。


puts “Ruby”.size
puts “Ruby”.downcase

我们对使用字面符号创建的字符串调用了两个方法。


puts [1, 2, 3].include? 3
puts [1, 2, 3].empty?

这里我们使用字面符号创建了两个数组。然后使用include?方法检查一个特定的数字是否是这个数组里;使用empty?方法检查这个数组是否为空。


puts :name.class
puts :name.frozen?

使用以冒号开头的字面符号创建了符号对象,并且调用的它的两个方法。


puts (1..6).class
puts (1..6).include? 4

使用字面符号创建了两个范围对象,并且调用了他们的两个方法。class方法返回这个类的名称,include?方法检查给定的数字是否是这个范围内。


$ ./literals.rb

Ruby

Ruby

Ruby

Ruby

4

ruby

true

false

Symbol

false

Range

true


以上是例子的输出结果。


对象层级


在许多面向对象语言中对象是层级形式的。Ruby中也有对象层级。与树形层级相似,我们也有父对象和子对象。对象从它的父对象中继承数据和行为。层级的顶级是根对象,称为Object。在Ruby中每个对象都至少有一个父对象。也就是就每个对象都继承至Object对象的基类。


根据Ruby的官方文档,Object是Ruby的类层级的根。它的所有方法在所有的类中都是一样的,除非显示的覆盖了。


#!/usr/bin/ruby

puts 4.is_a? Object
puts “Ruby”.is_a? Object
puts [2, 3].is_a? Object
puts :name.is_a? Object
puts (1..2).is_a? Object

以上例子的代码展示了所有对象都是继承至根对象Object


puts 4.is_a? Object

使用is_a?方法检查一个数字是否为特定的类型,也就是说它是否继承至给定的对象类型。


$ ./mother.rb

true

true

true

true

true


所有方法都返回true,意味着所有的对象都继承至母类。




即使是基本的Ruby对象,它们的继承层级也可能是很复杂的。


#!/usr/bin/ruby

puts 6.class

puts 6.is_a? BasicObject
puts 6.is_a? Object
puts 6.is_a? Numeric
puts 6.is_a? Integer
puts 6.is_a? Fixnum

puts 6.is_a? Bignum
puts 6.is_a? String

这个例子展示了小数字的继承层级。


puts 6.class

我们发现数字6的类型是Fixnum


puts 6.is_a? BasicObject
puts 6.is_a? Object
puts 6.is_a? Numeric
puts 6.is_a? Integer
puts 6.is_a? Fixnum

以上这些代码全都返回true。数字6是Fixnum类型。从Ruby文档中我们发现另外四个对象是Fuxnum对象的父类。


puts 6.is_a? Bignum
puts 6.is_a? String

$ ./inheritance.rb

Fixnum

true

true

true

true

true

false

false


以上是输出结果。




这节的最后再举个例子展示下自定义对象的继承。


#!/usr/bin/ruby

class Being

def to_s
“This is Being”
end

def get_id
9
end
end

class Living < Being

def to_s
“This is Living”
end
end

l = Living.new

puts l
puts l.get_id
puts l.is_a? Being
puts l.is_a? Object
puts l.is_a? BasicObject

在这个例子中我们创建了两个对象。BeingLivingLiving对象继承至Being。第一个是父对象,第二介是子对象。


class Being

def to_s
“This is Being”
end

def get_id
9
end
end

这里定义了一个Ruby的自定义对象。定义内容是classend关键字之间。在定义里我们创建了两个方法。当puts方法接了一个对象作为参数时,会调用它的to_s方法。它通常返回这个对象的字符串描述。


class Living < Being

def to_s
“This is Living”
end
end

定义了一个Living对象,这个对象继承至Being对象。<操作符用于创建继承关系。to_s方法被覆盖了。


l = Living.new

我们创建了一个Living实例对象。自定义对象使用new关键字创建。


puts l

puts方法调用Living对象的to_s方法。只有当Living类没有定义to_s方法时,Being类的to_s方法才会被调用。


puts l.get_id

Living对象没有定义get_id方法。在这种情况下就检查它的父类是否有此方法。在这里Being有这个方法,并且被调用。


puts l.is_a? Being

这行将返回trueLiving对象是Being类型的,因为它继承至Being类。


puts l.is_a? Object
puts l.is_a? BasicObject

我们的Living自定义对象中,没有特别显示的指定与Object或者BasicObject的关系。然而这两行也返回true。这是因为在Ruby中所有对象都是自动设置为这两个对象的后代。这是Ruby解释器在幕后完成的。


$ ./custominher.rb

This is Living

9

true

true

true


以上是输出结果。


Ruby的顶级环境


Ruby中有一个特殊的对象引用到Ruby的顶级环境,这是定义在其他上下文之外的默认执行环境。顶级环境名字是main。它是一个Object类型的实例对象。以下main分配了一个局部空间,所有的局部变量有属于它。


#!/usr/bin/ruby

n1 = 3
n2 = 5

puts local_variables

Kernel.puts self
puts self.class

这是描述Ruby顶级环境的第一个例子。


n1 = 3
n2 = 5

我们定义了两个数字类型的变量,这些变量是顶级环境的局部变量。


puts local_variables

这里我们输出所有的局部变量。local_variablesKernel模块的一个方法,它包含了每个顶级环境的对象。


Kernel.puts self

self是Ruby的伪变量。它返回当前对象的接收者。这行将在终端打印“main”。这是顶级环境的名字。Kernel.puts代码部分的Kernel可以省略。完整的名字表示的puts方法属于Kernel模块。


puts self.class

这行打印了顶级环境的类型。我们得到顶级环境的对象类型。它是Object类型,Ruby类层级的根。


$ ./toplevel.rb

n1

n2

main

Object


这是这个例子的输出结果。n1n2是顶级环境所分配的局部变量。main是Ruby顶级执行环境的名字。最后Object是顶级环境的类型。




我们再展示另一个关于Ruby顶级环境的例子。


#!/usr/bin/ruby

@name = “Jane”
@age = 17

def info
“#{@name} is #{@age} years old”
end

puts self.instance_variables
puts self.private_methods.include? :info

puts info

我们展示的属于顶级环境的实例变量和方法。


@name = “Jane”
@age = 17

我们定义了两个实例变量。在Ruby中实例变量以@符号开头。实例变量属于指定的对象实例。在这里是属于Ruby的顶级环境。


def info
“#{@name} is #{@age} years old”
end

这里定义了一个方法。每个方法都必须属于一个对象。这个方法是属于顶级环境的。所有顶级环境的方法都是私有的。私有方法的访问是受制的。


puts self.instance_variables

instance_variables方法打印self的所有实例变量。


puts self.private_methods.include? :info

所有的顶级环境的方法都自动设为私有。private_methods返回该对象所有的私有方法。由于内容太多,我们就调用include?方法来检查info方法是否是其中一个。注意我们是通过符号名来引用info的。


$ ./toplevel2.rb

@name

@age

true

Jane is 17 years old


以上是例子的输出结果。


这章包含了Ruby对象的基本内容。




原文地址: http://zetcode.com/lang/rubytutorial/objects/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程4——变量

变量

在这章的教程中我们将详细介绍变量。


变量是保存数据的地址。每个变量都有唯一的一个名字,变量命名存在着一些约定。变量保存着数据对象,更确切的说变量是对数据所在的计算机内存地址的引用。每一个对象都具有一定的数据类型,内置的类型或者自定义的类型。Ruby属于动态语言,与Java、C或者Pascal之类的强类型语言不同,动态语言不用为变量定义确切数据类型,而是解释器在分配变量时决定它的类型。在Ruby中程序运行过程变量可以包含不同类型的不同值。



#!/usr/bin/ruby


i = 5

puts i

i = 7

puts i



变量是可变的,与常量不同,在程序运行过程中它们可以保存不同的值。在上面这个例子中有一个名为i的变量,首先赋值为5,然后又改为7。


命名约定


与其他语言一样,Ruby对变量标识符也有些命名约定。

Ruby是区分大小写的,这意味着ageAge是两个变量名。许多语言都是区分大小写的,但是BASIC例外。我们改变字符的大小写可以创建不同的变量,但是不推荐这种做法。



#!/usr/bin/ruby


i = 5

p i

I = 7

p I



这个例子定义了两个变量Ii,它们保存了不同的值。


./case.rb

5

7


以上是case.rb脚本的输出结果。




在Ruby中变量名可由字母数字和下划线组成。为了使解释器能简单的从字面上区分数字和变量,变量名不能以数字开头。变量名同样也不能以大写字母开头,在Ruby中以大写字母开头会被认为是常量。



#!/usr/bin/ruby


name = “Jane”

placeOfBirth = “Bratislava”

placeOfBirth = “Kosice”

favorite_season = “autumn”


n1 = 2

n2 = 4

n3 = 7


p name, placeOfBirth, favorite_season

p n1, n2, n3



在这个脚本中我们展示一些变量的命名。




变量名应该是有意义的。好的编程习惯是给变量取个具有描述性的名字,使得程序更加可读。


#!/usr/bin/ruby

name = “Jane”
place_of_birth = “Bratislava”
occupation = “student”

i = 5
while i > 0 do
puts name
i -= 1
end

这个脚本展示三个具有描述性的变量名。对于程序员来说place_of_birth比其他的名字如pob更具有描述性。在循环的时候通常选择一个比较简单的变量名。


印章(Sigils)


变量标识符可以以一些特殊的印章(Sigils)符号开头。印章(Sigils)是附加在标识符上的符号。在Ruby中变量印章(Sigils)表示了变量的作用域范围。在Perl中它是表示数据的类型。Ruby的变量印章(Sigils)符号有$@



#!/usr/bin/ruby


tree_name = “pine”

$car_name = “Peugeot”

@sea_name = “Black sea”

@@species = “Cat”


p local_variables

p global_variables.include? :$car_name

p self.instance_variables

p Object.class_variables



我们定义了四个不同作用域范围的变量。作用域表示了该变量可以被引用到的范围。我们使用了内置的方法来决定变量的作用域。



tree_name = “pine”



不包含印章(Sigils)符号的变量是一个局部变量。局部变量只在局部有效,如在方法、代码块、模块内。



$car_name = “Peugeot”



全局变量以$符号开头。它们在所有地方都是有效的。在程序中不要滥用全局变量。



@sea_name = “Black sea”



实例变量是以@符号开头。它只有在实例对象中才有效。



@@species = “Cat”



最后我们定义了一个类变量。它在所有属于这个类的实例中都有效。



p local_variables



local_variables是保存了当前环境下所有定义的局部变量的数组。



p global_variables.include? :$car_name



类似的,global_variables是保存的全部全局变量的数组。由于全局变量很多,我们就不将它们全部在终端上打印了。每次Ruby脚本启动时都会预定义一些变量。我们使用数组的include?方法来检查我们全局变量是否定义了。同时请注意我们引用变量是用的符号。(符号是以一个冒号开头)



p self.instance_variables



self伪变量指向了instance_variables方法的接收对象。这个例子中的接收对象是main,Ruby的顶级执行区域。



p Object.class_variables



最后我们获取所有的类变量数组。main是一个Object类的实例。


$ ./sigils.rb

[:tree_name]

true

[:@sea_name]

[:@@species]


以上是这个例子的输出结果,我们看到了变量的符号名。


局部变量


局部变量是只在Ruby源代码的局部区域有效。这个区域也称为局部作用域。局部变量是在Ruby的模块、方法、类中定义。


#!/usr/bin/ruby

def method1
x = 5
p x
end

method1

p x

我们定义了一个名为method1的方法,它有一个变量。这个变量是局部变量。这意味着这个变量只在这个方法内有效。我们只能在这个方法名到end关键字之间访问x变量。


def method1
x = 5
p x
end

以上定义了一个method1方法。在方法内部创建了一个局部变量x,然后将它的值打印到终端。



method1



方法被调用。



p x



我们试图在方法外部访问这个局部变量。这将导致NameError错误,Ruby解释器找不到这个标识符。


$ ./locals.rb

5

./locals.rb:11:in <main>’: undefined local variable
or method
x’ for main:Object (NameError)


以上是这个例子的输出结果。




以下例子是对前一个例子的简单修改。


#!/usr/bin/ruby

x = 5

def method1
x = 10
p x
end

method1

p x

我们定义了两个x变量。一个是在method1内部定义的,另一个是在外部定义的。他们是两个不同的局部变量,并不会相互冲突。


x = 5

我们创建了一个局部变量,它的值为5。这个变量的局部作用范围是main区域。它在method1内部是无效的。


def method1
x = 10
p x
end

method1内部创建了一个新的x局部变量,它的值是10.它存在于method1方法内部,在end关键字之后就会失效。


$ ./locals2.rb

10

5


以上是输出结果。




如果一个方法接收了参数,那么就会创建与这些参数相对应的局部变量。


#!/usr/bin/ruby


def rectangle_area a, b
puts local_variables
return a b
end

puts rectangle_area 5, 6

我们定义了一个方法,它接收两个值,然后返回这个矩形的面积。


def rectangle_area a, b
puts local_variables
return a
b
end

rectangle_area方法接收两个参数。它们是矩形的边长,然后我们计算它的面积。对应于标识符ab的两个局部变量将自动创建了。我们调用local_variables方法查看方法内部的所有局部变量。


puts rectangle_area 5, 6

这里我们给rectangle_area方法传了两个值。这两个值将会分配给在方法内部创建的两个局部变量。


$ ./parameters.rb

a

b

30


输出了三个结果。前两个是rectangle_area方法内部的局部变量名。第三个是面积的计算结果。




一个方法可以定义在另一个方法的内部。内嵌方法有它自己的局部变量。


#!/usr/bin/ruby

def method1

def method2

def method3
m5, m6 = 3
puts “Level 3”
puts local_variables
end

m3, m4 = 3
puts “Level 2”
puts local_variables
method3
end

m1, m2 = 3
puts “Level 1”
puts local_variables
method2

end

method1

在这个Ruby脚本中我们创建了三个方法。method2method3是内嵌方法。method2定义在method1内部,method3又定义在method2内部。每一个方法的局部变量仅在这个方法内是可访问的。


$ ./lms.rb

Level 1

m1

m2

Level 2

m3

m4

Level 3

m5

m6


从输出结果我们可以知道method1有两个局部变量m1m2。内嵌方法method2的局部变量有m3m4。最内部的方法method3的局部变量是m5m6




这一节的最后一个例子将展示一些局部作用域的示范。


module ModuleM
m1, m2 = 4

puts “Inside module”
puts local_variables
end


def method1
v, w = 3
puts “Inside method”
puts local_variables
end


class Some
x, y = 2
puts “Inside class”
puts local_variables
end

method1

t1, t2 = 7

puts “Inside toplevel”
puts local_variables

在这个例子我们分别在模块、方法、类和顶级环境中创建局部变量。local_variables是内核模块的一个方法,用于获取当前的所有局部变量。


module ModuleM
m1, m2 = 4

puts “Inside module”
puts local_variables
end

模块是一个方法和常量的集合。我们创建了两个局部变量m1m2


def method1
v, w = 3
puts “Inside method”
puts local_variables
end

method1方法中创建了两个局部变量vw


class Some
x, y = 2
puts “Inside class”
puts local_variables
end

Some类中创建了两个局部变量xy


t1, t2 = 7

最后我们为Ruby顶级环境创建两个局部变量。


$ ./locals3.rb

Inside module

m1

m2

Inside class

x

y

Inside method

v

w

Inside toplevel

t1

t2


输出结果展示了各个作用域的局部变量。


全局变量


全局变量可以在脚本的任何地方访问到。它们以$符号开头。

全局变量可能会引起很多程序错误,因此不鼓励使用全局变量。除非有原因要使用,否则建议使用局部变量。


#!/usr/bin/ruby

$gb = 6


module ModuleM
puts “Inside module”
puts $gb
end


def method1
puts “Inside method”
puts $gb
end


class Some
puts “Inside class”
puts $gb
end

method1

puts “Inside toplevel”
puts $gb
puts global_variables.include? :$gb

在这个例子中我们创建了一个全局变量$gb。这个变量在模块、方法、类和顶级环境都可以访问。全部变量$gb是所有的实体中都是有效的。


$gb = 6

创建全局变量$gb,它的值为6。


module ModuleM
puts “Inside module”
puts $gb
end

在一个模块定义中我们打印全局变量的值。


def method1
puts “Inside method”
puts $gb
end

在一个方法定义中我们打印全局变量的值。


class Some
puts “Inside class”
puts $gb
end

在一个类定义中我们打印全局变量的值。


puts $gb
puts global_variables.include? :$gb

在顶级环境下打印全局变量的值,并检查这个变量是否为全局变量。


$ ./globals.rb

Inside module

6

Inside class

6

Inside method

6

Inside toplevel

6

true


这个例子的输出结果确认了全局变量可以任何地方访问到。




当一个Ruby脚本启动时,它会访问多个预定义的全局变量。这些全局变量不认为有害并且能帮助完成一些常见的任务。


#!/usr/bin/ruby

p $LOAD_PATH
p $:

这个脚本显示了$LOAD_PATH这个全局变量。这个变量列出了require方法会搜索的所有目录。$:$LOAD_PATH的缩写。

更多的全局变量会在本章的变量预定义这节中介绍。


实例变量、类变量


在这节将简要的介绍下实例变量和类变量。它们将会在面向对象那一章详细介绍。

实例变量是属于具体某个对象实例的变量。每个对象都有它自己的变量。实例变量以@符号开头。类变量属于特定某个类的。这个类所创建的对象实例共享这个类的类变量。类变量以@@符号开头。


#!/usr/bin/ruby

class Being

@@is = true

def initialize nm
@name = nm
end

def to_s
“This is #{@name}”
end

def does_exist?
@@is
end
end

b1 = Being.new “Being 1”
b2 = Being.new “Being 2”
b3 = Being.new “Being 3”

p b1, b2, b3

p b1.does_exist?
p b2.does_exist?
p b3.does_exist?

我们创建一个自定义Being类。这个Being类有一个类变量和一个实例变量。


class Being
@@is = true

@@is是一个类变量。这个类变量被所有Being类的实例所共享。这个例子的逻辑是判断是不是Being


def initialize nm
@name = nm
end

initialize方法是构造函数。这个方法在对象被创建时调用。用于创建@name实例变量。


def to_s
“This is #{@name}”
end

当这个对象作为打印方法如p或者puts的参数时to_s method方法会被调用。这个方法返回这个对象便于人类阅读的描述内容。


def does_exist?
@@is
end

does_exist?返回类变量。


b1 = Being.new “Being 1”
b2 = Being.new “Being 2”
b3 = Being.new “Being 3”

创建Being类的三个实例对象。每个对象拥有不同的名字。这个名字存储在实例变量中,对于每个对象它是唯一的。名字将会在to_s方法中使用,用于返回一个对该对象的简短描述。


p b1, b2, b3

这个方法将刚创建的三个对象作为参数,它将调用每个对象的to_s方法。


p b1.does_exist?
p b2.does_exist?
p b3.does_exist?

最后我们调用每个实例对象的does_exist?方法。这三个方法会输出相同的结果,因为这个方法返回的是类变量。


$ ./icvars.rb
This is Being 1
This is Being 2
This is Being 3
true
true
true

以上是这个例子的输出结果。前三条信息是唯一的,因为这个字符串是存储在实例变量中的。true值是类变量,它被调用的三次。


环境&命令行变量


可以用ENV常量来访问环境变量。它是一个Ruby的hash对象。每个环境变量都是ENV这个hash对象的键值。


ARGV常量存储了命令行的参数值。它们是在脚本启动时传递的。ARGV是一个数组,参数以字符串存储。SARGV的别名。


ENVARGV都是全局常量。


#!/usr/bin/ruby

ARGV.each do |a|
puts “Argument: #{a}”
end

这个脚本我们通过循环遍历打印了ARGV的每个值。


$ ./commandline.rb 1 2 3

Argument: 1

Argument: 2

Argument: 3


我们给了三个命令行参数。它们在终端上各打印了一行。




接下来的例子介绍了处理环境变量。


#!/usr/bin/ruby

puts ENV[‘SHELL’]
puts ENV[‘LANG’]
puts ENV[‘TERM’]

这个脚本在终端上打印了三个环境变量的值。这些变量值的内容依赖于我们操作系统的系统设置。


$ ./environment.rb

/bin/bash

en_US.utf8

xterm


以上是一个输出例子。


伪变量


在Ruby中有一些变量被称作伪变量。它们不同于常规的变量,不能给它们设置值。

self是当前方法的接收者。nilNilClass的唯一实例,它代表值不存在。trueTrueClass的唯一实例,它代表布尔真。flaseFalseClass是唯一实例,它代表布尔假。

truefalse是布尔数据类型。从另一个角度来看他们是特殊的类实例,这是因为在Ruby中一切皆对象。


#!/usr/bin/ruby

p self
p nil
p true
p false

p self.class
p nil.class
p true.class
p false.class

这是一个伪变量的例子。我们打印所有的伪变量,然后再看它们的类名。


p self

在当前上下文self伪变量返回的是main执行的上下文。


$ ./pseudo.rb

main

nil

true

false

Object

NilClass

TrueClass

FalseClass


以上是例子的输出结果。




在本节的第二个例子,我们将进一步分析self


#!/usr/bin/ruby

class Some
puts self
end

class Other
puts self
end

puts self

之前我们说过,self是对当前方法接收者的引用。以上例子展示了三个不同的接收者。


class Some
puts self
end

这个接收者名为Some


class Other
puts self
end

这是另一个接收者,名为:Other


puts self

第三个接收者是Ruby顶级环境。


$ ./pseudoself.rb

Some

Other

main


以上是例子的输出结果。




本节的最后一个例子展示了另外三个伪变量。


#!/usr/bin/ruby

if true
puts “This message is shown”
end

if false
puts “This message is not shown”
end

p $name
p $age

上面的例子展示了truefalsenil伪变量。


if true
puts “This message is shown”
end

true用于布尔表达式中。这条消息总是会打印的。


if false
puts “This message is not shown”
end

这条消息永远不会打印。这个条件不成立。这个布尔表达式总是会返回一个负值。


p $name
p $age

如果全局变量没有初始化就引用,那么它们就会包含一个nil伪变量。这代表值不存在。


$ ./pseudo2.rb

This message is shown

nil

nil


以上是pseudo2.rb脚本的输出结果。


预定义变量


Ruby中有很多预定义的全局变量。这是继承到Perl,Ruby受Perl的影响很大。Ruby脚本启动之后就可以访问这些变量了。接下来有些例子展示预定义变量。


#!/usr/bin/ruby

print “Script name: “, $0, “\n”
print “Command line arguments: “, $
, “\n”

puts “Process number of this script: #{$$}”

以上使用了三个预定义变量。$0$$$$0存储了当前脚本的名字。$存储了命令行参数。 $$存储了当前脚本程序的PID。


$ ./predefined.rb 1 2 3

Script name: ./predefined.rb

Command line arguments: [“1”, “2”, “3”]

Process number of this script: 3122


以上是一个输出例子。




$?全局变量存储了最后一个子进程的退出状态。


#!/usr/bin/ruby

system ‘echo “Ruby”‘
puts $?

%x[exit ‘1’]
puts $?

我们执行两个子进程,然后使用$?查看它们的退出状态。


system ‘echo “Ruby”‘
puts $?

使用system方法启动一个子进程。它是一个bash的echo命令,用于在终端输出消息。


%x[exit ‘1’]
puts $?

第二个情况是使用状态1执行bash的exit命令。这次我们使用%x 操作符,用于执行一条被分隔符所选择的命令。


$ ./predefined2.rb

Ruby

pid 3131 exit 0

pid 3133 exit 1


第一个子进程退出状态为0,第二为1。




$;变量存储了字符串split方法的默认分隔符。


#!/usr/bin/ruby

str = “1,2,3,4,5,6,7”
p str.split

$; = “,”
p str.split

我们使用$;变量来控制字符串的split方法是如何分隔的。这个方法接收一个参数,用于确定字符串应该何处分隔。 如果这个参数省略了,那么将会使用$;的值。


$; = “,”
p str.split

我们为$;分隔符指定个值。当split方法没有传递参数时,$;的值将会被使用。


$ ./predefined3.rb

[“1,2,3,4,5,6,7”]

[“1”, “2”, “3”, “4”, “5”, “6”, “7”]


在第一种情况下字符串没有被分割,第二种情况下字符串正确的被分割了。




最后我们展示三个用于正则表达式的全局预定义变量。


#!/usr/bin/ruby

“Her name is Jane” =~ /name/

p $p $&amp; p $' </code></pre> <p>当我们对字符串使用<em>=~</em>保用符时,Ruby设置了一些变量。<em>$&amp;</em>变量设为最后一个匹配该正则式的内容。<em>$设为$&之前的内容.$’$&之后的内容。


$ ./predefined4.rb

“Her “

“name”

“ is Jane”


以上是这个例子的输出结果。


在这一章的教程中我们深入的学习了Ruby的变量。




原文地址: http://zetcode.com/lang/rubytutorial/variables/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程3——基础

基础

在这一章我们将覆盖Ruby语言的基本程序概念。我们展示一些非常基础的程序,使用到了变量、常量和基本的数据类型。从终端读取、写入内容;我们将会介绍变量的插值(interpolation)。


我们从一个非常简单的代码例子开始。



#!/usr/bin/ruby

puts “This is Ruby”



这个简单的脚本会在终端打印“This is Ruby”信息。



#!/usr/bin/ruby



这用于执行这个脚本的Ruby解释器的路径。



puts “This is Ruby”



puts是Ruby的关键字,用于将它的参数打印到终端上。在这个例子中它的参数是一个被双引号分隔的字符串。


$ ./first.rb

This is Ruby


以上是这个例子的输出结果。




我们可以从终端读取值。



#!/usr/bin/ruby

print “What is your name? “

name = gets
puts “Hello #{name}”



第二个程序将会从终端读取一个值并输出。



print “What is your name? “



print关键字是将参数打印到终端上。printputs的不同在于print不同自动换行,而puts会自动换行。



name = gets



这里我们将从用户输入中读取值并将其保存在name变量中。gets是一个方法用于从终端读取一行内容。它是一个内置的方法。



puts “Hello #{name}”



在这行代码我们展示变量的插值。变量插值(Variable interpolation)是将字符串字面量中的变量替换成它真实的值。变量插值(interpolation)的其他说法是:变量置换和变量扩展。



$ ./name.rb

What is your name? Jan

Hello Jan



以上是第二个程序的输出结果。




Ruby代码可以从命令行运行。这个是借鉴至Perl的单行方式,小块代码执行小任务。



$ ruby -e “puts RUBY_VERSION”

2.0.0



-e参数告诉Ruby要执行的代码从命令行中给定,而不是Ruby代码文件。我们例子将在终端输出Ruby解释器的版本号。

译注:原文的作者使用的是ruby 1.9.3,而如今ruby最新版已经是2.0.0了。




Ruby解释器有一个-c选项用于检查代码的语法。如果启用了的话,代码将不会被执行。如果代码没有语法错误,那么将会打印“Syntax OK”



#!/usr/bin/ruby

class Being end

m = Test.new

p m



以上例子中有一个语法错误。如果我们将classend关键字放在同一行,那么我们就必须还要使用分号字符(;)。


$ ruby -c syntax_check.rb

syntax_check.rb:3: syntax error, unexpected keyword_end, expecting ‘<’ or ‘;’ or ‘\n’

syntax_check.rb:6: syntax error, unexpected $end, expecting keyword_end


发现了语法错误。如果我们在Being的后面加上分号,错误提示消息就会消失。


命令行参数


Ruby程序可以从命令行接收参数。当我们执行程序时参数接在程序名的后面。



#!/usr/bin/ruby

puts ARGV



接在文件名后面的有效命令行参数被Ruby程序保存在全局数组ARGV中。


这里我们将所有的命令行参数打印到终端上。


$ ./args.rb 1 2 3

1

2

3


我们提供了三个数字作为命令行参数,并且它们都打印到终端上了。




在下面的例子中我们将打印所有的参数还有脚本名。



#!/usr/bin/ruby

puts $0

puts $



$0是全局变量,包含被执行的脚本的名称。在Ruby中全局变量是以$字符开头。$是另一个全局变量。它与ARGV是相等的,包含了命令行的所有参数。


$ ./args2.rb Ruby Python Perl

./args2.rb

Ruby

Python

Perl


args2.rb脚本接收了三个参数。脚本名和这三个参数都打印到终端上了。


变量和常量


变量是保存数据的地址。变量包括名称和数据类型。数据类型表示了数据的不同类型。整数、字符串和浮点数都是数据类型。Ruby是一门动态语言,这意味着我们不需要(也不能)定义一个变量的确定类型。而是Ruby解释器在分配变量时决定它的数据类型。此外,在程序运行时一个变量还可以包含不同类型的不同值。这与Java、C或者Pascal之类的强类型语言不同。与变量不同,常量(应该)保持它的值。一旦初始化了就不能修改。然后在Ruby中是有可能修改常量的值,这种情况下会出现一个警告。



#!/usr/bin/ruby

city = “New York”

name = “Paul”; age = 35

nationality = “American”


puts city

puts name

puts age

puts nationality


city = “London”


puts city



在上面的例子中我们使用了四个变量。



city = “New York”



我们给city变量分配了一个字符串。这个变量是动态创建的。



name = “Paul”; age = 35



创建两个变量。我们可以将两条语句放在一行里。然后为了提高可读性应该每行一条语句。



puts city

puts name

puts age

puts nationality



将变量的值打印到终端。



city = “London”



city变量分配新的值。


$ ./variables.rb

New York

Paul

35

American

London


这是以上例子的输出。




之前我们已经介绍过常量了,它一直都保存着一个值。但是不同于其他语言,Ruby没有对这个进行强制限制。



#!/usr/bin/ruby


WIDTH = 100

HEIGHT = 150


var = 40

puts var


var = 50

puts var


puts WIDTH

WIDTH = 110

puts WIDTH



在这个例子中定义了两个常量和一个变量。



WIDTH = 100

HEIGHT = 150



在Ruby中常量是以大写字母开头的。通常是将所有字母都大写。



var = 40

puts var


var = 50



定义并初始化一个变量。随后又给它分配了一个新的值,这是合法的。



WIDTH = 100



我们给常量分配了一个新的值。常量一旦创建就不应该改变,否则它就不意味着是一个常量。Ruby解释器将会给出一条警告。


$ ./constants.rb

40

50

100

./constants.rb:13: warning: already initialized constant WIDTH

110


以上是脚本的输出。


变量插值


变量插值(interpolation)是将字符串中的变量替换成它的值。变量插值的其他说法是:变量置换和变量扩展。



#!/usr/bin/ruby


age = 34

name = “William”


puts “#{name} is #{age} years old”



在Ruby中字符串是不可变的。我们不能修改一个已存在的字符串。变量插值是字符创建时进行的。



age = 34

name = “William”



定义两个变量。



puts “#{name} is #{age} years old”



字符串是被双引号所引起来。当我们将变量名放在#{}字符之间时,这个变量会被它的值所篡改。


$ ./interpolation.rb

William is 34 years old


以上是这个例子的输出。


这一章覆盖了Ruby语言的一些基础。




原文地址: http://zetcode.com/lang/rubytutorial/basics/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程2——词法结构

Ruby 词法结构

计算机语言跟人类语言类似也有词法结构。一个Ruby程序的源代码由符号构成。符号标志是最基本的代码元素。在Ruby语言中我们有多种词法结构,如:注释、变量、字面量、空白符号、操作符、分隔符和关键字。


注释


注释是用于向人们阐明源代码。在Ruby中有两种注释的方法,单行注释和多行注释。单行注释以#字符开始;多行注释是放置在=bgin=end 等号标志之间。



#!/usr/bin/ruby


=begin



comments.rb

author Jan Bodnar

ZetCode 2011



=end


# prints message to the terminal

puts “Comments example”



这个例子同时展示的两种方法的注释。注释的内容将会被Ruby解释器忽略掉。



=begin
comments.rb
author Jan Bodnar
ZetCode 2011
=end


这是一个多行注释的例子,两个符号标志必须在行首。


空白符号


在源文件中Ruby的空白符号被用于分隔符号标志和结束语句。它也用于增强代码的可读性。


if true then

  puts “A message”

end


空白字符在一些时候是必须的。例如在if关键字和true关键字之间;或者在puts方法和实际的字符串之间。而有时它又是被禁止的,如它不能包含在变量标识符或者语言关键字中。


a=1

b = 2

c  =  3


这些在符号标志之间的空白字符对于Ruby解释器是无关紧要的。但是它于整个项目的风格统一非常重要。





#!/usr/bin/ruby


x = 5 + 3

puts x


x = 5

    + 3

puts x


x = 5 +

    3

puts x



换行是一种用于结束语句的空白字符形式。


x = 5 + 3


在第一种情况,我们有一条语句。它将相加求和的值赋给x变量。这个变量的值为8。


x = 5

     +3


现在第二种情况。第1条语句被换行符终止了,x变量的值是5。另一条语句+3,没有任何影响。


x = 5 +

     3


最后,第1条语句的换行符之前有一个+二元操作符,因此解释器期望另一个值,它将检查第二行。在这种情况它将这两种作为一条语句,因此x这是的值为8。


$ ./whitespace.rb

8

5

8


以上为输出结果。


变量


变量是一个保存了值的标识符。在编程时我们说我们给一个变量分配一个值。专业一点的说法是一个变量是对计算机中存储了值的内存的引用。在Ruby中一个变量可以保存字符串、数字或者多种对象。不同时间变量可以被分配不同的值。

在Ruby中变量名由字母数字和下划线组成,但是不能以数字开头。Ruby解释器可以很容易地区分原始的数字跟变量。变量名不能以大写字母开头,在Ruby中以大写字母开头的标识符会被认为是一个常量。



Value

value2

company_name



以上这些都是合法的变量名。



12Val

exx$

first-name



以上这些都不是合法的变量名。


变量名前可以加$@这两个特殊的字符,它们用于创建特殊作用域的变量。


变量名是大小写敏感的,这意味着pricepRice是两个不同的标识符。



#!/usr/bin/ruby

number = 10

numBER = 11


puts number, numBER



在这个脚本中我们给两个标识符分配了两个数字。numbernumBER是两个不同的变量。



$ ./case.rb

10

11



以上是这个脚本运行的输出结果。


常量


常量的值在程序运行过程中是不变的。在Ruby中一个标识符的首字母大写即为一个常量。编程时对于常量约定是所有字母全都大写。

与其他语言不同,Ruby不会强制要求常量的值始终不变。当我们给一个常量分配新的值时解释器只会提示一个警告。



#!/usr/bin/ruby

Name = “Robert”

AGE = 23

Name = “Juliet”



在上面的例子中我们创建了两个常量,其中一个被重新定义了。



Name = “Robert”

AGE = 23



创建两个常量。在Ruby中标识符的首字母大写即定义为常量。作为约定常量通常是所有字母都大写的。



Name = “Juliet”



我们重新定义了一个常量,这会引起一个警告。



$ ./constants.rb

./constants.rb:6: warning: already initialized constant Name



以上是这个例子运行的输出。


字面量


字面量(literal)是按原文本内容所表示的特殊类型的值。字面量类型包括布尔型、整型、浮点型、字符串、字符和日期。专业的说一个字面量在编译时会分配一个值,该值在运行时会分配给对应的变量。



age = 29

nationality = “Hungarian”



这里我们分配了两个字面量变量。数字29和字符串“Hungarian”都是字面量。


#!/usr/bin/ruby

require ‘date’

sng = true
name = “James”
job = nil
weight = 68.5
born = Date.parse(“November 12, 1986”)

puts “His name is #{name}”

if sng == true
puts “He is single”
else
puts “He is in a relationship”
end

puts “His job is #{job}”
puts “He weighs #{weight} kilograms”
puts “He was born in #{born}”

在上面这个例子中,我们使用了多个字面量。布尔字面量的值可能为true或者falseJames是一个字符串字面量,nil表示一个不存在的值,68.5是一个浮点数,最后November 12,1986是一个日期。



$ ./literals.rb

His name is James

He is single

His job is

He weighs 68.5 kilograms

He was born in 1986-11-12



以上为literals.rb脚本的输出结果。


代码块


Ruby语句通常是放在代码块中。一个代码块可以被{}符号或者doend关键字分隔。


#!/usr/bin/ruby

puts [2, -1, -4, 0].delete_if { |x| x < 0 }

[1, 2, 3].each do |e|
puts e
end

这个例子中我们展示了两个代码块。


Ruby代码的控制流通常是使用if关键字。这个关键字k跟随着一个代码块,在这种情况下代码块被thenend关键字分隔,then关键字是可选的。


#!/usr/bin/ruby

if true then
puts “Ruby language”
puts “Ruby script”
end

在上面这个例子中,我们展示了一个简单的代码块。它有两条语句。这个代码块被thenend关键字分隔。then关键字可以省略。


符号


符号$@是特殊字符用于表示变量的作用域,$表示全局变量,@表示实例变量,@@表示类变量。



$car_name = “Peugeot”

@sea_name = “Black sea”

@@species = “Cat”



这些符号总是位于变量标识符的开头。


操作符


操作符是一个用于对值执行一个动作的符号。


!    +    -    ~        **    /    %
<< >> & | ^
== === != <=> >= >
< <= = %= /= -=
+=
= *= .. … not
and or ?: && ||

以上是在Ruby中所有有效的操作符,我们将在之后的教程中介绍它们。


分隔符


分隔符是一个或多个用于在纯文本或者其他数据流中指定分隔独立区域范围的字符序列。


(       )       [       ]       {       }
, ; ‘ “ | |

#!/usr/bin/ruby

name = “Jane”
occupation = ‘Student’
numbers = [ 2, 3, 5, 3, 6, 2 ]

puts name; puts occupation
puts numbers[2]
numbers.each { |i| puts i }
puts ( 2 + 3 )
5

在上面这个例子中我们展示多种Ruby分隔符的用法。



name = “Jane”

occupation = ‘Student’



在Ruby中单引号和双引号被用于分隔字符串。



numbers = [ 2, 3, 5, 3, 6, 2 ]



中括号用于指定数组的范围。逗号用于分隔数组项。



puts name; puts occupation



在Ruby中分号用于分隔两条语句。



puts numbers[2]



分隔符可用于不同的环境中,这里中括号用于访问数组。



numbers.each { |i| puts i }



大括号用于定义代码块。管道用于定义在每次循环中被当前数组项所填充的元素。



puts ( 2 + 3 ) * 5



括号用于改变一个表达式的求值。


关键字


关键字是在Ruby语言中被保留的字。关键字用于在计算机程序中展示特定的任务。例如:在终端中打印一个值,执行重复的任务或者展示逻辑操作。程序员不能使用关键字作为普通的变量。


alias    and      BEGIN      begin    break    case
class def defined? do else elsif
END end ensure false for if
in module next nil not or
redo rescue retry return self super
then true undef unless until when
while yield

这些是Ruby的关键列表。


以上就是Ruby的词法结构了。




原文地址: http://zetcode.com/lang/rubytutorial/lexis/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

[翻译]Ruby教程1——Ruby语言介绍

Ruby

在这部分Ruby教程中,我们将介绍Ruby编程语言。


目标


这个教程的目标是让你入门Ruby。这个教程覆盖了Ruby的主要内容,包括变量、表达式、集合、流程控制结构以及其他的一些主要特性。同样也会描述一些高级的概念,例如面向对象和正则表达式。这不会完全地覆盖这个语言。


Ruby


Ruby是一门动态的、反射的、通用的面向对象编程语言。它的源作者是一个日本程序员——松本行弘 (まつもとゆきひろ)。Ruby第一次发表是在1995年。


Ruby支持多种程序范式。包括面向对象、反射、命令式的和反射的编程。Ruby语言主要是受到Perl、Smalltalk、Eiffel和Lisp的影响。不同于java、C#以及C,Ruby没有官方的规范。取而代之的是用原始的C实现的Ruby语言作为实际参考。同时也还存在一些用其他方法实现的Ruby语言,如:JRuby、IronRuby或者MacRuby。


Ruby的官方网站是: ruby-lang.org


人气


如今有上百种编程语言,而Ruby属于最流行的一个。在langpop.comtiobe网站Ruby都排在第10名左右。Ruby on Rails——一个非常流行的web应用框架是使用Ruby开发第一个杀手级的应用。


交互式的解释器


我们可以通过脚本或者交互式的解释器来运行Ruby语句。在这个教程中我们将使用交互式的Ruby会话来展示一些小的代码片段。大的代码例子将放在Ruby脚本中。



$ irb

irb(main):001:0> puts RUBY_VERSION

2.0.0

=> nil



这是一个Ruby交互会式会话的例子。我们在终端中打印了一个特别的常量RUBYVERSION,它被设置为当前使用的Ruby的版本。

译注:原文的作者使用的是ruby 1.8.7,而如今ruby最新版已经是2.0.0了,因此我在翻译的时候也结合了当前新的内容。


Ruby脚本


我们开始我们的第一个简单的Ruby脚本例子。



#!/usr/bin/ruby

# first.rb

puts “This is Ruby”



这个脚本我们将在终端上打印一条消息。



#!/usr/bin/ruby



UNIX下的每一个脚本都是以shebang符号开始的。shebang是脚本中开始的前两个字符:#!。shebang后面是执行我们脚本的解释器的路径。/usr/bin是Ruby解释器最常用的位置。它也可以定位在/usr/local/bin或者其他什么地方。



# first.rb



在Ruby中注释是以#开始。



puts “This is Ruby”



puts方法是将字符串打印到终端。



$ which ruby

/usr/bin/ruby



Ruby解释器的路径可以使用which命令找到。



$ chmod +x first.rb

$ ./first.rb

This is Ruby



通过chmod命令,我们给脚本增加可执行的权限。


资源


以下资源在编写该教程时会使用到:

ruby-lang.org

ruby-doc.org

<a href=”http://en.wikipedia.org/wiki/Ruby(programming_language)”>Ruby article on wikipedia.org

ruby.runpaint.org


在这章的教程中我们介绍了Ruby语言。




原文地址: http://zetcode.com/lang/rubytutorial/ruby/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial

Scrapy框架学习笔记3—— Scrapy与mongodb结合

创建一个新的Item Pipeline,并将其添加到settings.py的ITEM_PIPELINES列表中。
在process_item方法中将item的数据保存到mongodb中。
scrapy的Item与dict相似,而mongodb中的数据是心bson格式保存的。因此Item的数据应该可以直接存储到mongodb中而几乎不用做额外的处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyMongoDBPipeline(object):
def __init__(self, mongodb_server, mongodb_port, mongodb_db, mongodb_collection):
connection = pymongo.Connection(mongodb_server, mongodb_port)
self.mongodb_db = mongodb_db
self.db = connection[mongodb_db]
self.mongodb_collection = mongodb_collection
self.collection = self.db[mongodb_collection]

@classmethod
def from_crawler(cls, crawler):
# 连接mongodb
return cls('localhost', 27017, 'scrapy', 'items')

def process_item(self, item, spider):
result = self.collection.insert(dict(item))
log.msg("Item %s wrote to MongoDB database %s/%s" % (result, self.mongodb_db, self.mongodb_collection),
level=log.DEBUG, spider=spider)
return item