Project1

标题: 求 深层 clone [打印本页]

作者: zh99998    时间: 2009-8-18 11:42
标题: 求 深层 clone
clone
dup
生成某对象的拷贝并返回它.

clone生成的是完整的拷贝,它包括freeze、taint和特殊方法等信息; 而dup则只拷贝对象的内容.

请注意,clone 和 dup 生成的都是"浅层(shallow)"拷贝.它们只拷贝对象本身,而不会拷贝对象的所指(例如数组的元素等).

另外,如果对拷贝进行如下测试的话

obj.equal?(obj.clone)

通常都不成立.但是

obj == obj.clone

通常都会成立.

若想对true, false, nil, Symbol对象等进行拷贝时,会引发TypeError异常.

ruby 1.7 特性: 在1.7版本中,若想对Numeric对象等immutable(内容不可改变)的对象进行拷贝时,会引发TypeError.

于是求深层clone[line]1[/line]Marshal.dump和save_data似乎能实现深层dump,这是怎么做到的
作者: 紫苏    时间: 2009-8-18 13:29
刚才去翻 TERENCE 关于对象克隆的提问贴,发现回档消失了……

于是送上备份的传送门:
http://szsu.spaces.live.com/blog/cns!D57D0E50BE1820CF!170.entry
作者: chaochao    时间: 2009-8-18 14:31
于是求深层clone

先Marshal.dump了,再读出来吧...
偷懒了...别打我啊= =
作者: zh99998    时间: 2009-8-18 14:35
有些对象是不能dump的
Marshal.dump(obj[,port][,limit])
把obj递归地写入文件. 若对那些不能被写入文件的对象使用该函数时, 会引发TypeError异常. 下列对象就不能被写入文件.

无名的Class/Module对象. (此时,将引发ArgumentError异常. 请参考Module.new来了解无名类的情况.)
其状态受到系统保护的那些对象. 具体说来就是以下实例. 例如Dir, File::Stat, IO及其子类File, Socket等.
MatchData, Data, Method, UnboundMethod,Proc, Thread, ThreadGroup, Continuation的实例.
定义了特殊方法的对象

作者: chaochao    时间: 2009-8-18 14:37
应该可以用重写方法的办法吧= =
ruby里应该有反射吧,有这个重写起来就方便多了.
菜鸟路过.:$
作者: chaochao    时间: 2009-8-18 14:40
还有一个办法,写一个方法,利用反射,来取得object的结构,然后递归复制.....
作者: zh99998    时间: 2009-8-18 14:41
不是,只要去覆盖 Object 父类的 clone 方法,让浅层次克隆返回的对象的成员变量依次被克隆即可,而如果这个被克隆的成员内部还有成员,那么也应该再次被克隆(层层嵌套),这样就是深层次的克隆了,比如 Array 的深层次克隆:
  1. class Array
  2.   def clone
  3.     obj = super
  4.     for i in 0...obj.size
  5.       begin
  6.         obj[i] = self[i].clone
  7.       rescue TypeError
  8.         next
  9.       end
  10.     end
  11.     return obj
  12.   end
  13. end
复制代码
a = [[[1], 2], [3, 4]]
b = a.clone
b[0][0][0] = 32767
p a[0][0][0] # <-- 1

让一个引用变量 obj 来保存最终克隆后的对象,先调用 super 获取 Object 类提供的浅层次克隆后的本对象(是一个数组),然后枚举它的每一个元素,克隆这个元素并保存到原地,如果这个元素是一个数组,那么调用这个元素的 clone 方法就会再次重复同样的步骤,否则的话则按照原来的方式去克隆其它类型的对象~

以上引自紫苏大人给出的讨论页

这个的意思也就是说,如果要实现深层clone.那么就必须针对每个类都进行修改吗
作者: 紫苏    时间: 2009-8-18 15:43
本帖最后由 紫苏 于 2009-8-18 15:57 编辑

Array 等 Ruby 的底层类比较特殊,因为是 C 写的,所以无法去获取这个类中的成员变量,像 Array 就只能通过 [] 方法来克隆它的元素,所以需要单独去写它的深层 clone 方法;RGSS 中的那些 Object 的徒子徒孙的话,去重写一下 Object 的 clone 就行了;至于 Sprite 啊,Tone 之类的,其内部已经覆盖了父类的 clone,就不用管了
  1. =begin

  2. class Object
  3.   alias _original_clone_ clone
  4.   def clone
  5.     obj = _original_clone_
  6.     for i in obj.instance_variables
  7.       begin
  8.         obj.instance_eval("i = i.clone")
  9.       rescue TypeError
  10.         next
  11.       end
  12.     end
  13.     return obj
  14.   end
  15. end

  16. =begin
  17. =end

  18. class A
  19.   attr_accessor :a
  20.   def initialize
  21.     @a = [1, 2, 3]
  22.   end
  23. end

  24. a = A.new
  25. b = a.clone
  26. b.a[0] = 99999
  27. p b.a, a.a
复制代码

作者: zh99998    时间: 2009-8-18 15:48
Array 等 Ruby 的底层类比较特殊,因为是 C 写的,所以无法去获取这个类中的成员变量,像 Array 就只能通过 [] 方法来克隆它的元素,所以需要单独去写它的深层 clone 方法
像这样的必须重写的类有哪些?
Hash,Module,Class,Struct?Thread?
作者: IamI    时间: 2009-8-18 15:50
本帖最后由 IamI 于 2009-8-18 15:51 编辑

轻声告诉紫苏……懒人zh想要深层clone的是顶级自调main或者是class类的实例
(顶级自调只有在VX中有……)

顺便,把内建类下来还不够吗?to zh
作者: zh99998    时间: 2009-8-18 15:52
不够啦,如果某个脚本很XE的修改了一些内建的东西,而又没被clone的话,会崩掉的

另外,除了这次的防F12后栈过深之外,我也有别的几个脚本需要获取到一个对象里包含的所有对象的
作者: 紫苏    时间: 2009-8-18 17:16
像这样的必须重写的类有哪些?
Hash,Module,Class,Struct?Thread?
zh99998 发表于 2009-8-18 15:48

Hash 需要;
Module 应该不用了,毕竟其内部也覆盖了父类的 clone,不过没有测试过;
Class 是 Module 的子类,Module 怎样 Class 就怎样;
Struct 不清楚;
Thread 不可克隆
[line]1[/line]
话说如果你们是要解决 F12 的问题的话,刚才我倒是发现了一个方法——
在所有脚本页前面插入:
  1. $__jmp__.call if $__jmp__
复制代码
在 Main 之前,所有其它脚本之后插入:
  1. callcc { |$__jmp__| }
复制代码
这样使得 F12 之后跳过了前面的类定义,而直接执行 Main
作者: zh99998    时间: 2009-8-18 17:26
Module 应该不用了,毕竟其内部也覆盖了父类的 clone,不过没有测试过;
Class 是 Module 的子类,Module 怎样 Class 就怎样;

这些里面是可能有常量、类变量啥的[line]1[/line]然后那个F12很棒呀,紫苏大人开帖发布吧,可能很多人需要呢
作者: 后知后觉    时间: 2009-8-18 20:32
本帖最后由 后知后觉 于 2009-8-18 20:34 编辑

今天来VX区捡到宝贝了
作者: zh99998    时间: 2009-8-19 07:36
zh99998  7:03:33
关于全局变量的错误,我找到例子了
zh99998  7:05:41
比如我拿一个全局变量来记录已经生成的window以便于统一管理,这个变量的初始化写在了类定义的外面(写在外面就省得判断是否初始化过什么的),F12之后,由于这个变量没有被清空,所以程序试图访问那些Window的时候就会RGSSError
作者: 神思    时间: 2009-8-24 22:16
F12..
我记得是抛出Reset异常来着= =||||||
可以抓的到的 。。。。。。




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