加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 taroxd 于 2014-8-11 14:21 编辑
如果你是刚刚接触 ruby 不久的新人,那么请无视这个帖子。
如果你是大触,那么也请无视这个帖子。
总之,这个帖子的内容没什么用,都是我瞎说的,有可能错误百出,看着玩玩就可以了。
@Scene
----------------------------------------------------
self 是什么?
要简单地说,也很简单。self 就是当前对象,也就是当前方法的接收者(receiver)。
但是 self 的存在意义远远不止这些。
----------------------------------------------------
首先,self 决定了实例变量的访问对象。
几乎每个对象都可以携带实例变量。当你访问一个实例变量的时候,Ruby 会寻找 self 内部的实例变量。
此外,self 在方法调用的时候会发生变化。隐式调用并不改变 self。
比如,print 函数其实就是定义在 Kernel 模块的私有方法。
当你调用 print 233 的时候,事实上是对当前的对象 self 调用了 print 方法。
此时 self 没有被改变。
然而,当你显式调用方法时,self 就会被设为方法的接收者。
比如 $game_party.members 的时候,在 members 的执行过程中,self 就被设为了 $game_party 所引用的那一个对象。
我们看一看调用 Game_Actors#max_level? 的时候会发生什么。
代码很简单,只有一行。
actor.max_level? # 假设 actor 已经赋值
actor.max_level? # 假设 actor 已经赋值
首先,我们显式地对 actor 调用了 max_level?,此时 self 被设为了 actor
然后执行 max_level 方法的内容:
首先我们遇见了 @level 。由于当前的 self 是 actor,因此 @level 访问了 actor 的实例变量。
接着又有一个隐式调用的方法 max_level。此时不改变 self,仍然对 actor 调用 max_level 方法。
最后调用 @level 的 >= 方法即可返回答案。
----------------------------------------
改变 self 的方式有如下几种。
最重要的一种刚刚已经说过,是方法的调用。
此外,还有类定义、模块定义也可以改变 self。
module SceneManager p self end #=> SceneManager
module SceneManager
p self
end
#=> SceneManager
在类定义和模块定义中,self 就被设置为当前的类或模块。
在这个例子里,这意味着,此时访问的实例变量,以及方法的隐式调用,self 都是设置为 SceneManager 的。
别忘了,模块也是对象,也可以拥有自己的实例变量。
module SceneManager #-------------------------------------------------------------------------- # ● 模块的实例变量 #-------------------------------------------------------------------------- @scene = nil # 当前场景实例 @stack = [] # 场景切换的记录 @background_bitmap = nil # 背景用的场景截图 #-------------------------------------------------------------------------- # ● 运行 #-------------------------------------------------------------------------- # 模块定义中,self 为 SceneManager。因此这里等价于 def SceneManager.run def self.run # ↓ 运行这里的代码时,self 一定会被设为 SceneManager DataManager.init Audio.setup_midi if use_midi? # 因此,访问 @scene 是访问模块的实例变量,也就是上面初始化过的变量。 # 同时,由于 self 在这里一定是 SceneManager,因此 first_scene_class 方法 # 的隐式调用,接收者正是 SceneManager。 @scene = first_scene_class.new @scene.main while @scene end end
module SceneManager
#--------------------------------------------------------------------------
# ● 模块的实例变量
#--------------------------------------------------------------------------
@scene = nil # 当前场景实例
@stack = [] # 场景切换的记录
@background_bitmap = nil # 背景用的场景截图
#--------------------------------------------------------------------------
# ● 运行
#--------------------------------------------------------------------------
# 模块定义中,self 为 SceneManager。因此这里等价于 def SceneManager.run
def self.run
# ↓ 运行这里的代码时,self 一定会被设为 SceneManager
DataManager.init
Audio.setup_midi if use_midi?
# 因此,访问 @scene 是访问模块的实例变量,也就是上面初始化过的变量。
# 同时,由于 self 在这里一定是 SceneManager,因此 first_scene_class 方法
# 的隐式调用,接收者正是 SceneManager。
@scene = first_scene_class.new
@scene.main while @scene
end
end
-------------------------------------------------------------
Proc 对象可以保留区块创建时的环境,包括 self。
module M lvar = 5 $a_mysterious_proc = Proc.new { print self, lvar, "\n" } end $a_mysterious_proc.call # 输出 M5
module M
lvar = 5
$a_mysterious_proc = Proc.new { print self, lvar, "\n" }
end
$a_mysterious_proc.call # 输出 M5
……这货有啥用?很有用。
class Game_Interpreter def setup_choices(params) params[0].each {|s| $game_message.choices.push(s) } $game_message.choice_cancel_type = params[1] $game_message.choice_proc = Proc.new {|n| @branch[@indent] = n } end end
class Game_Interpreter
def setup_choices(params)
params[0].each {|s| $game_message.choices.push(s) }
$game_message.choice_cancel_type = params[1]
$game_message.choice_proc = Proc.new {|n| @branch[@indent] = n }
end
end
关键在方法的最后一句,Proc.new {|n| @branch[@indent] = n }
Proc 传来传去时,可以保留 self ,因此 @branch 等实例变量都可以正确地访问了。
事实上 method 对象也有异曲同工之妙。只不过没有 Proc 那么优美的特性罢了。
要改变 self,我们可以使用 instance_eval 方法。
module M lvar = 5 $a_mysterious_proc = Proc.new { print self, lvar, "\n" } end "喵呜喵".instance_eval(&$a_mysterious_proc) # 输出 喵呜喵5
module M
lvar = 5
$a_mysterious_proc = Proc.new { print self, lvar, "\n" }
end
"喵呜喵".instance_eval(&$a_mysterious_proc) # 输出 喵呜喵5
在与 Proc 无关的代码中,我们也可以用 instance_eval 来改变 self。
$game_party.instance_eval { @gold = max_gold }
$game_party.instance_eval { @gold = max_gold }
但是这样就破坏了类的封装性,所以在不必要的时候还是少用为好。 |