是否有方法可以判断对象是否可变,类似于以下mutable?
?如果没有,实施它的最佳方法是什么?
"abcde".mutable? # => true
0.mutable? # => false
要回答mu太短而dbenhur的问题,我不喜欢enumerated.inject(initial){...}
或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"
因此,检测接收器是否可变是必要的。它是否冻结无关紧要。如果我使用冻结对象的方法的破坏性版本,它只会引发错误。没错。
答案 0 :(得分:2)
AFAIK所有(解冻)对象都是可变的,除了nil,true,false以及所有整数和符号。
答案 1 :(得分: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
。
修改强>
如下面的评论0.frozen?
中提到的检查将正确返回false
,因为0是Fixnum
类的实例。
答案 2 :(得分:1)
有两个属性可以使对象在ruby中不可变
1)对象可能会被Object#freeze
冻结,在这种情况下,您的不变性检查为Object#frozen?
2)对象可以是immediate value。我知道没有内置的方法告诉对象是直接的,所以必须依赖于直接性质的副作用。立即值不允许在其上定义单例类,因此我可以尝试以下作为代理:
class Object
def immediate_value?
class <<self; end
return false
rescue TypeError
return true
end
def mutable?
!(frozen? || immediate_value?)
end
end
虽然这可能是一个非常可靠的探测器(我不知道另一种阻止打开对象的单例类的机制),但它确实会产生令人遗憾的副作用,即为每个被查询的对象创建一个单例类。
答案 3 :(得分:-2)
我想出了这个
class Object
def mutable?; !!(dup rescue false) end
end