本帖最后由 taroxd 于 2014-6-24 12:09 编辑 moy 发表于 2014-6-24 10:39 @余烬之中 会提OOP的。他的解释挺不错的,我很喜欢。 我写的话,就会和上面一样,太理论太枯燥了,也不简单易懂。 这样的解释确实会有不利的影响。首先是“作用域”这个词,不能乱说。 然后,这对Ruby中调用方法的理解也会有影响。这在我上面举的那个Person中已经有所体现。现在继续。 [pre lang="ruby" line="1"]class Person attr_accessor :name include Math def do_math puts "sin(π / 3) = #{sin(PI / 3)}" end def do_physics puts "#@name 在做物理" end def do_something do_math do_physics end end class Physicist < Person def do_physics puts 'E = mc²' end end m5 = Physicist.new m5.do_something[/pre] 为什么 Person 类的方法 do_something 会引用到Physicist的方法?do_something 明明是在 Person 类定义的,按照你的“作用域理论”,调用的 do_physics 难道不应该是 Person 类的方法吗? 在引人类的继承和模块的 mix-in 后,方法的关系会愈加混乱。方法的调用到底会调用哪个类中的方法? 再举个错误的例子: [pre lang="ruby" line="1"] class Battler @hp = 20 def show_hp puts @hp end end Battler.new.show_hp # ??? Battler.show_hp # ???[/pre] 这不是类与实例的关系,而是对 self 和实例变量的理解问题。 极端点的例子,你可以看看 https://rpg.blue/thread-347871-1-1.html self 的概念,在其中无比重要。 当然,入门教程只要简单说一下就好了,知道 self 是什么,足矣 |
|
[pre lang="ruby" line="1"]class A def wryyy p self end def self.wryyy p self end end class B < A end a = A.new b = B.new a.wryyy #=> <A:0x*******> b.wryyy #=> <B:0x*******> A.wryyy #=> A B.wryyy #=> B[/pre] 我不知道你想怎么指,反正我的意思是,既然继承了A,那么他就继承了A的性质和作用域,但是他还是B。就好像糖水和盐水都是水一样。 ↑ 至于这种解释到底有没有谬误,我是不管的。我也不知道这样的解释是否有明显的弊端。 同时,我觉得并不需要理解self的具体含义。默认脚本中除了module使用了def self-end以外,别处都是对类的实例的self指定。 如果你要强调实例和类的区别,那么确实,我并没有提,也并不打算提。你提呗……我认真的。 |
本帖最后由 taroxd 于 2014-6-24 10:18 编辑 moy 发表于 2014-6-24 09:51 所以说,你对”类的作用域”的解释是完全错误的。include这一句,显然是在”类的作用域”里面的。 事实上,那些方法的隐式调用,是在 def 的作用域里面的。 你可以不说类的作用域,就像小学生不知道复数一样。你可以说,pos? 就是调用这个类里面刚刚定义过的方法。 但你既然说了,就不要乱说。你回去看看你对”类的作用域”是怎么说的。这不是近似说法,而是错误的说法。 可以近似,可以简略,可以避开,可以卖萌,甚至可以有漏洞,但绝不能错误。这是我的原则。 |
|
本帖最后由 taroxd 于 2014-6-24 06:42 编辑 吐槽start。 重要说明:以下内容并不算“入门”,不属于教程活动的范围之中。 教程活动仅需要对 self 的简单理解即可。 在这段脚本中,我们可以看到,同在Game_CharacterBase,pos_nt?方法内部直接使用了pos?方法,也就是说在同一个类(class)里面,方法之间的互相调用是可以直接实现的。这种嵌来套去的调用方式在VA-RGSS3的默认脚本里面可谓遍地都是。 这一段解释非常不好。 这种隐式的方法调用并不一定要在同一个类或子类中,关键在于 self 的设定。隐式方法调用相当于对 self 调用这个方法。 比如说下面的例子。 [pre lang="ruby" line="1"]class Person attr_accessor :name include Math end[/pre] 你注意到,我们调用了一些方法,分别是 attr_accessor 和 include。显然这个方法并不是在Person或者Person的父类中。 这是因为,在类定义中,self 指的就是这个类 我们翻阅Ruby文档,在 Module 类可以找到 attr_accessor 和 include 的定义。 于是,我们可以尝试 [pre lang="ruby" line="1"]class Person self.attr_accessor :name self.include Math end[/pre] 什么?你说报错?我才不告诉你为什么呢~ 于是,我们在写代码的过程中,有这些方式可以改变 self 的值…… 啊,再讲下去就成元编程了。我们还是回到原来的问题。 pos_nt?方法内部为什么可以直接使用pos?方法? 因为:在方法的定义中,self 的值被设为方法的调用者(接收者)。 我们假设对 a 事件调用了 pos_nt? 方法 a.pos_nt? 我们根据方法的定义,可以将其解释为: a.pos?(x, y) && !a的实例变量@through 我们注意到了这里的实例变量。实例变量访问的,其实也是 self 的实例变量。 我们也可以这么定义 pos_nt? 这是没有任何问题的。 [pre lang="ruby" line="1"]class Game_CharacterBase def pos_nt?(x, y) self.pos?(x, y) && !@through end end[/pre] 我们继续: [pre lang="ruby" line="1"] class Person attr_accessor :name include Math def do_math puts "sin(π / 3) = #{sin(PI / 3)}" end def do_something do_math do_physics end end m5 = Person.new m5.name = '喵呜喵5' def m5.do_physics puts "#{name}在做物理" end m5.do_something [/pre] 在这个例子中,你可以看到,在 Person 类里面并没有定义 sin 和 do_physics。那为什么我们可以直接调用呢? 为什么之后 m5.do_physics 明显在类的作用域外,却可以直接调用方法 name 呢? 没错,一切都在于 self 的切换 。 所以说,“类的作用域“仅仅有切换 self,切换当前类,屏蔽局部变量的功能,和方法的调用没有任何关系! 同理,def 的作用域也是如此! “切换当前类”是什么东西?我就不告诉你。 当我们不想要屏蔽局部变量的时候怎么办呢?这个时候就应该……咳咳我又要讲多了。嗯就这样吧。 最后: 我觉得我写的东西就是枯燥……所以才让你们写啦~~~ 但是,这种错误还是少犯为好。 |