- 浏览: 1400899 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
1 发送一条消息给一个对象
当你调用一个方法时,你也就是发送了一条消息给一个对象,在ruby中我们能够在运行时决定那个方法被调用。send 方法就是做这个的,他接受一个symbol为参数.
举个简单的例子,假设我们要写一个排序,我们想要使用不同的域作为比较的key。虽然我们这时可以用block,可是如果使用send的话,我们能有一个更优美的写法:
__send__ 其实也就是send方法的别名了。不过这边建议用__send__,这是因为send有可能作为一个用户自己定义的方法。
在1.9中,send方法不能调用private方法了,不过我们能够使用__send!来调用:
2 特殊化一个单独的对象
在很多oo语言里,一个类的所有的对象共享相同的行为,类作为一个模板,当构造器调用时,制造一个拥有相同接口的对象。
ruby中我们可以改变一个对象运行时的状态。你可以给对象一个私有的,匿名的子类:所有的原始的方法都是可用的。由于联系到这个对象上的行为是私有的,因此它只发生一次。一件只发生一次的事叫做“singleton”,比如singleton 方法,和singleton类.
看下面的代码:
加一个singleton 方法到一个对象,也就是创建了一个singleton 的类,然后这个类的父类是这个对象的类,如果你加多个方法到一个对象,这是你可以直接实现一个singleton 类:
这里要注意的是,一些更“primitive”的对象(比如Fixnum),不能加singleton 方法,这是因为这些对象,不是存引用在内存中的。但是在ruby将来的版本,可能会实现这个。
在一些库的源码中,我们能看到这种代码:
在一个类的体内,self 就指这个类自己,在这个类中的实例方法,其实也就是外面类的类方法:
使用这个技术的另一个原因是,可以创建一个类级别的帮助方法,然后我们就能在这个类的其他地方使用它了.
extend 方法能够mix一个模块到一个对象:
3 创建一个带参数的类
假设我们想要创建一个多样的类,也就是说,可以通过控制类变量来控制它的多种状态:
这样是可以的,这时如果我想要定义一些与Terran类似的类,你可能会马上想到是可以给这些类抽象出来一个超类就行了:
(注意,这里是错误的方法)
当你调用Terran.home_planet时,在1.9中会打印出nil,在1.8中会打印出Mars.
为什么会这样?答案是class variables 不是真正的class variables 。他们不属于类,而是属于整个继承体系。class variables不能从父类所被复制,但是能够从父类所被共享。
我们可以剔除掉类变量在基类中的定义,可是这时我们定义的类方法就不能工作了。
这里有一个稍好一些的方法,使用了class_eval 方法:
这个可以打印出我们想要的结果任何IntelligentLife里定义的实例变量,或者实例方法,都会被Terran 和 Martian所继承。
下面的方法可能是最好的方法,我们没有使用类变量,而是使用类实例变量:
这里我们打开了一个singleton class,定义了一个存取方法home_planet,两个子类调用他们自己的accessors 来设置变量.我们其实还可以给home_planet=方法设置为 private的。
这里其实还可以这样做:
4 使用Continuations 来实现一个生成器
ruby的一个更抽象的特性就是continuation。这是一种控制非局部的跳转和返回的方法。一个continuation 对象存储着一个返回的地址,和一个上下文.他看起来很像c中的setjmp/longjmp ,可是他存储着更多的上下文.
Kernel 的方法callcc接受一个block,返回一个Continuation 对象。这个被返回的对象作为一个参数被传递进这个block.Continuation唯一的方法就是call,调用它将会引起一个非局部的返回,执行callc的block直到它的尾部。
其实Continuation很像游戏中的保存游戏的特性。最好的理解Continuation的方法,就是去看电影Run, Lola, Run (哈哈,就是罗拉快跑).
Continuation的最好的例子就是生成器,现在生成器已经是ruby的一部分了。
请看下面的使用生成器的Fibonacci numbers 的例子:
这里要注意的是,continuations的性能不好,因为它保存了太多的状态和上下文...
当你调用一个方法时,你也就是发送了一条消息给一个对象,在ruby中我们能够在运行时决定那个方法被调用。send 方法就是做这个的,他接受一个symbol为参数.
举个简单的例子,假设我们要写一个排序,我们想要使用不同的域作为比较的key。虽然我们这时可以用block,可是如果使用send的话,我们能有一个更优美的写法:
class Person attr_reader :name, :age, :height def initialize(name, age, height) @name, @age, @height = name, age, height end def inspect "#@name #@age #@height" end end class Array def sort_by(sym) # Our own version of sort_by self.sort {|x,y| x.send(sym) <=> y.send(sym) } end end people = [] people << Person.new("Hansel", 35, 69) people << Person.new("Gretel", 32, 64) people << Person.new("Ted", 36, 68) people << Person.new("Alice", 33, 63) p1 = people.sort_by(:name) p2 = people.sort_by(:age) p3 = people.sort_by(:height) p p1 # [Alice 33 63, Gretel 32 64, Hansel 35 69, Ted 36 68] p p2 # [Gretel 32 64, Alice 33 63, Hansel 35 69, Ted 36 68] p p3 # [Alice 33 63, Gretel 32 64, Ted 36 68, Hansel 35 69]
__send__ 其实也就是send方法的别名了。不过这边建议用__send__,这是因为send有可能作为一个用户自己定义的方法。
在1.9中,send方法不能调用private方法了,不过我们能够使用__send!来调用:
class Foo private def foo "aa" end end p Foo.new.__send!(:foo) # => nil p Foo.new.send(:foo) #private method `foo' called for #<Foo:0xa89530> (NoMethodError)
2 特殊化一个单独的对象
在很多oo语言里,一个类的所有的对象共享相同的行为,类作为一个模板,当构造器调用时,制造一个拥有相同接口的对象。
ruby中我们可以改变一个对象运行时的状态。你可以给对象一个私有的,匿名的子类:所有的原始的方法都是可用的。由于联系到这个对象上的行为是私有的,因此它只发生一次。一件只发生一次的事叫做“singleton”,比如singleton 方法,和singleton类.
看下面的代码:
a = "hello" b = "goodbye" def b.upcase # create single method gsub(/(.)(.)/) { $1.upcase + $2 } end puts a.upcase # HELLO puts b.upcase # GoOdBye
加一个singleton 方法到一个对象,也就是创建了一个singleton 的类,然后这个类的父类是这个对象的类,如果你加多个方法到一个对象,这是你可以直接实现一个singleton 类:
b = "goodbye" class << b def upcase # create single method gsub(/(.)(.)/) { $1.upcase + $2 } end def upcase! gsub!(/(.)(.)/) { $1.upcase + $2 } end end puts b.upcase # GoOdBye puts b # goodbye b.upcase! puts b # GoOdBye
这里要注意的是,一些更“primitive”的对象(比如Fixnum),不能加singleton 方法,这是因为这些对象,不是存引用在内存中的。但是在ruby将来的版本,可能会实现这个。
在一些库的源码中,我们能看到这种代码:
class SomeClass # Stuff... class << self # more stuff... end # ... and so on. end
在一个类的体内,self 就指这个类自己,在这个类中的实例方法,其实也就是外面类的类方法:
class TheClass class << self def hello puts "hi" end end end # invoke a class method TheClass.hello # hi
使用这个技术的另一个原因是,可以创建一个类级别的帮助方法,然后我们就能在这个类的其他地方使用它了.
class MyClass class << self def accessor_string(*names) names.each do |name| class_eval <<-EOF def #{name} @#{name}.to_s end EOF end end end def initialize @a = [ 1, 2, 3 ] @b = Time.now end accessor_string :a, :b end o = MyClass.new puts o.a # 123 puts o.b # Mon Apr 30 23:12:15 CDT 2001
extend 方法能够mix一个模块到一个对象:
module Quantifier def any? self.each { |x| return true if yield x } false end def all? self.each { |x| return false if not yield x } true end end list = [1, 2, 3, 4, 5] list.extend(Quantifier) flag1 = list.any? {|x| x > 5 } # false flag2 = list.any? {|x| x >= 5 } # true flag3 = list.all? {|x| x <= 10 } # true flag4 = list.all? {|x| x % 2 == 0 } # false
3 创建一个带参数的类
假设我们想要创建一个多样的类,也就是说,可以通过控制类变量来控制它的多种状态:
class Terran @@home_planet = "Earth" def Terran.home_planet @@home_planet end def Terran.home_planet=(x) @@home_planet = x end #... end
这样是可以的,这时如果我想要定义一些与Terran类似的类,你可能会马上想到是可以给这些类抽象出来一个超类就行了:
(注意,这里是错误的方法)
class IntelligentLife # Wrong way to do this! @@home_planet = nil def IntelligentLife.home_planet @@home_planet end def IntelligentLife.home_planet=(x) @@home_planet = x end #... end class Terran < IntelligentLife @@home_planet = "Earth" #... end class Martian < IntelligentLife @@home_planet = "Mars" #... end
当你调用Terran.home_planet时,在1.9中会打印出nil,在1.8中会打印出Mars.
为什么会这样?答案是class variables 不是真正的class variables 。他们不属于类,而是属于整个继承体系。class variables不能从父类所被复制,但是能够从父类所被共享。
我们可以剔除掉类变量在基类中的定义,可是这时我们定义的类方法就不能工作了。
这里有一个稍好一些的方法,使用了class_eval 方法:
class IntelligentLife def IntelligentLife.home_planet class_eval("@@home_planet") end def IntelligentLife.home_planet=(x) class_eval("@@home_planet = #{x}") end #... end class Terran < IntelligentLife @@home_planet = "Earth" #... end class Martian < IntelligentLife @@home_planet = "Mars" #... end puts Terran.home_planet # Earth puts Martian.home_planet # Mars
这个可以打印出我们想要的结果任何IntelligentLife里定义的实例变量,或者实例方法,都会被Terran 和 Martian所继承。
下面的方法可能是最好的方法,我们没有使用类变量,而是使用类实例变量:
class IntelligentLife class << self attr_accessor :home_planet end #... end class Terran < IntelligentLife self.home_planet = "Earth" #... end class Martian < IntelligentLife self.home_planet = "Mars" #... end puts Terran.home_planet # Earth puts Martian.home_planet # Mars
这里我们打开了一个singleton class,定义了一个存取方法home_planet,两个子类调用他们自己的accessors 来设置变量.我们其实还可以给home_planet=方法设置为 private的。
这里其实还可以这样做:
module IntelligentLife attr_accessor :home_planet end class Terran class << self include IntelligentLife end self.home_planet = "Earth" #... end class Martian class << self include IntelligentLife end self.home_planet = "Mars" #... end puts Terran.home_planet # Earth puts Martian.home_planet # Mars
4 使用Continuations 来实现一个生成器
ruby的一个更抽象的特性就是continuation。这是一种控制非局部的跳转和返回的方法。一个continuation 对象存储着一个返回的地址,和一个上下文.他看起来很像c中的setjmp/longjmp ,可是他存储着更多的上下文.
Kernel 的方法callcc接受一个block,返回一个Continuation 对象。这个被返回的对象作为一个参数被传递进这个block.Continuation唯一的方法就是call,调用它将会引起一个非局部的返回,执行callc的block直到它的尾部。
其实Continuation很像游戏中的保存游戏的特性。最好的理解Continuation的方法,就是去看电影Run, Lola, Run (哈哈,就是罗拉快跑).
Continuation的最好的例子就是生成器,现在生成器已经是ruby的一部分了。
请看下面的使用生成器的Fibonacci numbers 的例子:
class Generator def initialize do_generation end def next callcc do |here| @main_context = here; @generator_context.call end end private def do_generation callcc do |context| @generator_context = context; return end generating_loop end def generate(value) callcc do |context| @generator_context = context; @main_context.call(value) end end end # Subclass this and define a generating_loop class FibGenerator < Generator def generating_loop generate(1) a, b = 1, 1 loop do generate(b) a, b = b, a+b end end end # Now instantiate the class... fib = FibGenerator.new puts fib.next # 1 puts fib.next # 1 puts fib.next # 2 puts fib.next # 3 puts fib.next # 5 puts fib.next # 8 puts fib.next # 13
这里要注意的是,continuations的性能不好,因为它保存了太多的状态和上下文...
发表评论
-
一个创建闭包的小技巧
2008-06-05 00:12 2139一个小技巧,在Ola Bini 的blog上看到的。 假设你 ... -
解决Colored Cubes问题
2008-06-02 10:43 2785Engineering Puzzle You have fo ... -
ruby1.9中的Iterators
2008-03-05 22:37 3724在ruby1.9中增加了External Iterators这 ... -
一个简单的ruby Metaprogram的例子
2008-03-03 23:49 4105比如下面一个文件 people.txt 引用name,age ... -
Ruby Object Model
2008-03-03 19:29 3582刚好看到,保存一下. -
一个检测方法的参数类型的小程序
2008-03-02 22:48 3249今天没事看blog的时候,看到一个小子实现了这个,不过他的程序 ... -
rails中的BlankSlate源码分析
2008-02-28 23:27 3448其实这个类实现的功能很简单,那就是实现一个没有predefin ... -
ruby中的类变量与类实例变量
2008-02-26 21:15 7637首先,在ruby1.8中类变量是所有子类和父类共享的,可以看下 ... -
在ubuntu上共存多个版本的ruby
2008-02-24 15:20 4379今天装Revactor库的时候,真把我郁闷了,没想到ubunt ... -
看到了一个用ruby写的scheme解释器
2008-02-16 21:35 3773,自己本来想等啥时候有时间做个类似的东西呢,没想到已经有人做 ... -
ruby way之处理RSS和Atom
2008-01-31 01:32 35231 rss 标准库 RSS 是基于xml的,因此你能简单的将 ... -
ruby way之使用REXML解析xml
2008-01-30 00:35 9256REXML 是一个完全用ruby写的processor ,他有 ... -
rails2中的一些被废弃的用法
2008-01-29 00:33 2544这些只是自己最近看web开发敏捷之道的时候(由于书中的版本是1 ... -
ruby way之动态特性之二
2008-01-25 00:49 36861 得到所定义的实体的列表 ruby的反射api能够使我们在 ... -
ruby way之动态特性之一
2008-01-23 01:25 45541 动态的evaluate代码 全局的方法eval 编译并且 ... -
ruby way之高级OOP特性之二
2008-01-20 03:43 29541 把代码像对象一样存储 当你想要以对象的形式存储一块代码的 ... -
ruby way之OOP之二
2008-01-16 23:59 23661 理解allocate 在一些特殊的环境中,你可能需要不调 ... -
ruby way之OOP之一
2008-01-16 00:25 26431 使用多个构造方法 在ruby中没有像c++或者ruby中 ... -
ruby way之连接数据库
2008-01-14 00:47 2477这边都只是个大概,具体的要自己去看文档了. 1 连接SQLi ... -
ruby way之高级数据存取
2008-01-13 02:31 3740经常我们需要以一种更 ...
相关推荐
通过以上内容的详细讲解,《The Ruby Way》第二版为读者提供了全面且深入的Ruby编程知识体系,无论是对于初学者还是有经验的开发者而言,都是一本非常有价值的参考书籍。此外,读者还可以从作者提供的网站...
继承、封装和多态是OOP的三大特性,它们在Ruby中都有强大的支持。 在"ruby-event-oop"中,我们可能关注以下几点: 1. **EventMachine库**:Ruby社区广泛使用的事件库,它提供了一个异步I/O框架,允许开发者编写...
然而,Ruby提供了一种称为“方法_missing”的特性,它允许在找不到特定方法时执行自定义代码。这在某种程度上模拟了JavaScript原型链的行为。 Ruby中,类通过继承来扩展功能,可以使用`super`关键字调用父类的方法...
在PHP中,面向对象编程(OOP)是高级开发中不可或缺的一部分。OOP技术使得代码更加模块化、可维护和可扩展。以下是对标题和描述中提到的几个关键知识点的详细解释: 1. **序列化(Serializing)**: 序列化是将对象...
Delphi 5高级编程丛书之一IDE与OOP编程压缩分卷之一
尽管C语言不是面向对象的编程语言,但通过结构体、函数指针和手动内存管理等技术,我们仍然可以在C语言中模拟面向对象编程的一些核心特性。这种方法虽然有一定的局限性,但也提供了足够的灵活性,允许我们在C语言中...
面向对象编程(Object-Oriented Programming,简称OOP)是软件开发中的一种核心编程范式,C#语言作为.NET框架的主要编程语言,充分利用了OOP的特性。在本主题".NET C# OOP面向对象技术"中,我们将深入探讨C#中的面向...
C#继承OOP实例源码Class 。 `
- 元编程是Ruby的核心优势之一。 - 动态创建方法和属性。 - 使用评估(Evaluation)和反射(Reflection)技术。 - 扩展和覆盖内置行为。 6. **测试与调试** - Ruby提供了丰富的测试框架,如RSpec和Test::Unit等。 ...
"PHP5面向对象初步(第二章).php"可能涉及封装的概念,这是OOP的四大特性之一。封装允许我们将数据和操作这些数据的方法绑定在一起,保护内部数据不受外界干扰。通过访问修饰符(如public、private、protected),...
这本面向初学者和高级读者的指南旨在全面介绍Ruby编程语言的基础及其高级特性,因此我们将从多个角度来解析这些内容。 ### 一、Ruby编程语言简介 #### 1.1 Ruby语言的历史与发展 Ruby是一种动态、面向对象的脚本...
第四章深入探讨了面向对象编程的思想,这是理解Ruby的关键之一。教程解释了对象、封装、继承和多态这些OOP核心概念,并通过实际示例展示了如何在Ruby中应用它们。对于希望掌握OOP原理的学习者来说,这部分内容尤为...
继承是OOP的另一个关键特性,允许新类从已有的类(父类)继承属性和方法,同时还可以添加新的特性或修改已有行为。这样,代码复用性大大提升,软件设计的灵活性也得以增强。父类和子类的关系形成了类的层次结构,...
《Ruby经典教程:从新手到专家》是一本深入浅出介绍Ruby编程语言的权威指南,由Peter Cooper编写,why the lucky stiff作序推荐,专为Ruby...Ruby作为一种灵活且强大的语言,其学习之旅将为你的编程生涯开启新的篇章。
Ruby是一种灵活、简洁且富有表现力的编程语言,它提倡元编程和代码简洁性,与Java的面向对象特性有所不同。 首先,我们要理解Java和Ruby在面向对象编程(OOP)上的差异。Java的OOP体系严谨,类定义严格,而Ruby则...
面向对象编程是现代软件开发中的核心编程范式之一,它以类和对象为基本单元,强调数据封装、继承和多态这三大特性。这款应用的创建旨在帮助学员深入理解和实践OOP思想。 首先,我们要理解什么是面向对象编程。OOP的...
封装是面向对象的三大特性之一,它隐藏了对象的内部实现细节,只对外提供公共接口进行交互。在Java中,我们使用访问修饰符(public, private, protected)来控制字段和方法的可见性,以实现封装。 3. 继承 继承允许...
在Ruby编程语言中,面向对象编程(Object-Oriented Programming, OOP)是一种核心特性,它使得代码更加结构化和可重用。"learn_oop_ruby:启动School Ruby OOP教程"是一个针对初学者的资源,旨在帮助他们掌握Ruby中的...