Project1
标题: 今天被ruby摆了一道……查了一天的bug [打印本页]
作者: 雪在燃 时间: 2016-9-6 17:02
标题: 今天被ruby摆了一道……查了一天的bug c#转型rgss3的新人脚本君
今天正在愉快的阅读代码之中,偶然看到这样一句代码
def create_contents
contents.dispose
if contents_width > 0 && contents_height > 0
self.contents = Bitmap.new(contents_width, contents_height)
else
self.contents = Bitmap.new(1, 1)
end
end 复制代码
哦简单,这里的contents就是引用父类的属性吧,省略了self而已
所以我加了self,果然如我所料,没有任何问题
所以这里的self.contents到底为什么不简化一下呢,所以我改成了contents = Bitmap.new(contents_width, contents_height)
开始报错了……
于是我搜索,self和this的区别(我怀疑self比this有不同的用法,因为在这里self如果和this用法一样,且可以省略的话,这样的修改应该没有问题的)
查了无数代码,p了多少次地址,我都确定 p self.contents 和p contents是一个东西了……
最后,我灵感来了!
contents = Bitmap.new(contents_width, contents_height)
p contents
p self.contents 复制代码
新思路的检测代码
果然……
我去,这里的contents是被声明为了临时变量,所以才会报bug
一下午的光阴就在这坑爹的bug中度过了……
作者: 喵呜喵5 时间: 2016-9-6 18:07
def a
2
end
def b
p a
a = 3
p a
end
b
b
作者: 雪在燃 时间: 2016-9-6 18:15
我的天,你想让我疯掉吗
为什么会这样……
等等,又是声明了个临时变量
我差点又歪到可以修改方法上了
一瞬间的心理历程↑
作者: RyanBern 时间: 2016-9-6 19:56
本帖最后由 RyanBern 于 2016-9-7 09:00 编辑
从别的面向对象语言转过来 Ruby 学起来是有点别扭的。建议的做法是少类比,忘掉从前学过的东西,直接从 Ruby 入手。
Ruby 中,'.'后面出现的一般都是方法,很少有“属性”这个说法。这个和 C# 专门引入了 Property 是不太一样的。另外,C# 的 this 和 Ruby 的 self 差的还是有点远。具体的我也不清楚,可以询问@taroxd 来解释。
楼主的代码中不能认为 self.contents 和 contents 相同,也不能认为 self.contents = 和 contents = 相同。
self.contents 和 self.contents= 这两个都是在调用方法,虽然看起来和 C# 中的 Property 极为类似,但是本质上有很大不同。
当你在这里写下 contents 时,Ruby 解释器会先找一下有没有临时变量叫 `contents',如果找不到,则找有没有该类的方法叫 `contents',如果还找不到则报错。
当你在这里写下 contents= 时,这句话实际是在赋值,而写下 self.contents= 时,这句话是在调用本类的 `contents=' 方法,所以效果是截然不同的。
另外,我对此表示疑问:
public int X{ get; set; }
public void test( ) { X = 5 ; }
public int X{ get; set; }
public void test( ) { X = 5 ; }
这样真的合法吗?当使用 C# 的 Property 时,this 真的能省略吗?
有点忘了 C# 了,试了一下应该是可以的。
作者: 寒冷魔王 时间: 2016-9-6 21:38
本帖最后由 寒冷魔王 于 2016-9-6 21:39 编辑
原先给Chd114神查过一个离奇Bug(见下面的func2)
class A
def initialize
@x = 0
end
def x=( e)
@x = e
end
def x
@x
end
# 注:attr_accessor :x 同理
def func0
self .x = 5
end
def func1
x = 5
end
def func2
p x
if false
x = 5
end
p x
end
end
puts ( "--0--" )
a0 = A.new
a0.func0
p a0.x
puts ( "--1--" )
a1 = A.new
a1.func1
p a1.x
puts ( "--2--" )
a2 = A.new
a2.func2
class A
def initialize
@x = 0
end
def x=( e)
@x = e
end
def x
@x
end
# 注:attr_accessor :x 同理
def func0
self .x = 5
end
def func1
x = 5
end
def func2
p x
if false
x = 5
end
p x
end
end
puts ( "--0--" )
a0 = A.new
a0.func0
p a0.x
puts ( "--1--" )
a1 = A.new
a1.func1
p a1.x
puts ( "--2--" )
a2 = A.new
a2.func2
Ruby语言十分灵活,有很多匪夷所思的陷阱。很多时候需要通过限制灵活性来减少Bug。比如在类内使用self.调用属性方法(如x, x=)。
另外,像这种名称遮掩在其他语言中也很常见吧,比如
class A
{
public :
void setX( int x) {
this->x = x; // 这种赋值的方法如果要同名的话一般加this。
}
private :
int x;
} ;
class A
{
public :
void setX( int x) {
this->x = x; // 这种赋值的方法如果要同名的话一般加this。
}
private :
int x;
} ;
作者: 雪在燃 时间: 2016-9-6 21:53
c#中这样当然可以直接使用 X除非声明了另一个X
问题是c#使用临时变量肯定要显示声明
主要是我想当然的认为了
不过是因为之前用了contents直接用了,然后我试了试,发现可以直接使用父类属性(当然所有语言都可以)
我就很疑惑下面的contents为什么要单独添加self.
作者: 喵呜喵5 时间: 2016-9-6 22:31
实际上,这些并不是陷阱,
我一直认为写ruby代码唯一需要保证的是:不要让ruby去猜你想做什么
只要保证这一点,很多东西根本不会匪夷所思而是非常符合直觉
例如这里的赋值,因为ruby调用方法不需要括号,所以ruby没法区分你执行 a= 是要调用方法还是创建临时变量,这时,加一个 self 显式消除这种含糊不清的命令就是义务,而如果你的命令不会有任何歧义,那么,省略不必要的修饰词则能让代码变得优雅
作者: taroxd 时间: 2016-9-7 09:26
本帖最后由 taroxd 于 2016-9-7 09:35 编辑
调用方法时(self.x = 这种的除外)不需要加 self,也不建议加。
1. 加了 self 就无法调用 private 方法。(同样 self.x = 这是个例外)
2. 保持这个习惯的话,只要出现了 self.xxx 这样显式写出 self 的方法调用,都可以检查一下代码哪里不规范。(默认脚本中主要是 self.def 和 self.class 这种撞关键字的,还有可以省略 self 但没省略的。self.def 可以理解成为了让技能公式更自然,那个 self.class 我实在无法理解为什么要这么做,又撞关键字而且还和 Kernel 里的方法同名……)
正确的做法是:不要用和方法同名的局部变量,除非两者表达完全相同的意思(此时不会造成混淆)。
# Good
class Game_BattlerBase
def hp=( hp)
@hp = hp
# 如果这里有东西要访问 hp,那么无论 hp 表示 self.hp 还是局部变量 hp,得到的结果都是一样的。
refresh
end
end
# Bad。参数名就不能命名为 new_exp 或者 value 之类的吗。
class Game_Actor
def change_exp( exp, show)
@exp [ @class_id] = [ exp, 0 ] .max
last_level = @level
last_skills = skills
# 注意下面两行都使用了 self.exp。不熟悉 ruby 的话是不是很容易掉坑里
level_up while !max_level? && self .exp >= next_level_exp
level_down while self .exp < current_level_exp
display_level_up( skills - last_skills) if show && @level > last_level
refresh
end
end
# Good
class Game_BattlerBase
def hp=( hp)
@hp = hp
# 如果这里有东西要访问 hp,那么无论 hp 表示 self.hp 还是局部变量 hp,得到的结果都是一样的。
refresh
end
end
# Bad。参数名就不能命名为 new_exp 或者 value 之类的吗。
class Game_Actor
def change_exp( exp, show)
@exp [ @class_id] = [ exp, 0 ] .max
last_level = @level
last_skills = skills
# 注意下面两行都使用了 self.exp。不熟悉 ruby 的话是不是很容易掉坑里
level_up while !max_level? && self .exp >= next_level_exp
level_down while self .exp < current_level_exp
display_level_up( skills - last_skills) if show && @level > last_level
refresh
end
end
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1