| 
本帖最后由 忧雪の伤 于 2012-8-6 15:17 编辑
x
加入我们,或者,欢迎回来。您需要 登录 才可以下载或查看,没有帐号?注册会员  
 
 
 
 前言:以下内容没有一个是你在平常的游戏制作中需要的,所以纯粹是来看教学的可以绕道了。 
 
 ① 元类 ( metaclass ) 先看一段代码。
 class << 和 class 有什么区别呢?为什么可以在一个不是类的对象前使用呢?复制代码class << foo = Object.new
  def foo
    p 0
  end
end
foo.foo
其实这个行为相当于把一个匿名类混合插入(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] 的改变而改变。
 于是你可以这样做。
 当然这时直接 p block 返回的是一个 #Proc,并不是我们想要的 #Fixnum,我们需要让它启动,因为这实际上处于一个封装的状态。这样就能让它启动。是不是很神奇呢?复制代码block = proc { $game_variable[var_id] }
实际上这和方法的原理相同,都是封装的过程,在你调用的时候进行计算。
 而且一样可以带参数(块的参数),例如。
 这简直就像无名函数一样。复制代码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
因为是封装,所以即使之后原来的方法被再定义也还是不会有变动。
 Ruby 还提供了一个非常有用的方法,那就是 Method#receiver,可以返回原来的被调对象。复制代码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
复制代码class Foo
  def foo;  end
end
foo = Foo.new
foo.equal? foo.method(:foo).receiver
 结言:大家看完了之后是不是感觉被坑了呢?反正笔者自己感觉是的。笔者暂时想到的就这么多,如果有其他新奇的东西也请麻烦提出来吧~ → 其实笔者自己也是个小白。
 
 
 
 |