【问题标题】:How come my duplicate also affects the original?为什么我的副本也会影响原件?
【发布时间】:2018-07-11 15:36:12
【问题描述】:

我正在尝试通过一些修改将副本添加到数组中:

  site.pages.dup.each do | page |
    new_page = page.dup
    data = new_page.data
    data['permalink'] = File.join('/app', page.url)
    data['layout'] = 'app'
    site.pages << new_page
  end

  site.pages.each do | page |
    puts page.data
  end 

当我输出 page.data 时,永久链接不同,但 data['layout'] 对于数组中的所有项目都是相同的。我还尝试了 data = new_page.data.dup 并在每个实例中写出 new_page.data

【问题讨论】:

  • dup 很浅,就像文档说的那样。 data 是本地的;您需要将数据复制到 新对象中。
  • 我该怎么做,试过new_page.data = page.data.clonenew_page.data = page.data.dup
  • 还有,它怎么会影响.layout,而不影响.permalink?

标签: ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

(移动评论以回答格式问题。)

请提供数据示例;我在使用类似结构时遇到的问题为零,例如,

pages = [
  {
    'name' => 'page 1',
    'data' => {
      'permalink' => 'p1 perma',
      'layout'    => 'p1 layout'
    }
  },

  {
    'name' => 'page 2',
    'data' => {
      'permalink' => 'p2 perma',
      'layout'    => 'p2 layout'
    }
  },
]

如果我(基本上)使用你的代码,加上我的评论:

pages.dup.each do |p|
  new_page = p.dup

  new_data = new_page['data'].dup

  new_data['layout']    = 'app'
  new_data['permalink'] = "#{new_data['permalink']} whatever"

  new_page['data'] = new_data

  pages << new_page
end

我得到以下输出:

[{"name"=>"page 1", "data"=>{"permalink"=>"p1 perma", "layout"=>"p1 layout"}},
 {"name"=>"page 2", "data"=>{"permalink"=>"p2 perma", "layout"=>"p2 layout"}},
 {"name"=>"page 1", "data"=>{"permalink"=>"p1 perma whatever", "layout"=>"app"}},
 {"name"=>"page 2", "data"=>{"permalink"=>"p2 perma whatever", "layout"=>"app"}}]

不相关,但我会将数组串联分开;相反,考虑mapping 页面并使用原始pages 和修改后的数组创建一个新数组。现在您正在做一个不必要的额外dup,这会增加一些混乱。

我还将data dup/modification 分解为一个单独的方法(可能还有整个欺骗过程)以真正保持紧密,大致:

def modify_page_data(data)
  new_data = data.dup

  new_data['permalink'] = "#{data['permalink']} whatever"
  new_data['layout'] = 'app'

  new_data
end

def dup_page(page)
  new_page = page.dup
  new_page['data'] = modify_page_data(page['data'])
  new_page
end

new_pages = pages.map(&method(:dup_page))

然后你可以concat 或任何你想要的原始pages 和修改后的新页面。

https://github.com/davelnewton/stackoverflow/tree/master/ruby/51289405

【讨论】:

  • 这是一个很好的答案,但 new_data = new_page['data'].dup 输出 jekyll 3.7.3 | Error: can't dup NilClass
  • 我得到了它与 new_data = new_page['data'].dup 但随后 new_page['data'] = new_data 输出 jekyll 3.7.3 | Error: undefined method []=' for #&lt;Jekyll::Page @name="about_us.md"&gt; Did you mean? []
  • new_page['data'] 为空,但 new_page.data 是一个哈希值。
  • @Himmators 这就是你需要具体的原因;正如我所说,我创建了一个数据结构,因为无法知道您实际处理的是什么。您需要修改示例以适应数据结构/实例/等。你实际上正在处理。想法是一样的。
  • 谢谢,我是 ruby​​ 新手,所以很难弄清楚错误来自哪里。
【解决方案2】:

这里的问题是 dup 只是一个浅拷贝。这意味着它创建了第一层的副本,即数组本身,但不是任何更深的层。

您可能需要考虑像 full_dup 这样的 gem,它添加了 full_dup 方法,该方法可以根据需要深入挖掘以创建数据的完整副本。

完全披露:我编写了 full_dup gem。可能还有其他宝石也可以。

【讨论】:

  • 有没有办法只复制那个节点,我试过了 new_page.data = page.data.clone 和 new_page.data = page.data.dup
  • 还有,它怎么会影响.layout,而不影响.permalink?
  • 您尝试复制更深的数据结构失败了,因为在该层之下还有另一层。 page.data 本身就是一个哈希,所以 dup 只复制最顶层的哈希级别。哈希的内容仍然是共享引用。
猜你喜欢
  • 2021-04-01
  • 2020-02-21
  • 2020-09-22
  • 2011-09-30
相关资源
最近更新 更多