燕之庐网站建设 - 优质网站设计公司

Posts Tagged ‘ruby’

ruby

2010/01/16

Ruby程序快速入门之输入输出和标准库

Tags:

输入输出

在所有的本系列文章中,在编写Ruby代码时都使用了大量的Ruby标准输出方法。其中,最为常用的是print和puts方法,有关其使用细节不再赘述。

所有这些和其它处理输入和输出的方法都定义于Kernel模块中。这个Kernel模块又被包含在Object类中。因此,Kernel的方法出现在每 一个对象中。在输出方面,Kernel定义了print,printf,putc和IO类和两个子类(File和BasicSocket)-它们允许读写 文件和套接字。BasicSocket是套接字库的一部分并且将在以后讨论它。包含了FileTest模块的File类,提供了许多方法来操作系统文件和 目录。从Kernel中使用的用于读写到标准输入/输出机制的方法被进一步重用于File实例中的读写操作。下面是一个代码示例-它把一些名字写入一个新 建的文件中,然后再把这些名字读回到一个数组中。

customers=%w[Jim Kevin Davin Andrew]
outFile = File.new(”c:\\examples\\test\\customers.txt”, “w”)
customers.each{|customer| outFile.puts(customer)}
outFile.close
inFile= File.new(”c:\\examples\\customers.txt”, “r”)
readCustomers=inFile.readlines
readCustomers.each{|customer| puts customer}
inFile.close

标准库

Ruby除了提供大量内置的类和模块外,它还提供了一定数目的标准库。这些库不是自动地成为你可以利用的Ruby类,模块,方法的一部分。你必须先在你 的文件的顶部使用require(或load)关键字来使用库中的类或模块。在前一节中,我曾提到一个库-套接字库,它包含了大量的Ruby类(包括 BasicSocket),以便于访问网络服务。但是在Ruby下载中一同提供了一整套其它的库。你可以查看一下你的Ruby下载中的lib目录,这个目 录下应该存在大量的你的Ruby程序需要使用的库。

有关这些库的不好的一点是,没有大量的有关于这些类的参考文档。你可以在网站http://www.ruby-doc.org/stdlib/上找到一系列标准库及其包含类和模块的文件。即使是这些文档也指出:

“你需要明白,在表格中粗体的库具有良好的文档,而斜体的库没有文档。”

这就是Ruby的现状。你可能想说,Ruby是一个不可思议地丰富而有力的语言并且内置了许多构建我们的应用程序需要的功能,但是文档仍然有点不足。还 好,现在已经有不少的人在努力改进Ruby的文档和支持。现在有不少的Ruby论坛已经倔起,并且随着每一个新版本的发行,文档都将有一定的改进-当然, 这也是最近它备受关注的结果。然而,帮助文档仍然会成为这种语言挫败人心的一个因素。

北京网站建设公司

ruby

Ruby程序快速入门之输入输出和标准库

Tags:

输入输出

在所有的本系列文章中,在编写Ruby代码时都使用了大量的Ruby标准输出方法。其中,最为常用的是print和puts方法,有关其使用细节不再赘述。

所有这些和其它处理输入和输出的方法都定义于Kernel模块中。这个Kernel模块又被包含在Object类中。因此,Kernel的方法出现在每 一个对象中。在输出方面,Kernel定义了print,printf,putc和IO类和两个子类(File和BasicSocket)-它们允许读写 文件和套接字。BasicSocket是套接字库的一部分并且将在以后讨论它。包含了FileTest模块的File类,提供了许多方法来操作系统文件和 目录。从Kernel中使用的用于读写到标准输入/输出机制的方法被进一步重用于File实例中的读写操作。下面是一个代码示例-它把一些名字写入一个新 建的文件中,然后再把这些名字读回到一个数组中。

customers=%w[Jim Kevin Davin Andrew]
outFile = File.new(”c:\\examples\\test\\customers.txt”, “w”)
customers.each{|customer| outFile.puts(customer)}
outFile.close
inFile= File.new(”c:\\examples\\customers.txt”, “r”)
readCustomers=inFile.readlines
readCustomers.each{|customer| puts customer}
inFile.close

标准库

Ruby除了提供大量内置的类和模块外,它还提供了一定数目的标准库。这些库不是自动地成为你可以利用的Ruby类,模块,方法的一部分。你必须先在你 的文件的顶部使用require(或load)关键字来使用库中的类或模块。在前一节中,我曾提到一个库-套接字库,它包含了大量的Ruby类(包括 BasicSocket),以便于访问网络服务。但是在Ruby下载中一同提供了一整套其它的库。你可以查看一下你的Ruby下载中的lib目录,这个目 录下应该存在大量的你的Ruby程序需要使用的库。

有关这些库的不好的一点是,没有大量的有关于这些类的参考文档。你可以在网站http://www.ruby-doc.org/stdlib/上找到一系列标准库及其包含类和模块的文件。即使是这些文档也指出:

“你需要明白,在表格中粗体的库具有良好的文档,而斜体的库没有文档。”

这就是Ruby的现状。你可能想说,Ruby是一个不可思议地丰富而有力的语言并且内置了许多构建我们的应用程序需要的功能,但是文档仍然有点不足。还 好,现在已经有不少的人在努力改进Ruby的文档和支持。现在有不少的Ruby论坛已经倔起,并且随着每一个新版本的发行,文档都将有一定的改进-当然, 这也是最近它备受关注的结果。然而,帮助文档仍然会成为这种语言挫败人心的一个因素。

北京网站建设公司

ruby

Ruby入门之代码块、迭代子和过程对象

Tags:

在Ruby的一切都是一个对象。甚至一个代码块也是一个对象!在Ruby中,代码对象被称为代码块。你可以把代码块想像成小的程序单元。它们包含 Ruby代码并且能够在执行它们时转入到方法中。在Python,C和Java中与之类似的概念是函数指针,匿名函数,内部类和回调函数。

Ruby代码块的语法是,把Ruby代码放在大括号之间或放在do/end命令之间。如下所示:

{
#这是一个代码块…
}
do
#…并且这也是一个代码块
end

在一个很简单的实例中,{puts”hello world”}就是一个有效的代码块。那么,你应该如何使用这些代码块并且把它们作为一组代码传递给一个方法呢?为此,首先要定义一个如下形式的简单方法:

def someMethod
yield
end

命令yield把控制传递给代码块(它被传递给这个方法)。下面的代码向你展示,一个代码块是如何被传递到上面这个方法的。

irb(main):001:0> someMethod {puts “hello world”}
hello world

每当调用yield时,执行传递到该方法的代码块。下面是另一个更复杂些的方法的例子,它使用了一个代码块来做更多的工作。

irb(main):001:0>
def fibonacci (stop)
while stop < 20
stop=yield
end
end
=> nil
irb(main):006:0>
i=0; j=1; fibonacci(j) {puts i; temp = i; i = j;j = temp + j}
0
1
1
2
3
5
8

代码块被应用于整个Ruby中。最重要的是,代码块被Ruby内部地应用于象Array,Hash,甚至String这样一些类的iterator方法 中。一个代码块其实就是,你定义要执行什么任务(典型地,是针对一个元素的任务)。为了进一步说明代码块和iterator的使用,我们提供了一个小例 子。假定你定义了一些场院动物类(如图3所示),还有一个这些动物的数组,你可以通过在这个数组上使用一个代码块和一个迭代子来实现让每一种动物发声。


图3.简单的场院动物类
irb(main):031:0>
barnYard = [Cow.new, Duck.new, Chicken.new, Horse.new, Dog.new]
=> [#<Cow:0x58d2f48>, #<Duck:0x58d2f30>, #<Chicken:0x58d2f00>, #<Horse:0x58d2ee8>, #<Dog:0x58d2ed0>]
irb(main):032:0>
barnYard.each {|animal| animal.talk}
Mooooo
Quack
Cluck-cluck
Naaaay
Bark bark

在barnYard上调用的每个方法正是一个数组上的iterator方法之一。注意,|符号用于定义要接收的参考。在本例情况中,代码块接收一个参数;也就是把barnYard中的每一种动物作为迭代子来遍历这个动物集合。

迭代子和代码块甚至允许我们完成如下一些相当简单和整洁的事情:

irb(main):001:0>
3.times {puts “Ruby is cool!”}
Ruby is cool!
Ruby is cool!
Ruby is cool!

是的,即使是Integer类也提供了一个迭代子(times方法)-它使用一个代码块来快速地执行循环操作。

在离开有关代码块和迭代子的讨论前,你还应该知道代码块可以被赋值给一个变量。事实上,这样的代码块实际上是Proc类的实例。你可以使用new方法来定义一个Proc实例,或者使用这些Proc实例-这些实例稍后可以使用call方法来调用。

irb(main):003:0> simpleProc.call
hello
=> nil
irb(main):004:0> anotherProc.call(”hello yourself”)
hello yourself
=> nil

这允许一个可重用的代码块可以被包装为一个对象(它可以在任何地方执行)而进行传递。下面是显示Ruby中可重用代码的示例!

irb(main):001:0>
def simpleMethod(aProc)
puts “Is Ruby cool or what?”
aProc.call(”Way cool dude!”)
end
=> nil
irb(main):005:0>
simpleMethod(anotherProc)

Ruby酷不酷?相当不错!

北京网站建设公司

ruby

Ruby程序快速入门之数据结构

Tags:

就象许多程序语言一样,Ruby也提供了完整的数据结构来存储和管理数据与对象。数组是使用方括号和用逗号隔开的单个对象参考列表创建的。

presidents=["John","Richard","Gerald","Ronald","George","William"];

为了更为容易地创建一个充满单词的数组,Ruby提供了一个特殊的标志来消除双引号和逗号,见下面例子:

presidents= %w[ John Richard Gerald Ronald George William];

在其它编程语言中,”数组”一词经常意味着一组相同性质的对象的集合。但在Ruby中,不是这样。在Ruby中,一个”数组”可以是由不同性质的对象参考组成的集合。因此,下面是有效的数组表达形式:

order_date=Date.today()
shirt_information=[14.5,"Long",32,order_date]

在这个数组中,对象参考按顺序存储并索引。象Java一样,索引从0开始,索引可用来从数组中检索对象参考。下面的示例中请求的是,上面创建的 shirt_information数组中的第3个元素(索引为2)。注意,你可以使用方括号标志或at方法来检索数组中的对象参考。

irb(main):003:0> shirt_information[2]
=> 32
irb(main):004:0> shirt_information.at(2)
=> 32

有趣的是,你还可以使用一个负数索引来引用数组中的元素。一个负数索引是从数组尾部开始计数的。

irb(main):005:0> shirt_information[-3]
=> “Long”

数组是动态的,意味着数组的大小可以根据你的操作而动态地改变。你可以使用[index]=操作符来添加或替换一个数组中的元素。

irb(main):013:0> shirt_information
=> [14.5, "Long", 32, #<Date: 4907585/2,0,2299161>]
irb(main):014:0> shirt_information[1]=”Medium” #change shirt length
=> “Medium”
irb(main):015:0> shirt_information[4]=49.99 #add shirt cost
=> 49.99
irb(main):016:0> shirt_information
=> [14.5, "Medium", 32, #<Date: 4907585/2,0,2299161>, 49.99]

你也可以使用数字对和范围来由数组的一部分创建一个新数组,通过使用一个[开始索引,元素数目]标志或[开始索引...结束索引]标志。

irb(main):019:0> shirt_information
=> [14.5, "Long", 32, #<Date: 4907585/2,0,2299161>, 49.99]
irb(main):020:0> shirt_dimensions = shirt_information[0,3]
=> [14.5, "Long", 32]
irb(main):021:0> shirt_order = shirt_information[2..5]
=> [32, #<Date: 4907585/2,0,2299161>, 49.99]
irb(main):030:0> shirt_information[-3,2]
=> [32, #<Date: 4907585/2,0,2299161>]

这个结合了赋值运算符([]=)的标志将产生一个很复杂的元素插入或代替操作。一个开始/结束索引或范围可以用在赋值操作符中。具体使用请参考下面的示例:

irb(main):001:0> test_array=["zero", "one", "two", "three", "four"]
=> ["zero", "one", "two", "three", "four"]
irb(main):002:0> #starting at the second element, replace the next
two elements with a single element
irb(main):003:0* test_array[1,2]=1
=> 1
irb(main):004:0> test_array
=> ["zero", 1, "three", "four"]
irb(main):005:0> #insert a new element after the second one
(zero as a second parameter indicates “insert”)
irb(main):006:0* test_array[2,0]=2
=> 2
irb(main):007:0> test_array
=> ["zero", 1, 2, "three", "four"]
irb(main):008:0> #add an array of elements after element 5
irb(main):009:0* test_array[5,0]=[5,6,7]
=> [5, 6, 7]
irb(main):010:0> test_array
=> ["zero", 1, 2, "three", "four", 5, 6, 7]
irb(main):011:0> #replace elements in the index range of 3..4 with the array assigned
irb(main):012:0* test_array[3..4]=[3,4]
=> [3, 4]
irb(main):013:0> test_array
=> ["zero", 1, 2, 3, 4, 5, 6, 7]

最后,也许Ruby数组中最有力量的运算可以从数学操作符中找到答案-它们能够从现在数组创建新的数组。例如,+操作符允许你由两个数组的连接创建一个新数组,而*操作符允许你复制或连接一个数组自身若干次。

irb(main):033:0> shirt_information
=> [14.5, "Long", 32, #<Date: 4907585/2,0,2299161>, 49.99]
irb(main):034:0> pant_information=[34,32,59.99,order_date]
=> [34, 32, 59.99, #<Date: 4907585/2,0,2299161>]
irb(main):035:0> shirt_information + pant_information
=> [14.5, "Long", 32, #<Date: 4907585/2,0,2299161>, 49.99, 34, 32, 59.99,
#<Date: 4907585/2,0,2299161>]
irb(main):036:0> shirt_information * 2
=> [14.5, "Long", 32, #<Date: 4907585/2,0,2299161>, 49.99, 14.5, "Long", 32,
#<Date: 4907585/2,0,2299161>, 49.99]
irb(main):037:0> array1 = [2,4,6,8,10]
=> [2, 4, 6, 8, 10]
irb(main):038:0> array2=[3,6,9]
=> [3, 6, 9]
irb(main):039:0> array1 – array2
=> [2, 4, 8, 10]

在Ruby中,与数组联系最密切的就是哈希表。在一个数组中,索引是一个整数。在Ruby中Hash类行为上与Array非常相似,但是它允许在集合中 出现到参考对象的任何类型的对象”索引”(或键)。在另外的程序语言中,这可能被称为一个字典或地图或哈希地图。一般地,当使用哈希表时,你应该为集合中 的每个元素提供两个对象参考。其中,一个对象参考用作键,另一个用作该键所指对象(即”值”)。用于指示一个键对象所指内容的标志是=>符号。当创建哈希 表时,键/值对可以在两个大括号之间被收集。作为一个哈希表的例子,你可以在哈希表中使用简单的字符串对象作为键来引用Date对象(值)。

holidays={”New Year”=>Date.parse(”2006-01-02″), “MLB Birthday”=> Date.parse(”2006-01-16″),
“Washington Birthday”=>Date.parse(”2006-02-20″), “Memorial Day”=>Date.parse(”2006-05-29″), “July
4th”=>Date.parse(”2006-07-05″)}

为了检索纪念日的Date对象,你可以使用”Memorial Day”字符串键。

irb(main):004:0> holidays["Memorial Day"]
=> #
irb(main):005:0> holidays["Memorial Day"].to_s
=> “2006-05-29″

如你所想,在数组和哈希表中还有另外许多方法来允许你存取和修改集合中的单个元素或改变全部集合本身。因此,在Ruby中,数组和哈希表都是功能极强的动态的数据结构。

一旦你有一个对象参考的集合,那么在编程中最常用的一项任务就是遍历该集合中的每一个元素并执行某些操作。Ruby当然也提供了数组和哈希表中的类似机 制。Ruby提供的实现遍历集合的机制是该集合对象上的一组方法。Array中的方法(如each,each_index,delete_if)和 Hash中的方法(如each,each_key,each_value,each_pair)允许你的编码进行集合遍历并执行特定的任务。事实 上,Ruby中的许多类都包含迭代子(iterator)方法。例如,String就提供了一个iterator方法来执行字符串的以字符或字节为单位的 遍历任务。然而,在你理解iterator方法前,你首先需要理解Ruby中代码块的概念。因为当遍历集合中的元素时,对于每一个iterator方法, 都是通过传递一个代码块来执行的。

北京网站建设公司

ruby

Ruby程序快速入门之数字、字符串和其它

Tags:

在Ruby中,一切都是对象。更精确地说,Ruby中的一切都是一个具有完整功能的对象。因此,在Ruby中,数字4,定点数3.14和字符 串”Hi”都是对象。显然,它们是有点”特殊”的,因为你不必使用new方法来创建它们。代之的是,你使用例如”literal 4″这样的形式来创建一个代表数字4的对象的实例。

然而,对于绝大多数人来说,学习一种新的编程语言时,首先理解该语言提供的”标准”类型是非常有用的。所以,在这一节,我们先探讨数字类型,字符串类型,布尔类型和另外一些基本的Ruby数据类型。

数字类型

实质上,Ruby中的数字被分为整数和浮点数两大类。其中,整数又被进一步细分为”常规大小”的整数和大型整数。因为在Ruby中一切都是对象,所以整 数和浮点数都是按类来定义的(见图1)。从图1看出,Numeric是所有数字类型的基类,Float和Integer类是Numeric的子类。 Fixnum和Bignum都是Integer的子类型-它们分别定义了”常规大小”的整数和大型整数。


图1.Ruby的数字类型类继承图。

Literal用来描述这些类的实例。下面的在交互式Ruby外壳(irb)中的代码显示了Float,Fixnum和Bignum的literal实例。注意,可以在literal上进行方法调用(在此,是指类方法)。

irb(main):001:0> 3.class
=> Fixnum
irb(main):002:0> 3.4.class
=> Float
irb(main):003:0> 10000000000000000000.class
=> Bignum

还有另外一些语法用来创建数字类型,显示于下面的代码列表中。字母E可以用来描述以指数标志的数字。数字的前面加上0代表这是一个八进制数,加上0x代 表这是一个十六进制数,而0b代表是一个二进制数。为清晰起见,下划线可以用作数字中的分隔符号。注意,当写literal时,不要用逗号作为分隔符号。 在一些情况中,这实际上能生成一个数组,我们将在后面讨论。最后,在一个字符(或Ctrl或元字符的组合)前面的一个问号将会创建一个Fixnum的实 例,相应于字符的ASCII字符/逃逸序列值。

<
irb(main):001:0> 3.14E5 #指数标志
=> 314000.0
irb(main):002:0> 054 #八进制
=> 44
irb(main):003:0> 0×5A #十六进制
=> 90
irb(main):004:0> 0b1011 #二进制
=> 11
irb(main):005:0> 10_000 #10,000,用下划线隔开
=> 10000
irb(main):006:0> i=10,000 #创建一个数组而不是10000 Fixnum
=> [10, 0]
irb(main):007:0> i.class
=> Array
irb(main):008:0> ?Z #Fixnum ASCII值
=> 90
irb(main):009:0> ?Z.class
=> Fixnum
irb(main):010:0> ?\C-s #Control-s的值ASCII
=> 19

Fixnum和Bignum实例间的真实差别是什么?Fixnum整数可以被存储在机器中的一个字(通常16,32或64位)中,但减去1个位;而 Bignum实例是超出固定存储空间的整数。当然,作为开发者,你不必担心整数的大小(见下面的例子),由Ruby负责为你实现Fixnum和 Bignum之间的自动转换!

irb(main):001:0> i=4
=> 4
irb(main):002:0> i.class
=> Fixnum
irb(main):003:0> i=i+100000000000000
=> 100000000000004
irb(main):004:0> i.class
=> Bignum
irb(main):005:0> i=i-100000000000000
=> 4
irb(main):006:0> i.class
=> Fixnum

字符串

在Ruby中,字符串是任意顺序的字节。通常,它们是一个字符序列。在Ruby中,可以使用一个literal或new方法来创建String类的实例。

irb(main):001:0> s1=”Hello World”
=> “Hello World”
irb(main):002:0> s2=String.new(”Hello World”)
=> “Hello World”

当然,String中定义了许多方法(和操作符)。另外,可以使用单引号或双引号来指定一个字符串。双引号情况下允许串中加入逃逸字符并能够嵌入待计算的表达式。在单引号串情况下,你看到的就是串中的实际内容。为了更好的理解,请看下列例子。

irb(main):001:0> str1=’a \n string’
=> “a \\n string”
irb(main):002:0> str2=”a \n string”
=> “a \n string”
irb(main):003:0> puts str1
a \n string
=> nil
irb(main):004:0> puts str2
a
string
=> nil
irb(main):005:0> ‘try to add #{2+2}’
=> “try to add \#{2+2}”
irb(main):006:0> “try to add #{2+2}”
=> “try to add 4″
irb(main):007:0> this=”that”
=> “that”
irb(main):008:0> ‘when single quote rights #{this}’
=> “when single quote rights \#{this}”
irb(main):009:0> “double quote rights #{this}”
=> “double quote rights that”

请注意,在显示之前,双引号中的文本是如何被计算的,其中包括了逃逸符号(\n)和表达式(#{2+2})。

除了使用单引号和双引号来定义一个字符串literal外,在Ruby中,还有另外的方法可以表达literal。一个百分号和小写或大写字母Q可以用来表达一个字符串,分别相应于单引号或双引号风格。

irb(main):001:0> %q@this is a single quote string #{2+2} here@
=> “this is a single quote string \#{2+2} here”
irb(main):002:0> %Q@this is a double quote string #{2+2} here@
=> “this is a double quote string 4 here”

注意,跟随在q%或Q%后面的字符分别定义了字符串literal的开始和结束。在本例中,@符号用作字符串开始与结束的限界符号。

还应该注意,Ruby并没有区分一个字符串和一个字符。也就是说,没有适用于单个字符的特定的类-它们仅是一些小的字符串。

北京网站建设公司

ruby

Ruby程序快速入门之多继承

Tags:

一些程序语言(如C++和CLOS)提供了多重继承机制:一个类可以继承自多个超类。例如,一个House可能继承自一个Building类(连同 Office和Hospital类一起)和Residence类(连同Apartment类一起)。尽管多重继承可能成为一种语言强有力的特征,但是由于 它会增加该语言的复杂性和歧义,因此许多面向对象语言都没有加入它。

Ruby支持单继承。然而,它还提供了mixin-它提供了多继承的许多特征。一个mixin是一种”模块”类型。为此,你必须首先理解在Ruby中模块的含义。

在Ruby中,模块是一种把方法和常数分组的方式。它与类相似,但是一个模块没有实例并且也没有子类。也许解释模块的最好方法是举一个例子。假定你正在 开发一个制造业应用程序。该程序需要存取大量的科学公式和常数,那么你可以或者是创建一个通用类来把这些放在其中或者是创建一个模块。模块的优点在于,在 存取其中的公式时,根本没有任何实例扰乱所带来的烦恼。

module Formulas
ACCELERATION = 9.8
LIGHTSPEED = 299792458
def energy (mass)
mass*(LIGHTSPEED**2)
end
def force (mass)
mass*ACCELERATION
end
end

现在,这些公式方法和常数可以被任何数目的其它类或其自身所使用:

irb(main):046:0> Formulas.force(10)
=> 98.0
irb(main):047:0&Gt; Formulas::ACCELERATION
=&Gt; 9.8

注意,为了调用一个模块方法或使用一个模块常数,你必须使用类似于调用一个类方法的标志。为了调用一个模块方法,你需要使用模块类名,后面跟着一个点,再跟着模块方法名。为了引用模块常数,你可以使用模块名,后面跟着两个冒号,再跟着常数名。

除了作为方法和常数的”公共”应用以外,模块还可以帮助定义多重继承。一个mixin是一个简单的”包括”有一个类定义的模块。当一个类包括一个模块 时,所有的模块中的方法和常数都成为类的实例方法和常数。例如,假定上面定义的Formula模块作为一个mixin被添加到Rectangle类。为 此,你要使用”include”关键字:

class Rectangle
include Formulas
end

现在,Rectangle的实例具有了它们可以使用的force和energy方法,并且Rectangle类能够访问常数ACCELERATION和LIGHTSPEED:

irb(main):044:0> class Rectangle
irb(main):045:1> include Formulas
irb(main):046:1> end
=> Rectangle
irb(main):047:0> Rectangle.new(4,5).force(10)
=> 98.0
irb(main):048:0> Rectangle::LIGHTSPEED
=> 299792458

这意味着,mixin给Ruby中的类带来了许多多重继承的优点,却避开了多重继承中存在的问题。

十一、 控制流

象所有的程序语言一样,Ruby提供了一组控制流命令,这包括条件语句(if/else结构),case语句和循环语句(do,while和for),还提供了象Ada和Java等语言中的异常处理能力。下面是Ruby中的一些控制流语句的示例:

ifarea > 100
“big”
else
“small”
end
case height
| when 1
| print “stubby\n”
| when 2..10 #高度范围为2~10
| print “short\n”
| when 10..20 #高度范围为2~10
| print “tall\n”
| end
aRect = Rectangle.new(4,6)
while aRect.area < 100 and aRect.height < 10
aRect.doubleSize()
end
for element in [2, 9.8, "some string", Math::PI] #遍历对象集合
print “The type is: ” + element.type.to_s + “\n&”
end

控制语句通常非常直接,但是如前面的case语句和for循环语句所显示的,Ruby借鉴了其它一些语言特征和普通的面向对象的特性。
异常处理类似于Java中的”try…catch…finally”语句。在Ruby中,它们更改为”begin…rescue…ensure”语句:

begin
#实现一些事情
rescue
##处理错误
ensure
#做一些清理工作,如关闭一个打开的文件等
end

为了在你的代码中引发一个异常,你只需要简单地调用raise方法:

if area < 0
raise
else if area > 0 and area < 10
raise “Rectangle too small”
else if area > 100
raise TooBigException “Rectangle too big”
end

第一个raise调用创建一个RuntimeError。第二个raise创建一个显示一条消息的RuntimeError。最后一个raise调用一个TooBigException的新实例(由它创建一个粗略定义的错误),并设置它的适当消息。

一个Ruby小程序

为了帮助你更好地掌握Ruby的基础知识,我在本文中提供了一个小程序供你学习之用。为了使这个程序工作,你可以下载并把该文件解压到你的文件系统。之 后,它将创建一个examples文件夹,在这个目录下共有9个Ruby代码文件(.rb文件)。本文中的代码就包含在这些文件中。另外,你会找到一个 testShapes.rb文件,它是测试Ruby的Rectangle,Square和Circle对象的主文件。只需简单地打开一个命令提示符并运行 testShapes.rb文件即可,如图8所示。

图8.一个小型Ruby的例子。

你将注意到,在testShapes.rb和另外一些代码中,文件以”require”再加上一个文件名开头(象rectangle.rb)。这是在你的Ruby程序中加入或使用来自于其它文件代码的Ruby标志。

总结

Ruby能否接管Java或C#而成为业界领先的现代软件开发语言?尽管Ruby可能变得十分流行,但我对此仍抱有怀疑态度。作为一名在业界摸爬滚打多 年的专业人员,我对其偶然性并不感到惊讶,但我还是比较注重实效的。例如,我发现Smalltalk是一种比Java优越的高级语言,然而优越并不会总会 赢。现代语言背后总存在大量的技术和市场方面的支持。库,开发工具包,框架,架构,连接器,适配器,支持平台,服务,知识库,能干的开发团队,等等,都会 被配置到位以支持象Java这样的程序语言。并且,无论你喜欢与否,Sun和Microsoft主宰下的市场在未来一段时间内肯定还是开发环境的胜者。

那么,为什么还要探讨Ruby呢?作为一种Perl或Python脚本语言的代替(这正是它的最初目的)或快速原型开发工具,Ruby可能特别有用。一 些人也已经看到了Ruby的威力,并且开始把Ruby作为一种伟大的方法进行编程教学。根据我的本地Ruby用户组的成员提供的信息,有一些人正在把它应 用于测试生产系统。不仅如此,我将邀请你,就象Bruce Tate和Dave Thomas邀请我一样来探讨一下这种语言的力量和美丽之处。即使Ruby不会得到广泛使用,但是随着人们对它的逐渐认识和试用,它一定会找到适应自己的 编程环境。

北京网站建设公司

ruby

Ruby程序快速入门之方法存取控制

Tags:

在许多情况中,当你设计你的应用程序时,你可能想实现一个方法仅为一个对象内部使用而不能为另外一些对象使用。Ruby提供了三个关键字来限制对方法的存取。

· Private:只能为该对象所存取的方法。

· Protected:可以为该对象和类实例和直接继承的子类所存取的方法。

· Public:可以为任何对象所存取的方法(Public是所有方法的默认设置)。

这些关键字被插入在两个方法之间的代码中。所有从private关键字开始定义的方法都是私有的,直到代码中出现另一个存取控制关键字为止。例如,在下 面的代码中,accessor和area方法默认情况下都是公共的,而grow方法是私有的。注意,在此doubleSize方法被显式指定为公共的。一 个类的initialize方法自动为私有的。

class Rectangle
attr_accessor :height, :width
def initialize (hgt, wdth)
@height = hgt
@width = wdth
end
def area ()
@height*@width
end
private #开始定义私有方法
def grow (heightMultiple, widthMultiple)
@height = @height * heightMultiple
@width = @width * widthMultiple
return “New area:” + area().to_s
end
public #再次定义公共方法
def doubleSize ()
grow(2,2)
end
end

如下所示,doubleSize可以在对象上执行,但是任何对grow的直接调用都被拒绝并且返回一个错误。

irb(main):075:0> rect2=Rectangle.new(3,4)
=> #<Rectangle:0×59a3088 @width=4, @height=3>
irb(main):076:0> rect2.doubleSize()
=> “New area: 48″
irb(main):077:0> rect2.grow()
NoMethodError: private method ‘grow’ called for #<Rectangle:0×59a3088 @width=8, @height=6>
from (irb):77
from :0

默认情况下,在Ruby中,实例和类变量都是私有的,除非提供了属性accessor和mutator。

北京网站建设公司

ruby

Ruby程序快速入门之类变量和类方法

Tags:

象大多数面向对象语言一样,Ruby类也允许定义类变量和方法。一个类变量允许在一个类的所有实例间共享单个变量。在Ruby中,两个@@号用于指示类变量。例如,如果你想要使一个BankAccount类的所有实例共享相同的利息率,那么该类可能被如下定义:

class BankAccount
@@interestRate = 6.5
def BankAccount.getInterestRate()
@@interestRate
end
attr_accessor :balance
def initialize (bal)
@balance = bal
end
end

如你所见,类变量必须在使用前初始化,并且就象实例变量一样,如果你想存取类变量的话,你需要编写存取器方法。在此,我定义了一个类方法来返回利息率。 注意,类名和在getInterestRate前面的句号表示一个类方法。一个类方法,不管对于任何实例,其工作方式都是相同的-在此,是把相同的利息率 返回到所有的BankAccount实例。为了调用类方法,你需要使用类名,就象它使用于类方法定义中一样:

irb(main):045:0> BankAccount.getInterestRate
=> 6.5

事实上,用于创建类实例的”new”方法就是一个类方法。因此,当你在程序中输入”Rectangle.new”时,你实际在调用new类方法-这是Ruby默认情况下所提供的。

继承

面向对象编程的原则之一是支持类层次结构。就象自然界中的事物分类一样,类允许从更为通用的类进行继承。面向对象编程的特征主要体现在方法和变量的使用 上。例如,一个Square类继承Rectangle类的一些特征,如方法和变量。一个Square是一种更具体类型的Rectangle(高度和宽度相 等的Rectangle实例),但是它仍然有一个高度和宽度,也有一个面积(而且与矩形的计算方法相同)。在Ruby中,Square类可以使用下列定义 创建:

class Square < Rectangle
end

“<Rectangle”意味着,Square是Rectangle的一个子类,或反过来说,Rectangle是Square的一个超类。默认情 况下,一个Square实例自动地拥有所有一个Rectangle所拥有的相同的属性和方法,包括height,width和area方法。为了确保 Square实例的边长相等,你可以重载现有的Square的initialize方法:

class Square < Rectangle
def initialize (size)
@height = size
@width = size
end
end

因为在Ruby中一切都是对象,所以Ruby中的一切几乎都派生自Object类。尽管这在所有类定义中都不是显式的(你不会看到<Object 出现在定义中),但是的确所有的类都派生自Ruby的基类Object。知道这个事实后,你就会更容易地理解接下来要讨论的内容。

当编写你的应用程序时,你可以在一个类定义外定义方法。在本文开始,你已看到了一个并不是任何一个类的一部分的摄氏到华氏转换器方法。作为另外一个示例,下面是一个位于任何类之外的方法:

def feel?
return “I feel fine.”
end

为了执行这个方法,只要输入该方法名,而不需要类或实例:

irb(main):042:0> feel?
=> “I feel fine.”

此方法看似另外一种语言(如C)中的函数或过程。事实上,尽管这些方法看上去好象不属于任何类,但是这些方法却都是你已经添加到Object类上的方 法,它(因为Object是所有类的超类)反过来也把这一方法添加到你的继承类上。因此,现在你可以在任何对象(如Square和Rectangle的实 例)甚至一个类(如Rectangle类)上调用这个方法。

irb(main):043:0> sq1=Square.new(4)
=> #<Square:0×5a18b50 @width=4, @height=4>
irb(main):044:0> rect1=Rectangle.new(5,7)
=> #<Rectangle:0×5a139a8 @width=7, @height=5>
irb(main):045:0> sq1.feel?
=> “I feel fine.”
irb(main):046:0> rect1.feel?
=> “I feel fine.”
irb(main):047:0> Rectangle.feel?
=> “I feel fine.”

北京网站建设公司

ruby

Ruby程序设计语言快速入门之变量与赋值

Tags:

变量与赋值

至此,你是否注意到前面所有的示例代码中都缺少某种东西?难道你必须输入常数,实例变量或类变量?绝对不 是!这正是Ruby的真正面向对象的天性的一部分。为此,首先让我们看一下Ruby中以前的普通变量。至此,你已经创建了很多Rectangle实例,但 是你并没有把它们保留多长时间。比方说,你想要把一个变量赋值给你创建的一个Rectangle实例:

myRectangle = Rectangle.new(4,5)

在 Ruby中这是完全有效的代码,而且根本不需要另一行代码来把myRectangle类型化或声明为引用Rectangle的某种东西。在执行这一行代码 以后,变量myRectangle就引用一个Rectangle的实例(高度和宽度值分别为4,5)。但是,这仅是一种在任何时刻都可以更改的对象引用, 而与对象的类型无关(在Ruby中一切都是对象)。因此,下面的命令提示符行中,你可以容易地把myRectangle赋值给一个字符串:

irb(main):049:0< myRectangle=Rectangle.new(4,5)
=> #<Rectangle:0×587c758 @width=5, @height=4>
irb(main):050:0< myRectangle=”Jim’s Rectangle”
=> “Jim’s Rectangle”

你可以在许多其它程序语言(甚至包括象Java这样的面向对象的语言)中试验一下,并观察从你的IDE所产生的编译错误。

变量,实例变量,类变量,甚至还有”常量”其实都只是对象引用。它们引用对象,但是它们并不是对象本身。因此,它们可以被动态地改变,甚至引用另一种不同类型的对象。

因为这一灵活性,所以必须在Ruby中进行一些约定以帮助每个人都知道某个变量正为代码所使用。其实,你已经看到了其中之一(@符号,它意味着这是一个实例变量)。其它的变量,方法和类命名约定列于下表1中。

· 局部变量和方法参数以一个小写字母开头。
· 方法名字以一个小写字母开头。
· 全局变量以一个$开头。
· 实例变量以一个@开头。
· 类变量以两个@开头。
· 常数以一个大写字母开头(它们经常被指定全部大写)。
· 类和模块名以一个大写字母开头。

局部变量 全局变量 实例变量 类变量 常数 类名 方法名
aVar $Var @var @@var VAR MyClass myMethod
name $debug @lastName @@interest PI Rectangle area

表1.这个表包含了在Ruby编码约定下的相关示例。

操作符方法

现在,假定你想实现合并Rectangle类的实例或把它们添加到另一个Rectangle实例。你当然可以定义另外一个称为”add”的方法,这种选 择利用了Ruby真正的面向对象的特征之一。然而,你还可以重载”+”运算符来适当地把两个Rectangle实例加起来。这个”+”方法(如4+5), 对Ruby来说,只是另外一个方法而已。由于只是”另外一个方法”,所以你可以给它增加一些功能来满足Rectangle类的需要。例如,你还可以定 义”+”运算符来实现一个矩形面积加上另一个矩形面积。

def + (anotherRectangle)
totalArea = area() + anotherRectangle.area()
Rectangle.new(@height,totalArea/@height)
end

在把这个方法添加到Rectangle类以后,你可以使用+方法调用来把两个Rectangle的实例相加:

irb(main):001:0> rect1=Rectangle.new(2,3)
=> #<Rectangle:0×58aa688 @width=3, @height=2>
irb(main):002:0> rect2=Rectangle.new(3,4)
=> #<Rectangle:0×58a6ef0 @width=4, @height=3>
irb(main):003:0> rect1+rect2
=> #<Rectangle:0×58a4a60 @width=9, @height=2>

这正是操作符重载,对于那些使用过Agol,C++,Python和其它语言的用户来说,可能已经非常熟悉这个特征。

方法参数

至此,我们一直假定,传递给一个方法的参数个数是已知的。也许在其它语言中不可思议,但是Ruby的确允许你传递可变个数的参数并且以单个参数来捕获它 们。为了创建一个可变长度的参数,只需要把一个星号(*)放在最后一个参数前面即可。这样,你就可以在Ruby中编写一个如下的多边形定义。

class Polygon
def initialize (s1,s2,s3,*others)
@sideOne = s1
@sideTwo = s2
@sideThree = s3
@otherSides = others
end
end

如下所示,你可以使用这个定义来创建一个三角形或一个六边形。

irb(main):009:0> poly1=Polygon.new(2,4,5)
=> #<Polygon:0×594db10 @otherSides=[], @sideThree=5, @sideTwo=4, @sideOne=2>
irb(main):010:0> poly2=Polygon.new(2,18,4,5,7,9)
=> #<Polygon:0×5948d58 @otherSides=[5, 7, 9], @sideThree=4, @sideTwo=18, @sideOne=2>

在支持可变长度参数的同时,Ruby还允许定义一个方法参数的默认值(在调用者没有提供的情况下使用)。例如,下面是Rectangle类的一个更好的初始化表达。

def initialize (hgt = 1, wdth = 1)
@height = hgt
@width = wdth
end

现在,在调用时如果省略了某参数,那么在定义中参数紧邻的赋值运算符担当一个缺省的赋值器。现在,当创建一新的矩形时,如果在调用时省略了宽度,那么一个适当的宽度也会被默认地提供:

irb(main):090:0> rect=Rectangle.new(2)
=> #<Rectangle:0×5873f68 @width=1, @height=2>

北京网站建设公司

ruby

Ruby语言快速入门之对象,方法和类

Tags:

在Ruby中,一切都是对象。对于那些喜欢使用高度面向对象的语言(例如Smalltalk,Eiffel或CLOS)的用户来说,这是非常受欢迎的。例 如1,2,3或10.8等等都是对象,而不是如Java或C++中的原始类型;字符串是对象,类和方法也都是对象。例如,下面都是有效的Ruby代码(在 Ruby中,注释行是以”#”符号界定的):

#对象-34的绝对值
-34.abs
#对一个浮点数进行四舍五入处理
10.8.round
#返回一个字符串对象的大写且逆转的副本
“This is Ruby”.upcase.reverse
#返回数学sin方法的参数个数
Math.method(:sin).arity

图5.Ruby是全对象化的:在Ruby中,整数,浮点数,字符串,甚至类和方法都是对象。这里的代码展示了针对这些类型对象的方法调用。

在Ruby中,所有功能都是通过调用对象上的方法(或操作)实现的。事实上,Ruby中的方法调用就象其它程序语言中的函数或过程调用一样。

就象在所有面向对象程序语言中一样,对象是从类中创建的。Ruby库中提供了许多预构建的类。你可以修改这些类或构建你自己的类。Ruby中的类是使 用”class”关键字定义的。类名开始是一个大写字母。类定义以”end”关键字结束。因此,一个Rectangle类的定义可能有如下形式:

class Rectangle
end

为了把方法添加到类,可以使用def关键字。方法的定义也应该以end关键字结束。跟随def关键字和方法名后面就是方法参数。把一个area方法添加到上面的Rectangle类的代码看上去如下所示:

class Rectangle
def area (hgt,wdth)
return hgt*wdth
end
end

对于那些熟悉其它程序语言的用户,他可能注意到一些差别。Ruby并不使用任何花括号来限定类或方法,也不使用分号或其它字符来表示程序语句行的结束。 Ruby的目标,根据它的创建者说明,是简单、易用并使编码成为一件”趣事”。谁想记住所有的那些分号?没有意思!在Ruby中,只要你把语句放在一行 上,不需要分号或其它代码行结束标记。顺便说一下,在area方法参数周围的括号是不必要的。在默认情况下,Ruby返回一个方法中最后的内容,因此 return关键字也可以省略。因此,你可以建立如下简单编码的Rectangle类:

class Rectangle
def area hgt, wdth
hgt*wdth
end
end

尽管上面代码是有效的,但是小括号还是被推荐使用于方法参数表达的,这主要是为了实现较好的可读性。

北京网站建设公司