加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 忧雪の伤 于 2012-8-6 15:17 编辑
前言:以下内容没有一个是你在平常的游戏制作中需要的,所以纯粹是来看教学的可以绕道了。
① 元类 ( metaclass )
先看一段代码。- class << foo = Object.new
- def foo
- p 0
- end
- end
- foo.foo
复制代码 class << 和 class 有什么区别呢?为什么可以在一个不是类的对象前使用呢?
其实这个行为相当于把一个匿名类混合插入(mix-in)进对象,这个行为就和 include 相似。
所以对象就会拥有这些新的实例方法了。
以上的行为就像添加对象的特殊方法,并不会影响到原本的类和其他实例。
(实际上不少人都把它这样用了,例如有人说可以用这个方式来代替 Module#module_function )
这个行为有个好处就是可以用类的方法,比如 Class#attr_accessor、Class#alias_method什么的。你甚至可以往这里 include,不污染到原本的类什么的。- class << foo = Object.new
- def foo
- p 0
- end
- alias_method :bar, :foo
- end
- foo.bar
复制代码 不过说到底这些根本很少会用到吧?
这个匿名类也是一个实际存在的对象,我们可以通过编写一个快捷的方法来获得它。- class Object
- def metaclass
- class << self
- self
- end
- end
- end
- p Object.new.metaclass
复制代码 就可以获取到了~至于这个对象有什么用就是你要研究的事情了。
元类是个很神奇的东西,笔者有很多事情到现在都无法理解。(不会告诉你笔者是才刚懂的)
元类也有一种叫法叫单例类(Singleton Class)。(从异常报告来看似乎 Ruby 自己的叫法就是这个)
② 过程对象 ( Proc )
RPG Maker 中,如果你需要一个变量或者常量随时返回一个 #Game_Variable 的值怎么办?
难道是 var = $game_variable[var_id] ?#Fixnum 是即时值,var 并不会随着 $game_variable[var_id] 的改变而改变。
于是你可以这样做。- block = proc { $game_variable[var_id] }
复制代码 当然这时直接 p block 返回的是一个 #Proc,并不是我们想要的 #Fixnum,我们需要让它启动,因为这实际上处于一个封装的状态。这样就能让它启动。是不是很神奇呢?
实际上这和方法的原理相同,都是封装的过程,在你调用的时候进行计算。
而且一样可以带参数(块的参数),例如。- block = proc {|arg| p arg }
- p block.call 0
复制代码 这简直就像无名函数一样。
过程对象在构建的时候会导入当前作用域的局部变量,这需要注意。RPG Maker XP 的默认脚本中就用到了这个来传递实例变量(虽然我觉得根本没这个必要……)
③ Object#instance_eval
如果想在当前作用域中进入其他对象的作用域怎么办?
Ruby 为我们提供了非常便捷的方法,那就是 instance_eval 。
它可以干什么呢?
例如,为对象定义一个它的实例变量?- Object.new.instance_eval { @foo = 0 }
复制代码 实际上,这个方法是在调用对象的作用域中计算所带的块。
可以做到一些很方便的事情哦,毕竟是跨了作用域。当然要怎么玩都由你们自己发现了。
此外它也支持像 eval 一样计算字符串的功能,例如。- Object.new.instance_eval 'p self'
复制代码
④方法对象 ( Method )
如果需要在一个对象调用另外一个对象的方法怎么办(这两个对象本身作用域不同)?
Ruby 有一个特殊的类 Method,它不能通过 Class#new 生成实例,而是要通过 Object#method 来生成它的实例。
Object#method 可以把对象的方法变为方法对象,把方法和被调对象都封装在了一起,例如。- class Foo
- def foo
- end
- end
- foo = Foo.new
- method = foo.method :foo
- p method
复制代码 如果执行这个对象,相当于调用了那个方法。- class Foo
- @@foo = []
- def foo
- @@foo << 0
- end
- end
- method = Foo.new.method :foo
- method.call
- class Foo
- p @@foo
- end
复制代码 所以才能做到跨作用域调用原对象的方法。
因为是封装,所以即使之后原来的方法被再定义也还是不会有变动。- class Foo
- @@foo = []
- def foo
- @@foo << 0
- end
- end
- method = Foo.new.method :foo
- class Foo
- def foo
- @@foo.pop
- end
- end
- method.call
- class Foo
- p @@foo
- end
- Foo.new.foo
- class Foo
- p @@foo
- end
复制代码 Ruby 还提供了一个非常有用的方法,那就是 Method#receiver,可以返回原来的被调对象。- class Foo
- def foo; end
- end
- foo = Foo.new
- foo.equal? foo.method(:foo).receiver
复制代码
结言:大家看完了之后是不是感觉被坑了呢?反正笔者自己感觉是的。笔者暂时想到的就这么多,如果有其他新奇的东西也请麻烦提出来吧~ → 其实笔者自己也是个小白。
|