Ruby是面向对象的语言
Ruby是一个真正的面向对象的语言,你所操作的任何东西都是对象,这些操作本身返回的也是对象。
在Ruby中,这些对象是调用构造器来创建的,构造器是类的一个特殊方法。标准的构造器叫做new。
song1 = Song.new("Ruby Tuesday") song2 = Song.new("Enveloped in Python") # and so on |
这些实例都源自同一个类,但它们又都有唯一的特性。第一,每个对象都有一个唯一的object identifier(简写作object id),就是对象标识符。第二,你可以定义实例变量,变量的值对每个实例来说都是唯一的,这些实例变量记录着对象的属性。比如说我们的每一首歌曲,都可能有一个实例变量记录了歌曲的标题。
每一个类你都可以定义实例方法。方法是功能的集合体,可以在类中或者类以外(取决于访问级别)被调用。这些实例方法可以访问对象的实例变量,当然也就可以访问对象的属性。
"gin joint".length >> 9
"Rick".index("c") >> 2
-1942.abs >> 1942
sam.play(aSong) >> "duh dum, da dum de dum ..."
Ruby的一些基本知识
我们开始于一个简单的Ruby程序,我们写一个方法来返回一个字符串,给这个字符串附加一个人名,我们会调用两次这个方法。
def sayGoodnight(name) result = "Goodnight, " + name return result end
# Time for bed... puts sayGoodnight("John-Boy") puts sayGoodnight("Mary-Ellen") |
ruby语法是干净的,不需要在行尾加上分号,一行一个语句。Ruby注释开始于#号,结束在行尾.
方法是由关键字def来定义的,紧跟着方法的名字(本例中是“sayGoodnight”),方法的参数括在圆括号中。Ruby不使用大括号来划定复合语句和定义的界限,而是简单地用关键词end来结束它们。
“puts sayGoodnight("John-Boy")”这行包含了两个方法调用,一个调用sayGoodnight另一个调用puts,为什么这两个方法中有一个它的参数括在圆括号中,而另一个却没有圆括号,这种情况纯粹取决于感觉,下面的行是完全等价的:
puts sayGoodnight "John-Boy" puts sayGoodnight("John-Boy") puts(sayGoodnight "John-Boy") puts(sayGoodnight("John-Boy")) |
第二件事就是Ruby要修改双引号括住的字符串,字符串中的#{表达式}序列要用表达式的值来替换,我们用这个来重写前面的方法。
def sayGoodnight(name) result = "Goodnight, #{name}" return result end |
当Ruby构造这个字符串对象时,它找到name的当前值,并在字符串中替换它。#{...}结构中可以放入任意复杂的表达式,一个简洁的写法是,如果表达式是一个简单的全局变量、实例或者类变量,那么就不必写出大括号。
可以让这个方法更加简化,一个Ruby方法的返回值默认是最后被求的表达式的值,所以我们可以省略掉return语句。
def sayGoodnight(name)
"Goodnight, #{name}"
end
Example variable and class names
Variables Constants and
Local Global Instance Class Class Names
name $debug @name @@total PI
fishAndChips $CUSTOMER @point_1 @@symtab FeetPerMile
x_axis $_ @X @@N String
thx1138 $plan9 @_ @@x_pos MyClass
_26 $Global @plan9 @@SINGLE Jazz_Song
数组和哈希
数组----一个方括号括起来的元素集合
a = [ 1, 'cat', 3.14 ] # 三个元素的数组
# 访问第一个元素
a[0] >> 1
# 设置第三个元素的值
a[2] = nil
# 输出数组的值
a >> [1, "cat", nil]
你可以创建一个空数组,用一个没有元素的数组的字面值,或者用数组对象的构造器,Array.new。
empty1 = [] empty2 = Array.new |
直接把字符串变成数组:
a = %w{ ant bee cat dog elk }
a[0] >> "ant"
a[3] >> "dog"
Ruby的哈希和数组相似,一个哈希的字面值使用大括号而不是方括号
举例来说,你可能希望把管弦乐团的乐器归类,使用哈希的话就是:
instSection = { 'cello' => 'string', 'clarinet' => 'woodwind', 'drum' => 'percussion', 'oboe' => 'woodwind', 'trumpet' => 'brass', 'violin' => 'string' } |
索引哈希使用和数组一样的方括号。
instSection['oboe'] >> "woodwind" instSection['cello'] >> "string" instSection['bassoon'] >> nil |
如果使用一个不存在的键来索引哈希,默认返回nil
控制结构
if count > 10
puts "Try again"
elsif tries == 3
puts "You lose"
else
puts "Enter a number"
end
while weight < 100 and numPallets <= 30
pallet = nextPallet()
weight += pallet.weight
numPallets += 1
end
if radiation>3000 puts "Danger,Will Robinson" end |
这次用语句修饰符来重写。
|
puts "Danger,Will Robinson" if radiation>3000
(非常自然的语言,很接近程序员的思维方式,你怎么想就怎么写,而不是按着语言的规矩写)
同样的,一个while循环如下:
while square < 1000 square = square*square end |
变得更简洁,
|
square = square*square while square < 1000
正则表达式
正则表达式虽然晦涩难懂,但确实是处理文本的绝佳工具。(深有同感!)
在Ruby中,用两个斜线括住的模式来显式地创建一个正则表达式(/pattern/),而且,由于Ruby之所以为Ruby的原因,正则表达式当然的也是对象,并且能被处理。
举例,你要写一个模式来匹配一个包含"Perl"或者"Python"的字符串,就用下面的正则表达式:
也可以在模式中重复声明,/ab+c/匹配一个字符串,它包含一个"a",然后是一个或者多个"b",然后是一个"c"。如果把加号改成星号,就是/ab*c/那么创建的正则表达式是匹配一个"a",0或者更多的"b",和一个"c"。 你也可以用一个模式来匹配一组字符,常见的如"\s"匹配空白字符(空格、Tab、换行符等),"\d"匹配所有的数字,"\w"匹配所有的可打印字符,简单的一个字符"."(一个点号)匹配任意字符。 (这些规则跟一般的正则差不多的,应该说基本一样吧)
匹配算符"=~"用在正则表达式匹配一个字符串的时候。当模式在字符串中被匹配到后,=~返回它开始的位置,否则返回nil。
if line =~ /Perl|Python/ puts "Scripting language mentioned: #{line}" end
代码块和迭代器 (译者注:代码块就是blocks的直译)
你可以使用代码块实现回调,传递一系列代码(但要比C的函数指针更加复杂),和实现迭代器。
代码块是用大括号或者do...end括起来的一系列代码。
{ puts "Hello" } # 这是一个代码块
do # club.enroll(person) # 这也是代码块 person.socialize # end # |
一旦你创建了一个代码块,就可以把它和一个方法调用关联在一起。那个方法能够调用代码块一次或者更多次,用Ruby的yield语句。
def callBlock yield yield end
callBlock { puts "In the block" } |
结果:
你可以在调用yield时给出参数,这些参数传递给代码块。在代码块中,列举变量的名字来接受参数,这些参数被用"|"括着。 代码块贯穿在实现迭代器的Ruby库中,迭代器就是一种方法,用来连续返回某种集合的元素,比如一个数组。
|
a = %w( ant bee cat dog elk ) # 创建一个数组 a.each { |animal| puts animal } # 迭代所有的内容 produces: ant bee cat dog elk
|
5.times { print "*" } 3.upto(6) {|i| print i } ('a'..'e').each {|char| print char } |
结果:
(怎么都是代码块实现的?times,upto,each函数)
读写 puts把它的所有参数写出来,每一个都加入一个新行,print也写出它的参数,不过没有新行。它们两个都能向任意的I/O对象写入,不过默认是写入控制台。 (就是可以重定向而已了)
另一个常用的输出方法是printf,它按格式输出参数(就像C或者Perl的printf)。
| printf "Number: %5.2f, String: %s", 1.23, "hello" | 结果:
| Number: 1.23, String: hello | 有很多种方式来把输入读取到你的程序中,也许,最传统的就是使用gets例程,它从你的程序的标准输入流中返回下一行。
gets例程有一个附带效果,它除了返回读取的行,还把它储存到全局变量$_中,这个变量很特殊,在很多环境中它作为默认变量使。如果你调用print而没有带参数,它显示$_的内容;如果你写一个if或者while语句时仅仅使用一个正则表达式作为条件,那么这个表达式匹配的对象是$_。尽管一些纯粹主义者把这看作是令人讨厌的野蛮行径,但是这些简写确实又能帮助我们写出简洁的程序来。例如,下面的程序现实输入流中的所有行中包含"Ruby"单词的行。
while gets # assigns line to $_ if /Ruby/ # matches against $_ print # prints $_ end end |
Ruby方式的写法是使用迭代器:
| ARGF.each { |line| print line if line =~ /Ruby/ } |
这里使用了预定义对象ARGF,它描述可以被程序读取的输入流。 (这篇比较长,而且讲了些语法方面的东西,不过不够详细,应该好好学习,然后写一些例子熟悉下,慢慢理解下)
| |