使用 [].replace 复制数组 [英] Use [].replace to make a copy of an array

查看:42
本文介绍了使用 [].replace 复制数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,我在一个实例变量上使用了 Array#shift 实例方法.我以为我制作了我的实例变量的副本",但实际上我没有,shift 实际上是在更改实例变量.

I have a class where I was using the Array#shift instance method on an instance variable. I thought I made a "copy" of my instance variable but in fact I hadn't and shift was actually changing the instance variables.

例如,在我期望得到 ["foo", "bar", "baz"] 之前,给定以下内容:

For example, before I would have expected to get ["foo", "bar", "baz"] both times given the following:

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"]

但如图所示,我的副本"根本不是真正的副本.现在,我不确定是否应该将我想要的称为副本"、克隆"、复制"、深度克隆"、深度复制"、冷冻克隆"等......

But as shown my "copy" wasn't really a copy at all. Now, I'm not sure if I should be calling what I want a "copy", "clone", "dup", "deep clone", "deep dup", "frozen clone", etc...

我真的很困惑要搜索什么,并发现了一堆疯狂的尝试来做看起来像制作数组副本"的事情.

I was really confused about what to search for and found a bunch of crazy attempts to do what seems like "making a copy of an array".

然后我找到了另一个答案,其中一行字解决了我的问题:

Then I found another answer with literally one line that solved my problem:

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 的副本"是有道理的.

I understand that Array#replace is an instance method being called on an instance of Array that happens to be an empty array (so for example foo = ["cats", "and", "dogs"].replace arr will still work) and it makes sense that I get a "copy" of the instance variable @arr.

但这与以下有何不同:

foo = arr
foo = arr.clone
foo = arr.dup
foo = arr.deep_clone
Marshal.load # something something
# etc...

或者我在 SO 上看到的 dupmapinject 的任何其他疯狂组合?

Or any of the other crazy combinations of dup and map and inject that I'm seeing on SO?

推荐答案

这是 ruby​​ 中可变性的棘手概念.就核心对象而言,这通常与数组和散列有关.字符串也是可变的,但是可以通过脚本顶部的标志来禁用它.请参阅评论frozen_string_literal: true"是什么意思?.

This is the tricky concept of mutability in ruby. In terms of core objects, this usually comes up with arrays and hashes. Strings are mutable as well, but this can be disabled with a flag at the top of the script. See What does the comment "frozen_string_literal: true" do?.

在这种情况下,您可以轻松调用dupdeep_dupclone,达到与replace 相同的效果:

In this case, you can call dup, deep_dup, clone easily to the same effect as replace:

['some', 'array'].dup
['some', 'array'].deep_dup
['some', 'array'].clone
Marshal.load Marshal::dump(['some', 'array'])

在差异方面,dupclone 除了一些细微的细节之外是相同的 - 参见 Ruby 的 dup 和 clone 方法有什么区别?

In terms of differences, dup and clone are the same except for some nuanced details - see What's the difference between Ruby's dup and clone methods?

这些和 deep_dup 的区别在于 deep_dup 递归地工作.例如,如果您复制嵌套数组,则不会克隆内部数组:

The difference between these and deep_dup is that deep_dup works recursively. For example if you dup a nested array, the inner array will not be cloned:

  a = [[1]]
  b = a.clone
  b[0][0] = 2
  a # => [[2]]

同样的事情发生在哈希上.

The same thing happens with hashes.

Marshal.load Marshal::dump 是深度克隆对象的通用方法,与 deep_dup 不同,它位于 ruby​​ 核心中.Marshal::dump 返回一个字符串,因此它可以方便地将对象序列化到文件中.

Marshal.load Marshal::dump <object> is a general approach to deep cloning objects, which, unlike deep_dup, is in ruby core. Marshal::dump returns a string so it can be handy in serializing objects to file.

如果你想避免这样的意外错误,请记住哪些方法有副作用,并且只在有意义的时候调用它们.方法名称末尾的解释点表示它有副作用,但其他包括 unshift、push、concat、delete 和 pop.函数式编程的很大一部分是避免副作用.你可以看到 https://www.sitepoint.com/函数式编程技术与 ruby​​-part-i/

If you want to avoid unexpected errors like this, keep a mental index of which methods have side-effects and only call those when it makes sense to. An explanation point at the end of a method name indicates that it has side effects, but others include unshift, push, concat, delete, and pop. A big part of fuctional programming is avoiding side effects. You can see https://www.sitepoint.com/functional-programming-techniques-with-ruby-part-i/

这篇关于使用 [].replace 复制数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆