打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
.NET程序员新方向 Ruby核心语法入门
userphoto

2011.04.22

关注
本文的目的是为了找出为什么.NET程序员都想学习并使用Ruby,并探索Ruby语言的核心语法。
微软的IronRuby项目为Windows平台带来了强大的动态语言,Ruby编程语言是一个现代的,面向对象的基本语言,它的语法灵感来自Perl和Smalltalk语言,它是由一名日本人松本行弘(外号Matz)发明的,用他的话说,他是想发明一种语言比Perl更强大,同时比Python更面向对象的编程语言,在“http://www.linuxdevcenter.com/pub/a/linux/2001/11/29/ruby.html”有一篇对松本行弘专访文章,大家可以去看看。于是Ruby被设计为非常贴近自然语言,作者的原意就是要减少编程时候的不必要的琐碎时间,令编写程序的人高兴,他于1996年发布了1.0版本。
这么多年来,Ruby一直鲜为人知,但它的功能已经远远超出了最初设计时的想法:以最简化的方法操作数据和环境。我第一次“玩”它还是在几年前,那时我正在寻找一种替换处理自动管理任务的批处理文件的方法。
Ruby真正开始流行还得从一个来自伊利诺斯洲芝加哥市的名叫37signals小公司说起,它们发布了一个名叫Rails的Web应用程序框架,这个新的框架吸取了已经被证明是可靠的Model-View-Controller和ActiveRecord模型的经验,并且添加了一些新的思想,如convention over configuration,导致它实现了太多的目标,几乎不需要编码了。
RubyCLR和IronRuby
在2006年早些时候,John Lam发布了一个开源项目,叫做RubyCLR,它在Ruby和.NET之间起到一个桥梁的作用,它允许用户可以直接从Ruby访问.NET平台丰富的资源,甚至将Ruby对象都暴露给CLR了,这个项目非常有雄心,但它没有打算将Ruby向.NET靠拢,而是打算让这两个世界相互对话,你仍然需要在你的机器上按照Ruby运行时环境。
RubyCLR项目为人们理解如何将Ruby和.NET和谐地溶合到一起迈出了关键的第一步,John的工作没有引起人们的注意,2006年末,他在他的博客上宣布加入微软新成立的动态语言运行时环境(DLR)团队,在John宣布前几个月,微软发布了IronPython的1.0版本,它是Python语言在.NET框架上一个新的实现,动态语言运行时环境在IronPython上工作,它在.NET框架构建了一个运行环境,允许动态语言进入.NET。
John和他的团队在2007年的MIX大会上宣布了IronRuby,可能真正让人吃惊的是IronRuby项目本身是微软的第一个真正意义上的开源.NET语言,不仅可以得到源代码,而且还可以获取来自社区的贡献。
IronRuby仍然处于发展阶段,然而偶然也会删掉已经可以利用的东西,这些东西通常是其它项目的一部分,如最近发布的Silverlight 2.0 Beta 2,这些后续的项目也放在源代码树中了,并且也有相应的邮件列表。
为什么要学习Ruby?
我最喜欢的一本书叫做《程序员实务:从熟练工到大师》【英文名是《The Pragmatic Programmer: From Journeyman to Master》】,该书的作者鼓励程序员每年学习一门新的编程语言,对于我而言,当我学习了Ruby语言后,大大地改变了我的专业范围。
Ruby是一门完全面向对象的语言,这意味着在系统中每一样打交道的东西都是对象,包括直接的值,如数字,即使是类,也是由新创建的对象实例组成的模板。
因为Ruby是一个动态语言,你会发现类型已经变得不太重要了,当一个类函数以参数形式获取到一个对象时,不需要指定对象需要的类型。实际上,Ruby没有编译器,因此,可能直到传递给类函数的对象不满足方法的需要时,你才会发现这一点。
如果你象我几年前那样,你也许会发现这个概念让你不安,如果没有编译器,那么你可能要尽可能最快地在运行前就了解代码中的错误,而不用等到运行时才知道。如果你还是习惯于让编译器告诉你错误,那你就不用选择Ruby了。
正是由于以前编译器能够报告错误,如类型不匹配,当你编写一个类函数时,你可能希望“这里的对象必须能够做到foo和bar”,然后创建一个接口叫做IFooBar,看起来这是一个不错的解决方案,但当你想使用其它的在IfooBar之前创建的类时(特别是那些来自框架的类型),你就会失败了。
作者提醒:IronRuby还没有成为主流的工具,你可以使用Ruby的标准版本进行学习,如果你想实验后面的例子,可以从http://rubyinstaller.rubyforge.org/下载。
Ruby示例
学习Ruby或一门新的编程语言最好的方法就是多练习,研究它的交互接口,大多数动态语言都有交互提示符,称之为读-执行-打印环(即REPL,Read-Execute-Print Loop),Ruby中的REPL程序叫做irb(即交互式Ruby,interactive Ruby)。
当你执行irb程序时,你会看到一个irb提示符,如:
C:\Users\Brad> irb irb(main):001:0>
当你在irb提示符后敲入命令时,Ruby解释程序就会评估它们,并将结果输出到你屏幕上,与irb类似的REPL是学习一门语言的优秀方法:每次一条语句。
下面对irb做一个简单的介绍,在irb提示符后,敲入5+2,并回车,告诉Ruby计算这个表达式的值:
irb(main):001:0> 5 + 2 => 7
irb(main):001:0>部分是irb的提示符,当你敲入5+2并回车时,irb就将结果输出到屏幕上,如这里的=> 7,=> 是irb显示输出结果时使用的提示符。
如果Ruby认为你还没有完成表达式的书写,它允许你继续换行书写,如当你敲入5+2+时就按了回车,Ruby认为你还有一部分没有输入完毕,它会继续让你在下一行输入,如:
irb(main):002:0> 5 + 2 + irb(main):003:0* 13 => 20
第二行的提示符变为星号(*)了,而不是“>”,这样你就知道你在完成前面没有完成的表达式。
基础类型
如果一门编程语言不能处理数字,那就不值得学习和使用,Ruby当然能够满足算术运算了,如:
irb(main):004:0> 3 + 4 => 7 irb(main):005:0> 3 * 4 => 12 irb(main):006:0> 3 - 4 => -1 irb(main):007:0> 3 / 4 => 0 irb(main):008:0> 3.0 / 4.0 => 0.75 irb(main):009:0> 0xF => 15 irb(main):010:0> 0x3 * 0xA => 30
正如你所看到的,Ruby支持整数和浮点类型,甚至可以接收常用的十六进制整数,但0x3 * 0xA的结果是以十进制的形式显示的,即显示结果是30而不是0x1E。
因为在.NET中,数字也是真实的对象,因此,你可以在它们上面调用类函数,如:
irb(main):011:0> 14.to_s => "14"
在c++中不要这样做。
to_s类函数的功能是将一个对象转换成一个字符串,因此,14.to_s返回的结果是"14",和.NET中的to_string()函数一样,to_s函数实际上是一个对象函数,因此,在Ruby中你可以将任何东西转换成字符串。
字符串
Ruby的字符串具备完整的操作支持,如:
irb(main):012:0> "hello" + "there" => "hellothere" irb(main):013:0> "Reader".length => 6 irb(main):014:0> "Reader".reverse => "redaeR" irb(main):015:0> "reader".capitalize => "Reader" irb(main):016:0> "Reader".include?("foo") => false irb(main):017:0> "Reader".include?("ade") => true irb(main):018:0> " Reader ".strip => "Reader" irb(main):019:0> "Reader".gsub("e", "f") => "Rfadfr" irb(main):020:0> "Reader".delete("ea") => "Rdr" irb(main):021:0> "a" < "b" => true
几乎可以使用所有的字符串操作符,可能有的你还从来都没有使用过,如下面的代码按字母顺序测试某个字符串是否位于其他两个之间:
irb(main):022:0> "Bob".between? "Adam", "Chris" => true
乘法操作符可以让给定的字符串重复显示指定的数量,如:
irb(main):023:0> "hi" * 5 => "hihihihihi"
Crypt函数为字符串提供了一个单向哈希加密功能,在存储敏感数据如密码时就可以使用它,如:
irb(main):024:0> "Reader".crypt("ab") => "abofgDjq6JNJo"
字符
Ruby没有内置的字符类型,它象数字一样表现字符,可以是?语法来表示一个字符常量,你可以使用chr函数将一个数字转换成一个等价的字符串,如:
irb(main):025:0> "Reader"[2] => 97 irb(main):026:0> ?a => 97 irb(main):027:0> 97.chr => "a"
赋值
其实执行这个操作并没什么用途,除非你可以将其存储起来方便后面使用,如:
irb(main):028:0>x = 42 =>42
字符串有一个特殊的语法,允许嵌入式赋值,这个赋值不仅仅局限于简单的变量替换,它是一个完整的赋值,如:
irb(main):029:0> "The answer is #{x}!" => "The answer is 42!" irb(main):030:0> "The answer is #{6 * 7}!" => "The answer is 42!"
可以使用单引号将字符串引起来避免这种赋值,注意是单引号,不是双引号,如:
irb(main):031:0> 'The answer is #{x}!' => "The answer is \#{x}!"
数组
Ruby中的数组与.NET 1.0中的ArrayList类很接近,它们的大小都是可变的,用于存储任意类型的数据,从0开始编号,如:
irb(main):032:0> a = ["hello", 42, "world"] => ["hello", 42, "world"] irb(main):033:0> a << 5.0 * 7.5 => ["hello", 42, "world", 37.5] irb(main):034:0> a[0] => "hello" irb(main):035:0> a[6] = 'hi' * 2 => "hihi" irb(main):036:0> a => ["hello", 42, "world", 37.5, nil, nil, "hihi"] irb(main):037:0> a[99] => nil
前面的代码显示了如何使用<<操作符向数组末尾追加项目,以及获取或设置值使用的指针操作符[],当你向数组末尾添加一个项目时,Ruby使用零值填充数组中的“洞”,当你访问数组外的值时,Ruby返回零值而不是异常。
你可以使用一个范围的指针将数组分片,也可以使用负的指针从后向前访问数组,-1就是最后一项,-2是倒数第二项,以此类推,但不能使用反向范围获取反向分片,你可以使用一个正向范围,然后调用reverse方法,如:
irb(main):038:0> a[-1] => "hihi" irb(main):039:0> a[1..3] =>[42, "world", 37.5] irb(main):040:0>a[2..-2] =>["world", 37.5, nil, nil] irb(main):041:0>a[-4..-1] =>[37.5, nil, nil, "hihi"] irb(main):042:0>a[-1..-4] # 不能工作 =>[] irb(main):043:0>a[-4..-1].reverse # 能够工作 =>["hihi", nil, nil, 37.5]
和字符串一样,你会发现有多个唯一对数组有用的类函数,如:
irb(main):044:0> a => ["hello", 42, "world", 37.5, nil, nil, "hihi"] irb(main):045:0> a.compact => ["hello", 42, "world", 37.5, "hihi"] irb(main):046:0> a.join => "hello42world37.5hihi" irb(main):047:0> [10, 75, 6, 29].sort => [6, 10, 29, 75] irb(main):048:0> [[1, 2, 3], [4, 5, 6]] => [[1, 2, 3], [4, 5, 6]] irb(main):049:0> [[1, 2, 3], [4, 5, 6]].flatten => [1, 2, 3, 4, 5, 6]
散列
Ruby的最后一个核心数据结构是散列,与.NET 1.0中的散列表类似,它是一个联合数组,它的键值可以是任意类型的值,它们指向的数据也可以是任意类型的数据,实际上,大部分散列使用的是符号作为键值。
使用{}语法声明散列,并且使用key => value格式声明初始值,在散列中获取或设置值时都可以使用键值操作符,如:
irb(main):050:0> h = {:foo=>'bar', :baz=>'biff'} => {:foo=>"bar", :baz=>"biff"} irb(main):051:0> h[:foo] => "bar" irb(main):052:0> h[:unknown] => nil irb(main):053:0> h[:baz] = "new" => "new" => {:foo=>"bar", :baz=>"new"} irb(main):054:0> h.entries => [[:foo, "bar"], [:baz, "new"]]
变量
Ruby中的变量和类函数名都是以小写字母开头的,可以包括字母、数字和下划线。本地变量没有前缀,实例变量以@开头,全局变量以$开头。
在使用变量前无需声明,未初始化的变量有一个零值,下面是几个预定义的变量:
nil表示一个“无”对象,与.NET中的null类似,除了nil是一个实例化的NilClass类外。
true和false分别是实例化的TrueClass和FalseClass。
在类函数中使用时,self指向调用类函数的对象实例;在一个类中使用时,它指的是实例化的类对象本身。
__FILE__ 和__LINE__返回当前执行文件和那个文件中的行号。
符号
Ruby有一个特殊类型的字符串,叫做符号,因为字符串在Ruby中是可以被修改的,使用它们作为散列键是很慢的,而且有一些情况是不能预测的。
除了它们是以冒号(:)开头外,符号的命名规则和变量的命名规则一致,你不能改变符号的值,两个名字相同的符号它们的身份就一样,它们可以作为优秀的散列键,查找请求只需要比较整数值,而不是与一个可变长字符串的值进行对比。
Ruby中的所有事物都是对象,所有对象都是类的实例,为了探索类是个什么东西,在它上面调用类函数:
5.class => Fixnum (2 ** 96).class => Bignum 7.5.class => Float (1..10).class => Range "foo".class => String /^foo[a-e]$/.class => Regexp :foo.class => Symbol [].class => Array {}.class => Hash
块和闭包
虽然这与.NET 1.X中的事件处理程序类似,但当你想处理它们时还是必须要定义完整的类函数来连接这些事件,这就导致需要创建大量的类函数,因为框架需要它。
.NET 2.0引入了匿名委派的概念,它们起的作用与Ruby中的块类似,如:
irb(main):001:0> h = {:foo=>'bar', :hi=>'there'} => {:foo=>"bar", :hi=>"there"} irb(main):002:0> h.each_key {|k| puts k} foo hi => {:foo=>"bar", :hi=>"there"} irb(main):003:0> h.each {|k,v| puts "#{k}: #{v}"} foo: bar hi: there => {:foo=>"bar", :hi=>"there"}
正如你所看到的,Ruby中块的语法是相当简洁的:通常使用一对大括号打开块和关闭块,使用|x,y|语法标出传递给块的变量。
Ruby中的块和闭包类似,正如.NET 2.0中的匿名委派,这意味着它们有权访问它们封装作用域的值,即使那个作用域退出后也可以访问。下面是一个将几个值相乘的闭包示例:
irb(main):004:0> n = [5, 6, 10] => [5, 6, 10] irb(main):005:0> t = 1 => 1 irb(main):006:0> n.each { |i| t *= i } => [5, 6, 10] irb(main):007:0> t => 300
你甚至可以将引用存储在块中,方便以后使用,如:
irb(main):008:0> t = 1 => 1 irb(main):009:0> f = lambda { |i| t *= i } => # < PRE>
函数
Ruby中函数的定义比.NET简单多了,因为不需要指定类型,如:
irb(main):001:0> def greet(name) irb(main):002:1> puts "Hello, #{name}!" irb(main):003:1> end => nil irb(main):004:0> greet "Reader" Hello, Reader! => nil irb(main):005:0> greet 42 Hello, 42! => nil
Ruby执行的某些东西叫做“鸭式输入”:如果它走起路来像鸭子或声音也像鸭子,那它一定就是鸭子。你不用问它“你是一只鸭子吗?”,你只需要将它当做鸭子对它呷呷地叫就可以了,如果你渴望成为一只鸭子,只要你能呷呷地叫的就可以加入这个party。
注意greet函数定义时没有对对象的类型做任何限制,因为它只打印它们—Ruby中任何事物都是支持打印的,这得益于to_s类函数的优点,它可以将任何对象转换成字符串,最终结果就是你可以greet它们。
下面是另一个例子:
irb(main):006:0> def print_len(item) irb(main):007:1> puts "Len = #{item.length}" irb(main):008:1> end => nil irb(main):009:0> print_len "Reader" Len = 6 => nil irb(main):010:0> print_len [1, 4, 9] Len = 3 => nil irb(main):011:0> print_len 42 NoMethodError: undefined method <span class="pf">' </span>length' for 42:Fixnum from (irb):7:in <span class="pf">'</span>print_len' from (irb):11
这里的print_len函数做的事情更多了:它调用了length函数。因此传递给print_len的是length函数的返回值,可以传递一个字符串或一个数组,因为它们都有对应的length函数,但是不能传递一个数字,因为没有对应数字的length函数。
为了在.NET中编写一个类似的函数,你可能需要创建一个IHaveLength接口作为你的参数类型,由于在你创建接口前类就已经创建好了,所以不幸的是,可能你需要创建一个类型转换器。
从另一方面来看,至少你已经有了IHaveLength,并且知道函数需要什么东西,既然类型担当的是某种格式文档的角色,在动态语言中你需要一个取舍,这样你会在编写文档和单元测试时更自信,可以帮助你识别类或函数是如何使用的。
Ruby支持默认的参数值,如:
irb(main):012:0>def repeat(val, times = 5) irb(main):013:1>val.to_s * times irb(main):014:1>end =>nil irb(main):015:0>repeat "hi" =>"hihihihihi" irb(main):016:0>repeat "hi", 3 =>"hihihi" irb(main):017:0>repeat 10, 3 =>"101010"
注意在to_s * times前面没有return,除非你明确地告诉它返回什么值,否则Ruby中的函数总是返回最后一个赋值,因此就不需要return关键字了。
Ruby支持变量参数,如:
irb(main):018:0> def add(*values) irb(main):019:1> result = 0 irb(main):020:1> values.each {|x| result += x} irb(main):021:1> result irb(main):022:1> end => nil irb(main):023:0> add 1, 2, 3, 4, 5 => 15
Ruby将变量参数打包成一个数组,然后你就可以访问传递来的值,并且可以将它们集合到一块儿。
函数和变量命名约定
Ruby中的函数以小写字母开头,可以包含字母,数字和下划线。改变基础对象的函数名称以一个惊叹号(!)结束,例如:upcase函数返回字符串的大写,但是还单独保留了原始字符串;相反,upcase!函数就真实地改变了基础字符串。
回答问题(返回布尔值)的函数名称以一个问号(?)结束。
类是来自新对象实例创建时的模板,例如:为了将前面的greet函数放入一个类,你可能要编写以下代码:
irb(main):001:0> class Manners irb(main):002:1> def greet(name) irb(main):003:2> puts "Hello, #{name}!" irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> m = Manners.new => #< PRE irb(main):007:0> m.greet ?Reader? Hello, Reader!=">" nil>
前面的代码创建了一个新的类,叫做Manners,并将函数greet添加到该类中了,最后,它创建了一个Manners类的实例,使用它greet Reader。
你可能认为在Ruby中类是对象的活动模板,与.NET中的类不同,Ruby中的类是编译时定义的,你可以对其进行任意扩展,当你完成扩展后,类的现有实例也会立即得到新的反应,注意当你尝试告诉它farewell时会发生什么,如:
irb(main):008:0> m.farewell "Reader" NoMethodError: undefined method 'farewell' for #<Manners:0x404839c> from (irb):8
当你尝试调用farewell时,系统会告诉你它不知道这是什么,那么就可以对Manners类进行扩展,让它知道这么说拜拜,如:
irb(main):009:0>class Manners irb(main):010:1>def farewell(name) irb(main):011:2>puts "Goodbye, #{name}!" irb(main):012:2>end irb(main):013:1>end =>nil irb(main):014:0>m.farewell "Reader" Goodbye, Reader! =>nil
扩展了Manners类后,它的已有实例就会立即获得这个新的功能。
Manners类有两个函数,两个都需要你的名字,你可能需要重新编写它以便你创建它时可以传递名字给它,Ruby调用initialize函数,你传递的所有参数都传递给new,下面是更新后的Manners类:
irb(main):001:0> class Manners irb(main):002:1> def initialize(name) irb(main):003:2> @name = name irb(main):004:2> end irb(main):005:1> def greet irb(main):006:2> puts "Hello, #{@name}!" irb(main):007:2> end irb(main):008:1> def farewell irb(main):009:2> puts "Goodbye, #{@name}!" irb(main):010:2> end irb(main):011:1> end => nil irb(main):012:0> m = Manners.new "Reader" => #< PRE m.greet Hello, Reader!=">" nil @name="Reader" > irb(main):013:0> irb(main):014:0> m.farewell Goodbye,>
注意类在一个实例变量@name中存储的名字,同时注意检查实例包括所有实例变量的值。
你自己定义的类可以随意扩展,而且也可以扩展Ruby内置的类,如:
irb(main):001:0> class Array irb(main):002:1> def print_tr irb(main):003:2> puts "<tr>" irb(main):004:2> each { |item| irb(main):005:3* puts " <td>#{item}</td>" irb(main):006:3> } irb(main):007:2> puts "</tr>" irb(main):008:2> end irb(main):009:1> end => nil Irb(main):010:0> ["hello","world!"].print_tr <tr> <td>hello</td> <td>world!</td> </tr> => nil
Rails对内置类型添加了许多扩展属性,提供了非常丰富的接口,例如:你可以编写类似5.days.from_now这样的代码,返回从现在开始5天后的日期。
迄今为止,你定义的函数都已经成为实例函数,即它们仅在类的实例中有效。Ruby也有静态函数,有时也叫做类函数。实际上,你已经调用过一次静态函数了,那就是new。
你可以在现有的类上添加任何新的静态函数,如:
irb(main):001:0> def String.concat(s1, s2) irb(main):002:1> s1 + ' ' + s2 irb(main):003:1> end => nil irb(main):004:0> String.concat 'hi', 'bye' => "hi bye"
你也可以使用self语法在定义或扩展类的上下文中定义它们,如:
irb(main):001:0> class String irb(main):002:1> def self.concat(s1, s2) irb(main):003:2> s1 + ' ' + s2 irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> String.concat 'hi', 'bye' => "hi bye"
反射
反射是运行时发现关于对象的信息的过程,你可以通过调用methods函数找到某个类可用的函数,Ruby中的基础类也是对象,下面是查找在Ruby中对每个对象都有效的函数的代码:
irb(main):001:0> o = Object.new => #<Object:0x3f8feb4> irb(main):002:0> o.methods => ["inspect", "taguri", "clone", "public_methods" , "taguri=", "display", "instance_variable_defined ?", "equal?", "freeze", "methods", "respond_to?", ...many more methods listed...
调用methods函数返回的结果是一个字符串数组,包含了那个对象上有效的每个函数的名字,你也可以认为类与散列非常相似,调用methods函数就与获取散列表的键值相似。
你若不使用函数做点事情,你会觉得它很无趣,为了调用函数,你还可以使用send函数,如下面这两条语句都是等效的:
irb(main):003:0> o.inspect => "#<Object:0x3f8feb4>" irb(main):004:0> o.send "inspect" => "#<Object:0x3f8feb4>"
通过在你的类中定义method_missing函数,Ruby让你有机会处理未知的函数,如:
irb(main):139:0> class Object irb(main):140:1> def method_missing(*args) irb(main):142:2> puts args irb(main):143:2> end irb(main):144:1> end => nil irb(main):145:0> o.foobar 1, 2, 3 foobar 1 2 3 => nil
正如你所看到的,传递给method_missing函数的参数包括请求的函数和所有传递给那个函数的参数,一个更好的定义如下:
def method_missing(method, *args)
元编程
即使Ruby没有属性,你也可以使用函数调用,通常不需要括弧来模拟属性,你也需要影响Ruby以“=”结束函数的特殊处理方式,让它们担当调节器的作用。
你可以象下面这样定义一个person类:
irb(main):001:0> class Person irb(main):002:1> def age irb(main):003:2> @age irb(main):004:2> end irb(main):005:1> def age=(value) irb(main):006:2> @age = value irb(main):007:2> end irb(main):008:1> end => nil
接下来就可以使用person类的实例,将age当作person类的一个属性来处理,如:
irb(main):009:0>p = Person.new =># < PRE irb(main):011:0>p.age="42" =">nil" irb(main):012:0>p.age=">42">
如果你想将age的默认值设为一个非零的值,那么你可以使用initialize函数来设置。
这个代码显得非常标准,如果这是一个类似c#的语言,你可能会使用类似Visual Studio中片段,甚至静态代码的产生会自动生成reader和writer的属性。
在Ruby中,你可以使用元编程做一点努力就可以创建这些事物,理想情况下,你可以编写类似下面这样的代码:
class Person prop :age end
你应该在对象上定义个类(静态)函数以便你在定义自己的类时可以使用它,你也可以使用一个你还没有看到过的函数,class_eval函数,如:
irb(main):001:0> class Object irb(main):002:1> def self.prop *names irb(main):003:2> names.each { |name| irb(main):004:3* self.class_eval " irb(main):005:3" def #{name} irb(main):006:3" @#{name} irb(main):007:3" end" irb(main):008:3> self.class_eval " irb(main):009:3" def #{name}=(value) irb(main):010:3" @#{name} = value irb(main):011:3" end" irb(main):012:3> } irb(main):013:2> nil irb(main):014:2> end irb(main):015:1> end => nil
上面使用的class_eval函数是创建了另外一个函数结束的,它给字符串赋值,因此你可以在你的类中编写自己的函数。
每个传递给prop函数的名字向新类添加了两个函数:getter和setter。最终使用你传递给prop的名字替换掉#{name}。
接下来,你可以在你的类定义中使用prop了,如:
irb(main):016:0> class Person irb(main):017:1> prop :age, :name irb(main):018:1> irb(main):019:1* def initialize(age, name) irb(main):020:2> @age = age irb(main):021:2> @name = name irb(main):022:2> end irb(main):023:1> end => nil irb(main):024:0> p = Person.new(36, "Brad") => # < PRE @name="Brad" > @age="36," irb(main):025:0> p.age=">" 36 irb(main):026:0> p.name=">" ?Brad?>
在你的环境中有了这些便利的工具后,你可以更快速地创建更高层次的类,使用这些元编程技巧可以帮助你工作得更好,不需要依赖于编辑片段或编译时代码生成。
小结
本文只是对Ruby中便利工具做了一个皮毛介绍,今天学习好Ruby可以在当Ruby.在.NET和Silverlight中可用时帮助你,有这么强大的一个动态编程语言,你的编程工具箱也会扩宽许多,但更重要的是,它可以帮助你开始以一种新的方式思考问题和解决方案。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Ruby快速入门
Ruby之symbol研究
理解 Ruby Symbol (Ruby中的冒号)
二十分钟Ruby入门 - [Matrix - 与 Java 共舞]
从其他程式语言到Ruby
Ruby快速入门(30分钟)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服