Ruby 使用[]。替换创建阵列的副本
我有一个类,在这个类中,我对一个实例变量使用了Ruby 使用[]。替换创建阵列的副本,ruby,Ruby,我有一个类,在这个类中,我对一个实例变量使用了Array#shiftinstance方法。我以为我复制了我的实例变量,但事实上我没有,而且shift实际上正在更改实例变量 例如,在此之前,我希望两次都能获得[“foo”、“bar”、“baz”],前提是: class Foo attr_reader :arr def initialize arr @arr = arr end def some_method foo = arr foo.shift en
Array#shift
instance方法。我以为我复制了我的实例变量,但事实上我没有,而且shift
实际上正在更改实例变量
例如,在此之前,我希望两次都能获得[“foo”、“bar”、“baz”]
,前提是:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["bar", "baz"]
结果:
["foo", "bar", "baz"]
["bar", "baz"]
但如图所示,我的“副本”根本不是真正的副本。现在,我不确定我是否应该调用我想要的“复制”、“克隆”、“复制”、“深度克隆”、“深度复制”、“冻结克隆”等等
我真的很困惑该搜索什么,发现了一大堆疯狂的尝试,好像在“复制数组”
然后我发现有一句话解决了我的问题:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = [].replace arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["foo", "bar", "baz"]
输出:
["foo", "bar", "baz"]
["foo", "bar", "baz"]
我知道Array#replace
是对恰好是空数组的Array
实例调用的一个实例方法(例如foo=[“cats”,“and”,“dogs”]。replace arr
仍然有效),而且我获得实例变量@arr
的“副本”是有意义的
但这与:
foo = arr
foo = arr.clone
foo = arr.dup
foo = arr.deep_clone
Marshal.load # something something
# etc...
或者我在上面看到的
dup
和map
和inject
的任何其他疯狂组合?这是ruby中易变性的棘手概念。对于核心对象,通常会出现数组和散列。字符串也是可变的,但这可以通过脚本顶部的标志禁用。看
在这种情况下,您可以轻松调用dup
,deep\u dup
,clone
,其效果与replace
相同:
['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])
就差异而言,dup
和clone
是相同的,除了一些细微的细节-请参阅
这些与deep_-dup
之间的区别在于deep_-dup
是递归工作的。例如,如果复制嵌套数组,则不会克隆内部数组:
a = [[1]]
b = a.clone
b[0][0] = 2
a # => [[2]]
哈希也会发生同样的情况
Marshal.load Marshal::dump
是深度克隆对象的一般方法,与deep\u dup
不同,它位于ruby核心中Marshal::dump
返回一个字符串,以便将对象序列化到文件中
如果您想避免像这样的意外错误,请记住哪些方法有副作用,并且只在有意义时调用这些方法。方法名称末尾的解释点表示它有副作用,但其他包括取消移动、推送、压缩、删除和弹出。功能编程的很大一部分是避免副作用。您可以看到这是ruby中易变性的棘手概念。对于核心对象,通常会出现数组和散列。字符串也是可变的,但这可以通过脚本顶部的标志禁用。看 在这种情况下,您可以轻松调用
dup
,deep\u dup
,clone
,其效果与replace
相同:
['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])
就差异而言,dup
和clone
是相同的,除了一些细微的细节-请参阅
这些与deep_-dup
之间的区别在于deep_-dup
是递归工作的。例如,如果复制嵌套数组,则不会克隆内部数组:
a = [[1]]
b = a.clone
b[0][0] = 2
a # => [[2]]
哈希也会发生同样的情况
Marshal.load Marshal::dump
是深度克隆对象的一般方法,与deep\u dup
不同,它位于ruby核心中Marshal::dump
返回一个字符串,以便将对象序列化到文件中
如果您想避免像这样的意外错误,请记住哪些方法有副作用,并且只在有意义时调用这些方法。方法名称末尾的解释点表示它有副作用,但其他包括取消移动、推送、压缩、删除和弹出。功能编程的很大一部分是避免副作用。您可以看到首选方法是
dup
- 需要复制阵列时,请使用
array.dup
- 需要复制二维数组时,请使用
array.map(&:dup)
除非您真的想深度复制整个对象图,否则不要使用编组技巧。通常您只想复制数组,而不想复制包含的元素。首选方法是
dup
- 需要复制阵列时,请使用
array.dup
- 需要复制二维数组时,请使用
array.map(&:dup)
除非您真的想深度复制整个对象图,否则不要使用编组技巧。通常您只想复制数组,而不想复制包含的元素。这些方法之间的许多区别在于新数组中的对象是原始对象的副本,还是两个数组都指向相同的对象。需要注意的一点是:在ruby中赋值变量不会复制它,它只是创建一个指向该值的指针。因此,如果
arr=[1,3,4]
并指定x=arr
,您只为原始数组创建了另一个“名称”。这些方法之间的许多区别在于,新数组中的对象是原始对象的副本,还是两个数组都指向相同的对象。需要注意的是:在ruby中分配变量不会复制它,它只会创建一个指向该值的指针。因此,如果arr=[1,3,4]
并分配x=arr
,则只为原始数组创建了另一个“名称”。+1。还要注意的是,关注所讨论的类如何实现这些方法是明智的。正如上面所说,“一般来说,clone
和dup
在后代类中可能有不同的语义。”我不认为数组或散列与对象的文档有什么不同,但ActiveRecord记录可以,例如。感谢您的响应