Project1

标题: 有关方法重载的一个悲剧 [打印本页]

作者: DeathKing    时间: 2010-7-22 12:01
标题: 有关方法重载的一个悲剧
本帖最后由 DeathKing 于 2010-7-22 12:51 编辑

我最近正在慢慢研究ZTBS系统,为了稍微修改一下系统,我添加了一个叫做Fuki Help的帮助窗口,就像下面这样:



但是如果就这样的话,会导致那个小箭头没办法释放:



于是我就重载了visible=这个方法,我的想法是:当这个help_window的可见性被设置为false时,我就把这个小箭头给释放掉:

  1.   alias :dk_visible= :visible=
  2.   def visible=(value)
  3.     unless value
  4.       @fuki.bitmap = nil if @fuki.is_a? Sprite
  5.     end
  6.     dk_visible=(value)
  7.   end
复制代码
最后小箭头是释放掉了,但是窗体的却还是可见。我用反射机制看了看Window类,发现visible不是实例变量而是visible和visible=两个方法。

我上面的写法都没错啊,到底是怎么回事,需要工程么?
作者: IamI    时间: 2010-7-22 12:21
……你又囧了,直接赋值为nil当然还在,dispose啊……
另外,C类(内置类全部都是)当中只能改方法,没有变量……因为变量隐藏在C类中
作者: DeathKing    时间: 2010-7-22 12:22
回复 IamI 的帖子

@fuki是那个小箭头,我还要用的,所以不想要释放掉。
我说的是窗口。
   
作者: 六祈    时间: 2010-7-22 12:29
回复 DeathKing 的帖子

死君要改名做囧君了么~~~~~~~~

话说不太明白你的情况
不过愚以为窗体(window)用完都是dispose的。。。


   
作者: 风雪优游    时间: 2010-7-22 12:32
不如去掉那个小箭头吧,对于玩家来说,有没有都一样吧?
作者: IamI    时间: 2010-7-22 12:34
世界喜感……去掉重载方法名内的等号,世界清静了……
  1. class Window_K < Window
  2.   alias :dk_visible visible=
  3.   def visible=(value)
  4.     unless value
  5.       p "Set"
  6.     end
  7.     dk_visible(value)
  8.   end
  9. end

  10. a = Window_K.new
  11. a.visible = false
  12. p a.visible
  13. a.visible = true
复制代码

作者: DeathKing    时间: 2010-7-22 12:37
回复 IamI 的帖子
    的确可行,求原因,是alias的bug么?

   
作者: 紫苏    时间: 2010-7-22 12:38
可以通过显式指定 self 为接受者来告诉解释器这是一个方法
作者: 小旅    时间: 2010-7-22 12:38
嘛一般不是可以直接@sprite.visible = @help_window.visible 吗?一般我喜欢在update里插入
作者: IamI    时间: 2010-7-22 12:38
回复 DeathKing 的帖子
鬼才知道= =我们来看个更喜感的东西吧 囧
  1. class Window_K < Window
  2.   alias :dk_visible= visible=
  3.   def visible=(value)
  4.     unless value
  5.       p "Set"
  6.     end
  7.     self.dk_visible = value
  8.   end
  9. end

  10. a = Window_K.new
  11. a.visible = false
  12. p a.visible
  13. a.visible = true
复制代码

作者: DeathKing    时间: 2010-7-22 12:42
能否详细说明一下其中的奥妙?对Ruby和C之间的勾当很有兴趣。
   
作者: 六祈    时间: 2010-7-22 12:52
回复 DeathKing 的帖子

大约是被ruby当成局部变量了
   
作者: DeathKing    时间: 2010-7-22 12:54
回复 六祈 的帖子


    我加了括号变方法了啊(而且有参数)
作者: 六祈    时间: 2010-7-22 12:59
回复 DeathKing 的帖子
于是推测ruby对形如xxx=的执行优先级如下:
1.def定义的方法
2.局部变量
3.alias出来的方法

   
作者: 灼眼的夏娜    时间: 2010-7-22 13:01
回复
于是推测ruby对形如xxx=的执行优先级如下:
1.def定义的方法
2.局部变量
3.alias出来的方法

     ...
六祈 发表于 2010-7-22 12:59


varname = value 都是对局部变量赋值~ 不会调用方法 和 def的 alias的没关系


作者: DeathKing    时间: 2010-7-22 13:07
回复 灼眼的夏娜 的帖子

先膜拜一下夏娜大人

但是如果我使用 method= value 也会算成变量?

顺便打听RGE2.0的消息。
   
作者: DeathKing    时间: 2010-7-22 13:12
纯引用zh君的话,应该不算连帖吧?

古明地 蓝13:07:02
因为咱主人变笨了- -所以我也变笨了- -
右代宫 真里亚  13:07:11
self.xxx?
古明地 蓝  13:07:14

古明地 蓝13:07:25
调用带等号的方法的话
右代宫 真里亚 13:07:46
需要加 self ?
右代宫 真里亚  13:07:57
这个还真不知道
古明地 蓝  13:08:03
必须跟程序说清楚【这是方法】
否则程序会认为是局部变量
右代宫 真里亚13:08:25
= =
古明地 蓝13:08:24
因为带等号的方法通常都用作外部接口
死君(DK)13:08:27
囧死我 - -明白了,谢谢
右代宫 真里亚 13:08:31
C 里就没这个问题
古明地 蓝 13:08:34
所以大多数情况就不需要了
古明地 蓝  13:08:45
比如@window.x = XXX
古明地 蓝 13:08:52
这样程序能认出来是方法
古明地 蓝13:09:03
但是要是内部的话,除了直接对@x赋值之外
右代宫 真里亚 13:09:08
方法和变量时相同的名字了
古明地 蓝  13:09:08
就得用self.x = x

作者: 紫苏    时间: 2010-7-22 14:10
这个和解释器的实现有关,就快上完编译原理了,现炒现卖:

无论是解释器还是编译器,在解释、编译程序的时候都有两个相同的过程,第一个是词法分析,第二个是文法分析。两个过程都等同于把源文件遍历一次,前者是把源文件字元化,后者是解析字元,分析并检验语法,我们这个问题就和两者都有关。

字元化和解析都需要用到一个叫做确定性有限自动机的糟糕物(其英文缩写可能听过的人更多:DFA),和工程学里的有限状态自动机是一个概念,其作用有点像正则表达式,可以用有限的状态来组建一个字母串匹配模型。区别在于正则表达式仅仅是匹配字符串,其字母表是 ASCII 字符集,而确定性有限自动机可以表示任何字母,比如颜色的集合。自动机初始时是在一个“开始”状态,接着就开始逐字母读取,每获取一个字母,就根据“过渡”跳转到相应的状态。过渡是连接两个状态的桥梁,根据输入的字母的不同会有相应的过渡跳转到不同的状态。举个例子:可以设计这样一个自动机,开始状态为 S,接收到左圆括号 ( 字符则跳转到状态 A,在状态 A 时,输入任意字符都过渡这个状态本身,直到获取到一个右圆括号,才跳转到状态 B。如果我们把这个 “)” 所对应的状态设置为一个接受状态,那么这个简单的自动机实际上就是匹配了任意被圆括号包围的字符串,用相应的正则表达式表示就是 /\(.*\)/。

通过字元的有限状态自动机,我们可以用各种分隔符来表示一个字元的开始和结束,到最后,程序语言中的各种字元都会被按照在源件中出现的先后顺序串联起来。

这里就有一个问题:如何区分方法和局部变量。从正则语言的角度来讲,除了一些带特殊符号的方法名之外,方法名与局部变量名没有区别。显然字元的确定性有限自动机并不能有效地区分它们——在字元层上,这两者没有分别,所以需要把问题带到解析层上。

解析也有很多种方法,比较常见的是用 LR 解析器,进行从左到右的解析。在此之前,Ruby 必须要有一个严谨的语法定义:Part A:上下文无关文法;Part B:上下文有关文法。第一个部分是主要是一系列与上下文无关的生产规则,如 expr -> expr + expr 就是一个生产规则,意思是说一个表达式 A 的语法可以衍生为表达式 B + 表达式 C;第二个部分是与上下文有关语法,禁止使用未定义的变量、变量重声明都是上下文有关文法的一种。各种生产规则虽然变化多端,但却并非变化无穷,所以仍然可以被某种确定性有限自动机描述。

Ruby 首先遍历源文件,进行字元化,于是特殊符号和不带特殊符号的方法名或是变量名就分开了。我们姑且给除了关键字以外的所有以字母打头,以字母、数字或下划线结尾的字元取字元名: ID;称 “=” 这个符号为 BECOME;称 self 为 SELF,称小圆点 “.” 为 DOT。
在文法分析开始时,我们已经有了一个完整的字元列表。解释器随后会枚举列表中的字元,进行某种解析。

不难想到这里的存在的歧义:Ruby 方法名中可带 “=” 字元,是一个 ID 跟着一个 BECOME;而赋值语句,也是一个 ID 跟着一个 BECOME。

在这里 Ruby 必须只能做出一个抉择,那就是方法优先,还是变量名优先。再三考虑后,还是决定变量名优先,因为变量名可以统一使用 { ID } 跟着 { BECOME } 的形式来决定。具体的做法类似于:

如果前面没有 { SELF } 接着 { DOT } 的字元,那么当前如果输入了一个 ID 则处于状态 A,如果在状态 A,且下一个字元是 BECOME,那么 Ruby 会假设这是一个赋值语句,并跳转到相应的、独有的状态。所以 ID 表示的符号本身一定是一个局部变量,并把该符号列入符号表中,用某种方式提醒自己这个符号不是方法。

然而这里还有一另一个解析过程,就是 { SELF } 接着 { DOT }。如果出现这个组合,那么预先定义好的上下文无关语法的确定性有限自动机就会过渡到另一个状态 B。如果在状态 B,且下一个字元是 { ID },那么 Ruby 就会认为这是一个方法,并过渡到相应的、独有的状态。

一句话概括:self.XXXX= 和 XXXX= 是由在解释器定义的上下文无关文法所区分的,在其 DFA 中,它们分别处于两个不同的状态,所以相同的 XXXX 字元以及在这之后的字元也会有不同的意义。
作者: 灼眼的夏娜    时间: 2010-7-22 19:03
回复 DeathKing 的帖子


    是的 method=var 也会算成对变量赋值~  2.0缓慢进行中 目前大家在设计各种工具那些><




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1