Project1

标题: [讨论]RUBY中破坏性的方法有哪些? [打印本页]

作者: TERENCE    时间: 2009-5-29 04:56
标题: [讨论]RUBY中破坏性的方法有哪些?
●破坏性的方法(destructive methods)
此谓当还有其他变数参考到与接收者相同一个物件时,
用破坏性方法改变数时该变数也会改。

EX:(以pop阵列末端取出元素的操作为例)

p a = [1,2,3,4] #=> [1,2,3,4]
p b = a         #=> [1,2,3,4]
p b.pop         #=> 4
p b.pop         #=> 3
p b.pop         #=> 2
p b             #=> [1]
p a             #=> [1]

[LINE]1,#dddddd[/LINE]
popshift都有这个现象。

pop方法删除元素后,变数b被改变时,同时变数a也被改变了!
这是因为执行 a=b 时,并不是将a的内容复制给b,
事实上a和b代表同一个物件

所以使用破坏性的方法都要小心!

故此我想要问RUBY中破坏性的方法除了popshift外还有哪些? [LINE]1,#dddddd[/LINE]版务信息:本贴由楼主自主结贴~
作者: 紫苏    时间: 2009-5-29 05:43
这个是对象的引用,如果你直接把一个对象赋值给另一个对象,那么就是一个引用拷贝的过程,两个数组对象指向的是同一个地址,所以无论改变哪一个数组都会改变同一块内存~
可以利用对象的克隆机制让对象在内存中完全复制一份再把地址赋给引用变量,这样两个相同内容的对象就指向两块不同的独立的内存了
至于这种会改变本身的方法有很多,比如 String 的 gsub!、swapase!,Array 的 compact!、uniq! 等带感叹号的原地(in-place)算法的都会有这种现象~ [LINE]1,#dddddd[/LINE]版主对此帖的认可:『参与讨论的好孩子。』,积分『+300』。
作者: 虚幻死神    时间: 2009-5-29 05:46
弱弱的人.....

只是路过...

好久没来了~
作者: TERENCE    时间: 2009-5-29 06:00
以下引用紫苏于2009-5-28 21:43:56的发言:

这个是对象的引用,如果你直接把一个对象赋值给另一个对象,那么就是一个引用拷贝的过程,两个数组对象指向的是同一个地址,所以无论改变哪一个数组都会改变同一块内存~
可以利用对象的克隆机制让对象在内存中完全复制一份再把地址赋给引用变量,这样两个相同内容的对象就指向两块不同的独立的内存了
至于这种会改变本身的方法有很多,比如 String 的 gsub!、swapase!,Array 的 compact!、uniq! 等带感叹号的原地(in-place)算法的都会有这种现象~

也就是說
破坏性的方法  通常會加上「!」作為叮嚀??

另外如何克隆对象??
作者: TERENCE    时间: 2009-5-29 06:36
话说帖子被点亮悬赏图标?? 谢谢先~~~

但话说我没悬赏呢!
[LINE]1,#dddddd[/LINE]版主对此帖的评论:『3小时内请勿……嗯,前辈早安。』,积分『-50』。这些被扣积分的一半会用于对本帖正确答案的悬赏。
作者: 杨飞云    时间: 2009-5-29 07:41
提示: 作者被禁止或删除 内容自动屏蔽
作者: 后知后觉    时间: 2009-5-29 08:15
好吧!我算是明白clone是干嘛的了
以前看教程 柳柳说到这个clone就跳过去了没有详细解释

也明白为什么for循环的临时变量改变的属性会反映在实变量身上去
我一直就没搞懂这个问题来着,这下算是明白了{/cy}
作者: TERENCE    时间: 2009-5-29 08:30
以下引用杨飞云于2009-5-28 23:41:41的发言:
不过如果要克隆自己设计的类的对象,比如一个 Window 的子类包含了另外一个 Window 对象,需要去重载 clone 来实现深层次的克隆,也就是递归调用各个实例成员对象的 clone 方法,否则的话仅仅是拷贝了这个 Window 类对象本身,而没有拷贝它的成员变量的对象~

也就是说只能做到表层复制??

a = [[1,1],[2,2],[3,3]]
b = a.clone
a[0].push 9
p a #=> [[1,1,9],[2,2],[3,3]]

# b的元素也会被影响??
p b #=> [[1,1,9],[2,2],[3,3]]
[LINE]1,#dddddd[/LINE]
另问:
我刚刚在书上发现dup
而dup与clone近乎有相同功能

不同的是
dup只会复制内容,
而clone会连同特殊方法污染旗标(taint?)、冻结资讯(frozen?)一并复制

何谓
污染旗标(taint?)
冻结资讯(frozen?)

特殊方法又是因为什么才叫特殊方法??
作者: 紫苏    时间: 2009-5-29 13:23
dup只会复制内容,
而clone会连同特殊方法、污染旗标(taint?)、冻结资讯(frozen?)一并复制

你书上这样说的话其实有点问题 ^__^
dup 和 clone 都会拷贝对象的污染状态,但 dup 不会拷贝对象的冻结状态,这就是区别~[LINE]1,#dddddd[/LINE]
也就是说只能做到表层复制??

不是,只要去覆盖 Object 父类的 clone 方法,让浅层次克隆返回的对象的成员变量依次被克隆即可,而如果这个被克隆的成员内部还有成员,那么也应该再次被克隆(层层嵌套),这样就是深层次的克隆了,比如 Array 的深层次克隆:
class Array
  def clone
    obj = super
    for i in 0...obj.size
      begin
        obj = self.clone
      rescue TypeError
        next
      end
    end
    return obj
  end
end

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

上面的循环中会捕获到 TypeError 异常,因为 Fixnum 是不可克隆的,所以在枚举到 Fixnum 的时候就会跳过这个元素~不知道 Ruby 标准库中有没有提供判断对象本身是否可克隆的方法,Java 中就可以,所有可克隆的对象都实现了 Cloneable 接口……[LINE]1,#dddddd[/LINE]
何谓
污染旗标(taint?)

你的书中应该有讲到吧~我简单说一下 =)

对象污染的机制主要是为了保证程序运行的安全性~比如在脚本中调用了 eval 解释另一段脚本,而这段脚本却是来自外部的一段未知内容的脚本,这很明显是一个安全隐患。盲目地去执行这段脚本很可能会导致各种各样的问题,比如重要文件被篡改,密码被盗取等……{/fn}所以如果一个对象衍生于外部(即不在程序中),Ruby 会自动将其标记为“被污染的”,比如从文件、网路输入流中读取的字符串,操作系统环境变量等~

Ruby 对被污染对象的管理随着安全等级的不同而不同。所谓安全等级其实就是一个常量,保存在 $SAFE 中,当 $SAFE 是 0(默认)的时候不会检查被污染的对象,大于等于 1 的时候就会禁止污染对象在可能导致危险的操作中使用(至于更高的安全等级就查书吧,反正高于 1 就有可能会禁止使用被污染对象了),比如从文件读取了一段脚本保存到一个 String 对象中,然后传递给 eval,就会抛出一个 SecurityError 异常~

一个简单的例子:
$SAFE = 2

str = "damn"
str.taint

eval(str)  # Error!
执行到 eval 的时候抛出了一个安全异常,说调用 eval 不安全,这就是由于 str 是被污染的(当然抛出异常的过程是在 eval 内部进行的,会通过 tainted? 判断传递进来的参数是否被污染)[LINE]1,#dddddd[/LINE]
何谓
冻结资讯(frozen?)

这个很简单,就是冻结一个对象,让它无法被修改了~{/cy}要注意它冻结的是对象本身,而不是一个引用变量 =)
arr = [1, 2, 3, 4]
arr.freeze
arr[1] = 3 # Error!
尝试改变数组元素的值的时候发生了 TypeError 异常……[LINE]1,#dddddd[/LINE]
而特殊方法又是因为什么才叫特殊方法??

这个……还真不知道什么特殊方法不会被 dup 复制{/hx}
刚才试了下,跟访问权限没关系诶 [LINE]1,#dddddd[/LINE]版主对此帖的认可:『参与讨论的好孩子。』,积分『+300』。
作者: 精灵使者    时间: 2009-5-29 15:09
已经冻结的变量和常量(恒量)的管理方法应该是一样的吧。
怎样解除已经冻结的变量?
其实这个破坏的方法是有用处的,例如我经常要用到。
只需要修改一个修改区的变量就可以更改其他的数据区和功能区的变量,而不用繁琐的反复引用。
关于污染旗标,在RM里面最明显的就是用一些脚本来进行解密——如果能直接提升RM脚本中污染旗标的等级其实是最好的一种反解密的方法。
作者: 霜冻之狼    时间: 2009-5-29 15:27
以下引用紫苏于2009-5-29 5:23:33的发言:
这个很简单,就是冻结一个对象,让它无法被修改了~要注意它冻结的是对象本身,而不是一个引用变量 =)

你说得很对.
但是....与其冻结他,对它不使用操作命令不是更好吗?

作者: 紫苏    时间: 2009-5-29 15:43
以下引用精灵使者于2009-5-29 7:09:22的发言:

已经冻结的变量和常量(恒量)的管理方法应该是一样的吧。
怎样解除已经冻结的变量?

对象本身一旦冻结,不可解除……{/ll}
不过可以调用 dup 方法来返回一个没有冻结的克隆对象~

以下引用霜冻之狼于2009-5-29 7:27:23的发言:

但是....与其冻结他,对它不使用操作命令不是更好吗?

在规模比较大的代码编写中,有一部分数据是你不想改动的,但你又怕在调试过程中不小心改动到了,这时就可以把对象冻结……其实也就是让它变成常量了

这个机制可能也就是在保护数组内容的时候用得比较多,数字啊、true/false/nil 啊那些对象由于本身是单一实例的,所以本身是不可能被修改的,冻结它们也就没有意义了
作者: 灼眼的夏娜    时间: 2009-5-29 16:39
以下引用紫苏于2009-5-29 5:23:33的发言:


而特殊方法又是因为什么才叫特殊方法??

这个……还真不知道什么特殊方法不会被 dup 复制
刚才试了下,跟访问权限没关系诶


[本贴由作者于 2009-5-29 6:14:18 最后编辑]

class A
end
class << a = A.new
  def func1
    :func1
  end
end
b = a.dup
a.func1 # ok
b.func1 # undefined method `func1'
c = a.clone
c.func1 # ok


作者: 紫苏    时间: 2009-5-29 16:51
以下引用灼眼的夏娜于2009-5-29 8:39:30的发言:

class A
end
class << a = A.new
def func1
   :func1
end
end
b = a.dup
a.func1 # ok
b.func1 # undefined method `func1'
c = a.clone
c.func1 # ok

果然神就是神啊{/cy},受教了,原来特殊方法就是单例方法~
这样写应该是一样的吧:
class A
end

a = A.new

def a.fn
end

b = a.dup
c = a.clone

a.fn # OK
b.fn # Error!
c.fn # OK

作者: 灼眼的夏娜    时间: 2009-5-29 16:54
一样的  - -神么{/gg} 呃呃。。= =

话说紫苏的程序学的挺好的><
作者: 霜冻之狼    时间: 2009-5-29 17:01
以下引用灼眼的夏娜于2009-5-29 8:54:02的发言:
一样的  - -神么 呃呃。。= =
话说紫苏的程序学的挺好的><

好了好了,你们两个就别那么客气了...都是自己人...

作者: 精灵使者    时间: 2009-5-29 18:08
如此看来,那个只能输入一次且不可修改的东西就是这样设计的吧。
修改保存的数据会将其冻结……使其不能再进行修改操作。
作者: TERENCE    时间: 2009-5-29 18:55
以下引用紫苏于2009-5-29 5:23:33的发言:
你书上这样说的话其实有点问题 ^__^
dup 和 clone 都会拷贝对象的污染状态,但 dup 不会拷贝对象的冻结状态,这就是区别~

原来书上笔误了!~~赶紧更正


多谢紫苏的教导,虽然有些地方还是有点不清楚 ←这是我的问题

[LINE]1,#dddddd[/LINE]
关於特殊方法
灼眼的夏娜跟紫苏写的是相同的东西吧??

不过我似乎看不太懂单例方法
紫苏写的或许还能懂一些些
但灼眼的夏娜写的....
class << a = A.new
我看不懂了  @_@

P.S.
一个帖子才问了一个问题 我却问了一堆= =
对打那麼多字的紫苏有点不好意思了。


一个问题我竟然衍伸出那麼多个问题,
看来我的RUBY功力还不深厚啊啊啊.........

作者: 霜冻之狼    时间: 2009-5-29 19:18
以下引用TERENCE于2009-5-29 10:55:30的发言:
一个问题我竟然衍伸出那麼多个问题,
看来我的RUBY功力还不深厚啊啊啊.........

课堂是最不需要担心犯错的地方,敢于发问本身就证明你有进步...

作者: 紫苏    时间: 2009-5-29 19:51
龙兄客气了,多打点字对我也有好处~{/hx}

单例方法就是只属于单个对象实例的方法,这是 Ruby 的特性
比如,张三、李四都是“人”类的对象,我们可以专门给张三其人定义一个只属于他的方法“抽烟”,而这个“抽烟”的方法并没有在“人”类中定义,这样全天下的“人”类就只有张三这个人会抽烟了:
class Person
   def initialize(name)
     @name = name
     @health = 100
   end
   def say_hello
     print "你好,我的名字是#@name,请多指教!"
   end
end

zhangsan = Person.new("张三")
lisi = Person.new("李四")

def zhangsan.smoke
   @health -= 1
end

zhangsan.say_hello  # OK
lisi.say_hello      # OK
zhangsan.smoke      # OK
lisi.smoke          # Error! 此人不会抽烟……

俺那种写法和夏娜的那种写法都是让 a 这个对象的直属类变为了一个匿名单例类(没有类名,且实例只有一个,就是 a),而 a 原来的直属类 A 就成了这个匿名类的父类……
class << a = A.new 这一句可能这样写更简单易懂些:
a = A.new
class << a

a = A.new 会先执行,赋值结束后它的值就是 a 本身,class << a 就会专门为 a 这个实例建立一个匿名类~
这两种方式的区别在于一个是明确地去建立一个匿名类,并在类中定义单例方法;另一种则是直接用 def obj.method 的方式隐式地建立了匿名类 [LINE]1,#dddddd[/LINE]系统信息:本贴由楼主认可为正确答案,66RPG感谢您的热情解答~
作者: TERENCE    时间: 2009-5-29 20:47
感谢紫苏de用心教导
帖子的125分给你了

作者: 玄月    时间: 2009-5-30 20:46
超出我认知的讨论…………
好,暑假努力学C++
作者: hitlerson    时间: 2009-6-4 20:07
好久没来提问区了竟出现如此牛贴

强贴留名以哄抬身价
作者: 蓝の星辰    时间: 2009-6-6 03:28
提示: 作者被禁止或删除 内容自动屏蔽
作者: 玄月    时间: 2009-6-6 04:53
以下引用蓝の星辰于2009-6-5 19:28:05的发言:


以下引用hitlerson于2009-6-4 12:07:57的发言:

好久没来提问区了竟出现如此牛贴

强贴留名以哄抬身价



同,不知紫苏是那位同学的马甲

高手就等于马甲么 - - 唉,扭曲了扭曲了。
作者: tommay    时间: 2009-6-6 04:56
同LS。
话说紫苏大注册也有一段日子了,有程序基础的人在这段时间内完全可以成为高手。
作者: 后知后觉    时间: 2009-6-6 05:02
以下引用精灵使者于2009-5-29 7:09:22的发言:

已经冻结的变量和常量(恒量)的管理方法应该是一样的吧。
怎样解除已经冻结的变量?
其实这个破坏的方法是有用处的,例如我经常要用到。
只需要修改一个修改区的变量就可以更改其他的数据区和功能区的变量,而不用繁琐的反复引用。
关于污染旗标,在RM里面最明显的就是用一些脚本来进行解密——如果能直接提升RM脚本中污染旗标的等级其实是最好的一种反解密的方法。

$SAFE
这个东西吗?

他们那一直引用看得我头晕- -!

作者: 紫苏    时间: 2009-6-6 12:03
高手实在不敢当~
我用 RM 的时间可能比本帖的所有人都长,所以多知道点不足为奇,大家要是继续学习的话迟早能对这类看似高深的问题了然于胸的~
作者: 精灵使者    时间: 2009-6-6 16:42
我不知道RM的污染旗标的值是在什么地方的。
如果提升的话可以预防解密,但是可能会对事件执行脚本造成不良影响
作者: hitlerson    时间: 2009-6-6 19:49
我用 RM 的时间可能比本帖的所有人都长,所以多知道点不足为奇

终于明白 紫苏 原来是转世灵童
作者: 灼眼的夏娜    时间: 2009-6-6 20:42
以下引用精灵使者于2009-6-6 8:42:59的发言:

我不知道RM的污染旗标的值是在什么地方的。
如果提升的话可以预防解密,但是可能会对事件执行脚本造成不良影响

ruby的$safe仅仅是限制某些方法的执行而已  对现在的解密是无能为力的呢 咳咳。。
作者: 后知后觉    时间: 2009-6-12 08:00
那个单例方法以前我问模块的时候紫苏有给我说过

这帖子也解决了我好些问题{/hx}




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