1

是否有一种方法可以判断对象是否可变,类似于mutable?以下内容?如果没有,实现它的最佳方法是什么?

"abcde".mutable? # => true
0.mutable? # => false

回答 mu 太短和 dbenhur 的问题,我不喜欢enumerated.inject(initial){...}or的语法enumerated.each_with_object(initial){...}。我想要一个反转接收器和参数的方法,并且我希望它可用于各种各样的类;所以我有:

initial.my_new_method(enumerated){...}

0.my_new_method(1..10){|sum, i| sum + i} # => 55
"a".my_new_method(b: 3, c: 4){|s, (k, v)| s + k.to_s * v} # => "abbbcccc"

这将使返回成为接收器的修改版本,并且在概念上更自然。并且my_new_method,我希望它是非破坏性的。当接收器可变时,我还想定义一个破坏性版本

initial.my_new_method!(enumerated){...}

"a".my_new_method!(b: 3, c: 4){|s, (k, v)| s << k.to_s * v} # => "abbbcccc"

所以检测receiver是否可变是很有必要的。如果它被冷冻也没关系。如果我对冻结的对象使用该方法的破坏性版本,它只会引发错误。没有错。

4

4 回答 4

2

AFAIK 所有(未冻结的)对象都是可变的,除了 nil、true、false 和所有整数和符号。

于 2012-10-11T23:05:10.443 回答
1

有两个属性可以使对象在 ruby​​ 中不可变

1)对象可能会被冻结Object#freeze,在这种情况下,您的不变性检查是Object#frozen?

2) 对象可以是立即数。我知道没有内置方法可以告诉对象是即时的,因此必须依赖即时性质的副作用。不允许立即值在其上定义单例类,因此我可以尝试以下作为代理:

class Object
  def immediate_value?
    class <<self; end
    return false
  rescue TypeError
    return true
  end

  def mutable?
    !(frozen? || immediate_value?)
  end
end

虽然这可能是一个非常可靠的检测器(我不知道有另一种机制可以阻止打开对象的单例类),但它确实具有为每个查询的对象创建一个单例类的不幸副作用。

于 2012-10-12T05:35:33.050 回答
1

您可以调用.frozen?一个对象来查看该对象的实例是否是不可变的:

1.9.3p194 :001 > a = Array.new
 => [] 
1.9.3p194 :002 > a.frozen?
 => false 
1.9.3p194 :003 > a.freeze
 => [] 
1.9.3p194 :004 > a.frozen?
 => true 

在调用.freeze该对象实例后,将不允许其他更改,RuntimeError如果有人试图更改冻结的对象,则会抛出 a。

编辑:

正如评论中下面提到的检查0.frozen?将正确返回false,因为 0 是Fixnum该类的一个实例。

于 2012-10-11T22:37:45.803 回答
-2

我想出了这个

class Object
  def mutable?; !!(dup rescue false) end
end
于 2012-10-11T23:33:48.693 回答