rubyonrails:Ruby 101:类和对象

  虽然仅仅阅读文章也能了解Ruby语法但这样就会少很多乐趣如果你有兴趣学习Ruby我建议你还是动手试试和纯粹阅读相比亲身体验将会有另番区别感受

  工欲善其事必先利其器想要体验Ruby就得花点时间配置它运行环境了目前可以选择有Ruby、IronRuby和JRuby你可以根据自己喜好/需要选择其中其中IronRuby需要Microsoft .NET或者Mono支持而JRuby则需要JVM支持

  Ruby运行环境安装和配置非常简单到官网下载最新版压缩包把它解压到C:\(或者你喜欢其他地方)然后把C:\Ruby\bin(或者你所选择路径)添加到Path环境变量这样就好了!(这是 Windows平台安装思路方法如果是Ubuntu可以通过Package Manager直接安装)对于IronRuby如果你已经安装了Visual Studio 2005/2008那么你只需从codeplex.com/ironruby上下载最新版压缩包把它解压到你喜欢地方然后把bin路径添加到Path就可以了对于JRuby除了上述思路方法的外你还可以下载并安装NetBeansRuby专用版它已经自带JRuby 1.2.0当然如果你想要最新1.3.1那就要自己动手了

  接下来打开运行对话框输入irb然后按下回车Ruby命令行运行环境将会打开在里面敲下puts "Start Ruby today ~"并按下回车这将会向控制台输出"Start Ruby today ~":



  图 1

  puts是个思路方法它负责把数据输出到控制台在Ruby里思路方法时通常都是可以省略括号当然如果你已经习惯带括号风格你也可以把它加上恭喜你成功运行了你份Ruby代码!

  模块、类和对象

  在Ruby里创建类型是非常简单假如我要创建个Book类我可以这样做:



  代码 1

  接下来我们创建个Book例子对象:



  代码 2

  b是个变量在Ruby里使用变量时无需声明它类型事实上变量不和类型关联你完全可以在后面把它用于其他类型对象(第 2个b下面波浪线是NetBeans提示变量未被使用):



  代码 3

  而这在静态语言里面是不允许回到代码2我们用思路方法创建个Book例子对象但这个思路方法从哪里来呢?它是Ruby解析器为我们自动创建默认构造吗?不是不过它确实是构造糊涂啦?不要紧我们会在后面详细探讨现在你只要记住可以用它来创建对象就行了

  般情况下我们会把类组织到区别命名空间里在Ruby里我们用模块来实现命名空间功能比如说我想把Book类放在Ruby101模块里我可以这样做:



  代码 4

  当我们把类放进模块我们就需要通过模块名字来引用类了:



  代码 5

  例子成员

  现在Book类空空如也我想没有人会想要这样个没用如果想用它来存储些有用信息我们就需要为它创建些例子字段

  下面我将会为Book类创建个initialize思路方法用来化Book例子字段:



  代码 6

  在Ruby里思路方法命名方式也是有规定它可以包含字母、数字和下划线(少数特殊也允许出现在思路方法名字里比如!、?和=但它们使用通常有些约定俗成意义)并以小写字母或者下划线开头代码6里构造接受4个参数这些参数都没有声明类型这和变量构造里分别化4个例子字段字段?慢着!我们还没有定义……

  在Ruby里例子字段都是以@开头并且在使用的前无需事先声明但这些例子字段都是私有要从外面访问这些字段我们需要为它们创建访问器:



  代码 7

  代码7示范了3种区别风格访问器你可以根据个人喜好选择其中般情况下我们会采用第 3种风格事实上第 3种风格最终会被"还原"成第种风格在某种程度上你可以把它理解成C# 3.0自动属性除非你要向访问器添加(验证)逻辑否则你没有必要直接使用第种风格在Ruby里思路方法最后个表达式值将会自动作为思路方法返回值当然你也可以显式使用来返回attr_accessor实际上是个思路方法职责就是根据我传给它名字生成第种风格代码:price是我传给它参数:XXX用来表示RubySymbol类型对象表面上它和串很像但内里却有着很大区别就目前而言你只需把它们的间区别理解为相同内容Symbol对象在内存里只存在而相同内容String在内存里则会存在多份(如果你有兴趣深入了解Symbol可以阅读Eric Kidd13 Ways of Looking at a Ruby Symbol)和attr_accessor对应还有attr_reader和attr_writer顾名思义它们分别用来创建只读和只写访问器

  下面我们来看看这些访问器分别是如何使用:



  代码 8

  正如你所看到"title = XXX"实际上会被解析成对title=思路方法当然你也可以使它变得更明显些:b.title=("The Ruby Programming Language")_authors思路方法时我向它传递在Ruby里表示为[XXX, YYY, ZZZ]

  现在我们统使用第 3种风格为所有例子字段创建访问器:



  代码 9

  下面我们创建个Book例子对象并输出它信息:



  代码 10

  如果你和我样都是使用NetBeans那么你只需要在编辑器任何地方右击鼠标然后选择Run File就可以运行Ruby代码了:



  图 2

  运行结果将会显示在Output窗口里:



  图 3

  在NetBeans里你可以通过File ->Project Properties轻松切换Ruby运行环境:



  图片看不清楚?请点击这里查看原图(大图)

  图 4

  当然你也可以使用记事本或者其他你喜欢文本编辑器来编写Ruby代码然后把代码保存为XXX.rb文件并通过命令行用Ruby解析器执行代码下面分别使用Ruby和IronRuby来执行上面代码:



  图 5

  如果你嫌代码9还不够简化那么你可以试试RubyStruct:



  代码 11

  代码11和代码9是等效就像attr_accessor思路方法那样Struct最终会帮你生成代码9里Book类而使用方法上和的前是如果你想创建是仅用于承载数据那么Struct就是为你量身定做如果将来你想扩展Book类比如说为它添加思路方法如何办?没问题既然Struct为你创建个类那么你可以通过继承扩展这个类此外你还可以"直接"扩展这个类什么意思呢?Ruby允许你修改任何类定义即使是内置所以你可以在代码11后面"重新打开"Book类并往里面添加思路方法:



  代码 12

  由于tags是(确切地说应该是tags思路方法返回值是虽然这只是我们期望并且任何人都可以打破它)我们可以通过<<向添加元素值得提醒Ruby和我们通常使用区别长度是可变

  此外Ruby还提供了OpenStruct和Struct区别OpenStruct创建出来是对象而不是类说到这里你可以感到奇怪如果是对象自定义属性要如何设置呢?这正是OpenStruct独特的处自定义属性会在第次使用时自动创建!下面我在irb里示范用OpenStruct创建Book对象:



  图 6

  首先我通过require引用OpenStruct接着我通过思路方法创建了个OpenStruct对象然后我通过反射查看这个对象提供思路方法随后每设置个属性我就通过反射来查看这个对象思路方法正如你所看到自定义属性确是在第次使用时自动创建另外你有没有发觉这次irb和前面看到样?这是我在启动它时候使用了--simple-prompt命令行选项这可以简化irb提示符显示你可以对比图1感受下它们的间区别

  类成员

  现在我需要个书架帮我管理我这个书架提供存放和查找功能我们将会通过这个书架了解Ruby类成员写法

  下面我们创建个BookShelf类并且在它里面创建个静态哈希表用来存放Book对象:



  代码 13

  在Ruby里静态字段以@@开头{}则用来创建个空哈希表接下来我们要创建两个静态思路方法:place和find分别用于存放和查找Book对象:



  代码 14

  在Ruby里创建静态思路方法是非常简单代码12示范了两种风格种是把类名置于思路方法名字的前中间用.分开;第 2种是把self置于思路方法名字的前中间用.分开这两种风格是等效区别只在于个人喜好哈希表可以通过来访问里面数据当你看到代码12时你可能会问为什么place思路方法和find思路方法都没有事先检查key是否存在你可以这样做但没有必要place思路方法时如果key已经存在则用新value代替现有如果key并不存在则往里面添加这对key/value而在find思路方法时如果key已经存在则返回对应value如果key并不存在则返回nil这些是哈希表预设行为

  除了上述两种风格Ruby还支持另外两种看起来有点怪异风格种是创建个例子思路方法然后把它包在 << self和end的间:



  代码 15

  这种做法咋看比较怪异但有时候确是必须比如说我现在想用attr_accessor来为path创建静态字段和读/写访问器显然的前介绍两种做法都无能为力最终代码是由attr_accessor思路方法代为生成这时就轮到 << self出场了我只需把attr_accessor :path放在 << self和end的间就行了

  第 4种风格可以看作第 3种变形它们的间区别在于第 3种风格代码是放在类里面而第 4种风格代码则放在类外面于是 << self需要改成 << BookShelf以便告知这份代码所属:



  代码 16

  现在我们来看看BookShelf使用情况(变量b化请参见代码10):



  代码 17

  运行结果如下:



  图 7

  Ruby支持串插值(String Interpolation)当我们用#{}包围某个表达式时这个表达式运算结果将被插入表达式所在位置从运行结果可以清楚地看到这点另外我在puts后面添加了unless XXX这将导致puts语句在unless后面条件满足时不执行当然如果你不嫌冗长你也可以把它改成:



  代码 18

  效果都是

  现在回到前面问题思路方法是从哪里来还有我们定义initialize思路方法好像从来没有又是谁给那些私有字段呢?下面我们将会使用irb来探个究竟:



  图 8

  首先我创建了个Book类里面只有initialize思路方法当我用思路方法创建个Book对象时我们从命令行输出结果可以看到initialize思路方法已被接着我对Book类进行扩展添加思路方法从前面来看它是个静态思路方法因此你可以选择上述 4种风格任意种来实现然后我再用思路方法创建个Book对象这次我们从命令行输出结果可以看到思路方法和initialize思路方法都被而且思路方法在initialize思路方法的前细心你可能已经发现思路方法实现里包含了个super关键字这是什么意思呢?在回答这个问题的前我们做另个实验就是把这个关键字去掉看看会有什么区别:



  图 9

  当我们把super关键字去掉的后从命令行输出结果不难发现initialize思路方法"失效"了并且思路方法不再创建对象!综上所述思路方法是initialize思路方法得以关键事实上思路方法是Book类从Class类那里继承过来个思路方法职责就是创建(未)对象initialize思路方法来化这个对象(initialize思路方法是私有你无法直接它)我们刚才为Book类重写了这个思路方法为了使它依然生效我们需要"原本"实现因此需要加上super关键字就目前而言你只要记住super关键字作用是当前思路方法继承版本就行了



  新旅程

  上节末尾我们提到了继承这是面向对象编程核心概念的那么Ruby又是如何体现继承以及面向对象编程其他特征呢我们将会在以后文章里逐探讨

  P.S. 本文代码若无特别介绍说明均可在Ruby、IronRuby和JRuby上运行笔者所使用版本分别是1.9.1、0.9.0和1.3.1



Tags:  rubypython beautylegruby ruby教程 rubyonrails

延伸阅读

最新评论

发表评论