中国开发网: 论坛: 程序员情感CBD: 贴子 485387
haitao
ruby学习笔记
ruby学习笔记
└《二十分钟Ruby入门》:http://www.matrix.org.cn/resource/article/2007-02-26/ff82b100-c542-11db-9ca0-c55b502ecb5b.html#2eaf0dd6-d39a-11db-9bed-29012b8c745e
├摘要:[多行文本]
│├>:这是一个短小的Ruby入门,完全读完只需20分钟。
│├>:让我们从编写世界上最简单的"Hello,World"程序开始逐步深入了解Ruby的类、block、迭代器等特征,
│├>:也许这对你来讲还远远不过,但对于20分钟的入门来讲已经非常难得了。
│├>
│├>
│├>:cleverpig 发表于 2007-02-26 10:42:28
│├>:作者:cleverpig 来源:Matrix
│├>:评论数:15 点击数:1,657 投票总得分:15 投票总人次:3
│└>:关键字:Ruby,20分钟,快速入门,
├交互式的Ruby:[多行文本]
│├>:打开IRB(交互式Ruby外壳):
│├>: 如果你使用Mac OS X,那么请打开终端窗口输入irb;
│├>: 如果你使用Linux,那么请打开shell输入irb;
│├>: 如果你使用windows,那么请在开始菜单中找到Ruby->fxri,并执行它。
│├>
│├>:irb(main):001:0>
│├>
│├>:Ok,在打开IRB之后,在其中输入"Hello World"。
│├>
│├>:irb(main):001:0> "Hello World"
│├>:=> "Hello World"
│└>:irb(main):002:0>
├Ruby听从你的安排!:[多行文本]
│├>:发生了什么?我们刚才编写了世界上最短小的“Hello World”程序吗?
│├>:这么说不太确切。
│├>:第二行输出是IRB告诉我们:上一个表达式的评估结果。
│├>:如果我们希望打印出“Hello World”,那么就还需要一点努力:
│├>
│├>:irb(main):002:0> puts "Hello World"
│├>:Hello World
│├>:=> nil
│├>:irb(main):003:0>
│├>
│├>:puts在Ruby中是一个简单的打印输出命令。
│├>:后面的“=> nil”表示什么?——那是表达式的结果。
│├>:Puts总是返回nil,
│├>:这是Ruby中表示“绝对无值”(absolutely-positively-nothing value)的方式,
│└>:看上去有些类似Java中的null。
├你的免费计算器在这里!:[多行文本]
│├>:无需做什么,我们就能把IRB作为一个简单的计算器使用:
│├>
│├>:irb(main):003:0> 3+2
│├>:=> 5
│├>:irb(main):004:0>
│├>
│├>:这样就能计算3+2。够简单的!
│├>:那么3乘以2如何?
│├>:你可以在下面继续输入3*2,也可以回到上面(3+2处)重新修改你刚刚输入的计算公式。
│├>:使用键盘上的向上键,使光标到达3+2那一行,再用左键移动光标到加号上,然后使用空格键进行修改。
│├>
│├>:irb(main):004:0> 3*2
│├>:=> 6
│├>:irb(main):005:0>
│├>
│├>:下面,让我们尝试计算3的平方:
│├>
│├>:irb(main):005:0> 3**2
│├>:=> 9
│├>:irb(main):006:0>
│├>
│├>:在Ruby语言中,**表示幂运算。那么如何计算平方根呢?
│├>
│├>:irb(main):006:0> Math.sqrt(9)
│├>:=> 3.0
│├>:irb(main):007:0>
│├>
│├>:Ok,等一下,表达式中的sqrt(9)表示什么?
│├>:你一定能猜到这是计算9的平方根。而Math表示什么?
│└>:不要着急,下面就让我们进一步了解像Math这样的模块。
├模块——按照主题分组的代码:[多行文本]
│├>:Math是Ruby内建的数学模块。
│├>:在Ruby中,模块提供了两种角色:
│├>:一种角色是将类似的方法聚集在同一个“家族”名下。因此,Math也包括sin、tan这样的方法。
│├>:第二种角色是一个圆点(dot),它标记了消息的接收者。
│├>:什么是消息?在上面的例子中,sqrt(9)便是消息,它意味着调用sqrt方法取出9的平方根。
│├>
│├>:Sqrt方法调用的结果是3.0。你可能注意到它并不是3。
│├>:这是因为多数情况下,数字的平方根并不是整数,所以这里返回了一个浮点数。
│├>
│├>:那么我们如何记住这些计算结果呢?——将结果赋值给变量。
│├>:irb(main):001:0> a=3**2
│├>:=> 9
│├>:irb(main):002:0> b=4**2
│├>:=> 16
│├>:irb(main):003:0> Math.sqrt(a+b)
│├>:=> 5.0
│└>:irb(main):004:0>
├如何定义方法?:[多行文本]
│├>:如何才能方便省事地随意输出字符串,而无需过多地劳烦我们的手指呢?——我们需要定义一个方法!
│├>
│├>:irb(main):004:0> def h
│├>:irb(main):005:1> puts "Hello World!"
│├>:irb(main):006:1> end
│├>:=> nil
│├>
│├>:上面的代码中第一行“def h”标志着方法定义的开始。
│├>:它告诉Ruby我们正在定义一个名为h的方法。
│├>:下面一行是方法体:puts "Hello World"。
│├>:最后,也就是第三行“end”通知Ruby我们完成了方法定义。
│└>:Ruby的回应“=> nil”告诉我们它已经知道我们定义了此方法。
├简短、重复地调用方法:[多行文本]
│├>:现在,让我们尝试多次执行这个方法:
│├>
│├>:irb(main):007:0> h
│├>:Hello World!
│├>:=> nil
│├>:irb(main):008:0> h()
│├>:Hello World!
│├>:=> nil
│├>
│├>:哈,这太容易了。
│├>:在Ruby中调用某个方法只需将方法名提交给Ruby。
│├>:当然,这是在方法没有参数的情况下。
│├>:如果你愿意也可以添加一个空白的括号,但是这没有必要。
│├>
│├>:如果我们想对某个人说hello而不是整个“世界”(world),那该怎么做?
│├>:——重定义h方法使它接收name参数。
│├>
│├>:irb(main):009:0> def h(name)
│├>:puts "Hello #{name}!"
│├>:end
│├>:=> nil
│├>:irb(main):012:0> h("Matz")
│├>:Hello Matz!
│├>:=> nil
│├>
│└>:嗯,现在看来工作正常。
├字符串中的奥秘:[多行文本]
│├>:“#{name}”是什么意思?
│├>:这是Ruby在某个字符串中插入其它字符的方式。
│├>:在大括号之间放入的字符串(这里是指name)将被外部的字符串代替。
│├>:你也可以使用字符串类内建的capitalize方法来确保某人名字的首字母大写:
│├>
│├>:irb(main):024:0> def h(name="World")
│├>:puts "Hello #{name.capitalize}!"
│├>:end
│├>:=> nil
│├>
│├>:irb(main):016:0> h "chris"
│├>:Hello Chris!
│├>:=> nil
│├>
│├>:irb(main):027:0> h
│├>:Hello World!
│├>:=> nil
│├>
│├>:上面的代码有两个地方需要说明:
│├>:第一,我们通过无括号的方式调用方法,因为括号是可选的;
│├>:第二,这里的默认参数值为“World”。
│└>: 也就是说在调用方法时如果没有提供name参数,则使用默认值“World”。
├进化为Greeter!:[多行文本]
│├>:我们是否需要一个真正的问候者(greeter),他能记住你的名字、问候你、总是尊重地向你示好?
│├>:那么这就最好建立一个“Greeter”类:
│├>
│├>:irb(main):043:0> class Greeter
│├>:def initialize(name="world")
│├>:@name=name
│├>:end
│├>:def say_hi
│├>:puts "hi #{@name}!"
│├>:end
│├>:def say_bye
│├>:puts "bye #{@name}, come back soon."
│├>:end
│├>:end
│├>:=> nil
│├>
│├>:在上面的类代码中定义了一个称为Greeter的类和一些类方法,
│├>:其中出现了一些新的“关键词”:请注意“@name”,
│├>:它是类的实例变量,并对类中的所有方法(say_hi和say_bye方法)都有效。
│├>
│├>:如何让Greeter类发挥作用?现在让我们来建立一个Greeter对象并使用它!
│├>
│├>:irb(main):054:0> g=Greeter.new("Pat")
│├>:=> #<Greeter:0x55dcfb4 @name="Pat">
│├>:irb(main):055:0> g.say_hi
│├>:hi Pat!
│├>:=> nil
│├>:irb(main):056:0> g.say_bye
│├>:bye Pat, come back soon.
│├>:=> nil
│├>
│├>:Greeter类的实例对象g被建立后,它便接受了name参数(值为Pat)。
│├>:那么我们能直接访问name吗?
│├>
│├>:irb(main):057:0> g.@name
│├>:SyntaxError: compile error
│├>:(irb):57: parse error, unexpected tIVAR
│├>: from (irb):57
│├>: from ^C:0
│├>
│└>:看看上面的编译错误来看,这样直接访问name是行不通的。
├窥视对象的内部:[多行文本]
│├>:对象中的实例变量总是隐藏于其中,但也并非毫无踪迹可寻,
│├>:通过审查(inspect)对象便会见到它们。
│├>:当然还有其它的访问方法,但是Ruby采用了良好的面向对象的方式来保持数据的隐藏性。
│├>
│├>:irb(main):058:0> Greeter.instance_methods
│├>:=> ["methods", "h", "instance_eval", "dup", "instance_variables", "instance_of?",
│├>: "extend", "eql?", "say_hi", "hash", "id", "singleton_methods", "taint", "frozen?",
│├>: "instance_variable_get", "kind_of?", "to_a", "to_yaml_properties", "to_yaml_style",
│├>: "say_bye", "pretty_print_inspect", "type", "protected_methods", "instance_variable_set",
│├>: "is_a?", "respond_to?", "to_s", "pretty_print_cycle", "taguri", "method", "class",
│├>: "private_methods", "==", "tainted?", "__id__", "===", "taguri=", "untaint", "nil?",
│├>: "require_gem", "to_yaml", "pretty_print_instance_variables", "pretty_inspect",
│├>: "inspect", "display", "send", "pretty_print", "=~", "clone", "gem", "public_methods",
│├>: "__send__", "object_id", "freeze", "equal?", "require"]
│├>
│├>
│├>:喔!这么多方法,可是我们只定义了两个方法呀?其它的方法又出自何处?
│├>:不要担心,instance_methods方法列出了Greeter对象的所有方法,其中包括父类中定义的方法。
│├>:如果我们只想对Greeter类的方法进行列表的话,
│├>:那么把false作为参数调用instance_methods方法即可。
│├>:false意味着我们不需要父类定义的方法。
│├>
│├>:irb(main):059:0> Greeter.instance_methods(false)
│├>:=> ["say_bye", "say_hi"]
│├>
│├>:哈哈,这才是我们想要的。下面让我们看看Greeter对象能回应哪些方法:
│├>
│├>:irb(main):060:0> g.respond_to?("name")
│├>:=> false
│├>:irb(main):061:0> g.respond_to?("say_hi")
│├>:=> true
│├>:irb(main):062:0> g.respond_to?("to_s")
│├>:=> true
│├>
│├>:它知道say_hi、to_s(此方法将对象转换为字符串,是任何对象都必备的默认方法,
│└>:很像Java中的toString方法),但它不知道name。
├随时修改类定义:[多行文本]
│├>:如何才能查看或者修改name呢?Ruby提供了访问对象变量的简单方法:
│├>
│├>:irb(main):063:0> class Greeter
│├>:irb(main):064:1> attr_accessor:name
│├>:irb(main):065:1> end
│├>:=> nil
│├>
│├>:在Ruby语言中,你能够多次打开某个类并修改它。
│├>:而修改所带来的变化将应用在此后建立的任何新对象中、甚至现存的此类对象中。
│├>:下面让我们建立一个新对象并访问它的@name属性。
│├>
│├>:irb(main):066:0> g=Greeter.new("Andy")
│├>:=> #<Greeter:0x8056d94 @name="Andy">
│├>:irb(main):070:0> g.respond_to?("name")
│├>:=> true
│├>:irb(main):071:0> g.respond_to?("name=")
│├>:=> true
│├>:irb(main):072:0> g.say_hi
│├>:hi Andy!
│├>:=> nil
│├>:irb(main):073:0> g.name="Betty"
│├>:=> "Betty"
│├>:irb(main):074:0> g
│├>:=> #<Greeter:0x8056d94 @name="Betty">
│├>:irb(main):075:0> g.name
│├>:=> "Betty"
│├>:irb(main):076:0> g.say_hi
│├>:hi Betty!
│├>:=> nil
│├>
│├>:我们通过使用attr_accessor定义了两个方法:
│├>:“.name”用来获取name属性值;
│├>:“.name=”用来设置namee属性值。
│└>:这很类似在Java类中访问被Public修饰的成员变量。
├向每个人问候,MegaGreeter不会漏掉一个人:[多行文本]
│├>:Greeter并不完美,因为它只能一次服务一个人。
│├>:所以我们在这里设计一个能够一次向全世界、世界上每个人或者在名单中的人发送问候的MegaGreeter类。
│├>:在这里,我们将放弃从前的IRB交互模式,转而改为编写Ruby程序文件。
│├>
│├>:退出IRB的方法:输入“quit”、“exit”或者按下Control+D的组合键。
│├>
│├>:#!/usr/bin/env ruby
│├>
│├>:class MegaGreeter
│├>: attr_accessor :names
│├>
│├>:#Create the object
│├>:def initialize(name="world")
│├>: @names=names
│├>:end
│├>
│├>:#Say hi to everybody
│├>:def say_hi
│├>: if @names.nil?
│├>: puts "..."
│├>: elsif @names.respond_to?("each")
│├>
│├>: # @names is a list of some kind, iterate!
│├>: @names.each do |name|
│├>: puts "Hello #{name}!"
│├>: end
│├>: else
│├>: puts "Hello #{@names}!"
│├>: end
│├>:end
│├>
│├>:#Say bye to everybody
│├>:def say_bye
│├>: if @names.nil?
│├>: puts "..."
│├>: elsif @names.respond_to?("join")
│├>: # join the list elements with commas
│├>: puts "Goodbye #{@names.join(",")}. Come back soon!"
│├>: else
│├>: puts "Goodbye #{@names}. Come back soon!"
│├>: end
│├>:end
│├>
│├>:end
│├>
│├>:if __FILE__==$0
│├>: mg=MegaGreeter.new
│├>: mg.say_hi
│├>: mg.say_bye
│├>
│├>: # Change name to be "Zeke"
│├>: mg.names="Zeke"
│├>: mg.say_hi
│├>: mg.say_bye
│├>
│├>: # Change name to an array of names
│├>: mg.names=["Albert", "Brenda", "Charles", "Dave", "Englebert"]
│├>: mg.say_hi
│├>: mg.say_bye
│├>
│├>: # Change name nil
│├>: mg.names=nil
│├>: mg.say_hi
│├>: mg.say_bye
│├>:end
│├>
│├>
│├>:保存上面的代码到名为“ri20min.rb”的文件中,并使用“ruby ri20min.rb”的命令执行它。程序输出如下:
│├>:...
│├>:...
│├>:Hello Zeke!
│├>:Goodbye Zeke. Come back soon!
│├>:Hello Albert!
│├>:Hello Brenda!
│├>:Hello Charles!
│├>:Hello Dave!
│├>:Hello Englebert!
│├>:Goodbye Albert,Brenda,Charles,Dave,Englebert. Come back soon!
│├>:...
│├>:...
│├>
│├>:下面我们将深入了解一下上面的代码。
│├>
│├>:请注意上面代码中的起始行,它以#开头。在Ruby语言中,任何以#开头的行都被视为注释,并被解释程序忽略。
│├>
│├>:我们的say_hi方法已经发生了变化:
│├>
│├>:#Say hi to everybody
│├>:def say_hi
│├>: if @names.nil?
│├>: puts "..."
│├>: elsif @names.respond_to?("each")
│├>
│├>: # @names is a list of some kind, iterate!
│├>: @names.each do |name|
│├>: puts "Hello #{name}!"
│├>: end
│├>: else
│├>: puts "Hello #{@names}!"
│├>: end
│├>:end
│├>
│├>:它查找@names参数并按照其参数值作出决定:
│├>:如果参数值为nil,它将打印三个圆点。
│└>:那么@names.respond_to?("each")表示什么?
├循环——也叫迭代:[多行文本]
│├>:如果@names对象具有each方法,那么它是可以被迭代的,进而可以对其进行迭代,从而问候列表中每个人。
│├>:如果@names不具备each方法,则将它自动转换为字符串,并执行默认的问候。
│├>
│├>: @names.each do |name|
│├>: puts "Hello #{name}!"
│├>: end
│├>
│├>:each是一种方法,它接受一个代码块(block of code),然后针对列表中的每个成员执行这个代码块,
│├>:而在do和end之间的部分便是这个非常类似匿名函数的代码块。
│├>:在管道符之间的变量是代码块的参数name,它作为代码块参数被绑定为列表成员,
│├>:而代码块puts "Hello #{name}!"将使用这个参数进行输出。
│├>
│├>:大多数其它的编程语言使用循环遍历列表,下面是C语言的循环示例:
│├>:for (i=0; i<number_of_elements; i++)
│├>:{
│├>: do_something_with(element[i]);
│├>:}
│├>
│├>:上面的代码显然可以工作,但它不够“优雅”!
│├>:你不得不用i这个多余的循环变量,还需要指出列表的长度,然后再解释如何遍历列表。
│├>
│├>:Ruby的迭代方式则更加优雅,所有的内部管理细节都隐藏在each方法中,
│└>:你所需做的就是告诉它如何处理其中的每个成员。
├块(block),Ruby边缘的高亮点!:[多行文本]
│├>:块(block)的真正优势在于:能够处理比列表更加复杂的对象。
│├>:除了在方法中可以处理简单的内部管理细节外,
│├>:你还能处理setup、teardown和所有错误,而不让用户有所察觉。
│├>
│├>:#Say bye to everybody
│├>:def say_bye
│├>: if @names.nil?
│├>: puts "..."
│├>: elsif @names.respond_to?("join")
│├>: # join the list elements with commas
│├>: puts "Goodbye #{@names.join(",")}. Come back soon!"
│├>: else
│├>: puts "Goodbye #{@names}. Come back soon!"
│├>: end
│├>:end
│├>
│├>:say_bye方法没有使用each,而是检查@names是否具有join方法,
│├>:如果具有join方法,则调用join方法。否则它将直接打印@names变量。
│├>
│├>:此方法并不关心变量的实际类型,
│├>:这依赖于它所支持的那些被称为“Duck Typing”的方法:
│├>:duck typing是动态类型的一种形式:变量的值自身隐含地决定了了变量的行为。
│├>:这暗示了某个对象与其它实现了相同接口的对象之间是可交换的,
│├>:不管对象之间是否具有继承关系。
│├>:鸭子测试(duck test)是对duck typing的一种形象比喻
│├>:——“如果它走路像鸭子,那么也一定像鸭子一样呷呷地叫,那么它必定是一只鸭子”。
│├>:duck typing是某些编程语言的特性:如Smalltalk, Python, Ruby, ColdFusion。
│├>
│├>:Duck Typing的益处是无需对变量的类型进行严格地限制,
│└>:如果某人使用一种新类型的列表类,只要它实现了与其它列表相同语义的join方法,便可以拿来使用。
├启动脚本:[多行文本]
│├>:文件上半部分是MegaGreeter类的代码,而后面剩下的部分则是对这些类方法的调用。
│├>:而这是我们最后值得注意的一点:
│├>
│├>:if __FILE__==$0
│├>
│├>:__FILE__是一个“具有魔力”的变量,它代表了当前文件名。
│├>:$0是用于启动程序的文件名。
│├>:那么代码“if __FILE__ == $0”便意味着检查此文件是否为将被使用的主程序文件。
│├>:这样做可以使程序文件作为代码库使用,而不是可执行代码;
│└>:但当此文件被用作执行文件时,也可被执行。
└如何进一步学习Ruby:[多行文本]
├>:如何进一步学习Ruby
├>
├>:到此便是本入门的尾声了。当然还有许多值得浏览的:
├>:Ruby提供的各种不同的控制结构;块和yield的使用;模块作为mixins使用等。
├>:希望这次Ruby初体验能使你对Ruby更感兴趣。
├>
├>:注:mixin在面向对象编程语言中是一种提供某些功能给子类继承的类,但mixin并不能实例化。
├>:从某个mixin继承并不是什么特殊的形式,而它更适于收集功能。
├>:某个子类甚至可以通过继承一个或者多个mixin选择继承它的全部或者多数功能。
├>:一个mixin能延期定义和绑定方法直到运行时,而属性和实例参数也将在编译时才被定义。
├>:这不同于多数常见的方式:定义所有的属性、方法,并在编译时进行初始化。
├>
├>:如果这样的话,请埋头翻阅我们的文档,那里有免费、丰富的在线手册和入门资源。
└>:或者如果你喜欢在啃书本的话,可以到图书列表中选择一些你所需要的。
我的blog:http://szhaitao.blog.hexun.com & http://www.hoolee.com/user/haitao
--以上均为泛泛之谈--
不尽牛人滚滚来,无边硬伤纷纷现 人在江湖(出来的),哪能不挨刀(总归是要的)
网络对话,歧义纷生;你以为明白了对方的话,其实呢?

您所在的IP暂时不能使用低版本的QQ,请到:http://im.qq.com/下载安装最新版的QQ,感谢您对QQ的支持和使用

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录