【问题标题】:Weird behavior when copying one hash to another将一个哈希复制到另一个时的奇怪行为
【发布时间】:2017-07-29 11:23:09
【问题描述】:

我有一个管理配置的类(在本地保存为 JSON),并且我编写了一种将配置从一个文件复制到另一个文件的方法。两个 JSON 文件都作为哈希值加载到实例变量中(分别为 @local@repository)。我遇到了一些奇怪的行为,在一个哈希上设置一个键会覆盖另一个哈希中相同键的值。我已将问题缩小到下面代码 sn-p 的第 14 行。我在第 12 行的 puts 语句将 @repository[brand][:branches][branch] 显示为包含数据的非空哈希,而我在第 21 行的 puts 语句将 @repository[brand][:branches][branch] 显示为空哈希。

def copy(brand, branch = nil)
    brand = brand.to_sym
    branch =  branch.to_sym

    if branch.nil?
        if @local[:repository].has_key?(brand)
            @local[:repository][brand].deep_merge(@repository[brand])
        else
            @local[:repository][brand] = @repository[brand]
        end
    else
        puts @repository[brand][:branches][branch]
        unless @local[:repository].has_key?(brand)
            @local[:repository][brand] = @repository[brand]
            @local[:repository][brand][:branches] = Hash.new
        end

        unless @local[:repository][brand][:branches].has_key?(branch)
            @local[:repository][brand][:branches][branch] = Hash.new
        end
        puts @repository[brand][:branches][branch]
        @local[:repository][brand][:branches][branch].deep_merge(@repository[brand][:branches][branch])
    end

    self.write(CONFIG_FILE, @local)
end

如果我将第 14 行更改为 @local[:repository][brand] = Hash.new,则第 21 行的哈希值不再为空,实际上是预期值。关键是@local[:repository] 中的brand 键还不存在。

谁能解释一下这里发生了什么?

【问题讨论】:

  • 这与您的实际问题无关,但您应该阅读如何在 RoR 中使用 unlessrailstips.org/blog/archives/2008/12/01/… 并清理 if 声明,我没有机会了解发生了什么。
  • 这段代码的问题在哪里?您刚刚发布了一堵代码,但它没有解释预期的结果或问题的位置。 stackoverflow.com/help/mcve
  • 然而,你没有展示任何具体的例子来说明修改的内容、时间和地点。请用更清晰的例子回来。
  • 代码仍然太多,更糟糕的是,对于minimal reproducible example,这里的代码太复杂了。请尝试将代码精简到仍然存在问题的最少代码量。几乎不可能遵循复杂的条件句来找出可能有错或可能没有错的地方。不过我注意到了一件事:在标题中您谈到了复制,但我没有看到您实际复制任何东西的任何地方。
  • 这个问题是完全理智的。这家伙只是不完全明白他在做什么。但是,嘿,这正是 stackoverflow 可以介入并提供帮助的地方

标签: ruby


【解决方案1】:

罪魁祸首在于这一行(你使用了两次):

@local[:repository][brand] = @repository[brand]

这不会复制@repository[brand] 中的哈希值。
让我们把它拆分一下,这样我们就可以更清楚地讨论它:

brand_detail = @repository[brand]
local_repo = @local[:repository]
local_repo[brand] = brand_detail

在第三条语句之后,local_repo[brand] 将不包含brand_details 哈希的副本,而是对该哈希的引用。所以现在所有这些行都会产生相同的效果;他们都会修改同一个哈希实例:

  • brand_detail[:branches] = 3
  • local_repo[brand][:branches] = 3
  • @repository[brand][:branches] = 3

您应该能够通过使用dup 显式添加副本而不是引用来规避此问题:

@local[:repository][brand] = @repository[brand].dup

【讨论】:

    猜你喜欢
    • 2013-01-10
    • 2012-06-16
    • 2011-02-01
    • 2013-06-24
    • 2017-01-01
    • 1970-01-01
    • 2013-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多