博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

sislcb

寻找自己
sislcb.cublog.cn
Programming Ruby--Ruby的新特性
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"的字符串,就用下面的正则表达式:

/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" }



结果:

In the block
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 }


结果: 

*****3456abcde

(怎么都是代码块实现的?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例程,它从你的程序的标准输入流中返回下一行。

line = gets
print line
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,它描述可以被程序读取的输入流。
(这篇比较长,而且讲了些语法方面的东西,不过不够详细,应该好好学习,然后写一些例子熟悉下,慢慢理解下)


 

发表于: 2007-08-14,修改于: 2007-08-14 11:39,已浏览489次,有评论0条 推荐 投诉

给我留言
版权所有 ChinaUnix.net 页面生成时间:0.02283