哈希似乎通过引用传递:Ruby
Hash appears to be passing by reference : Ruby
我知道标题不明确,所以让我们看看下面的例子。
我有一个名为 sh
的哈希,然后我将 sh
分配给一个新变量 su
,之后我正在修改 sh
,但是 su
也被修改了。我想 su
保留原始内容。
irb(main):001:0> sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):002:0> su = sh
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):003:0> su
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):005:0> sh.delete("sex")
=> "male"
irb(main):006:0> sh
=> {"name"=>"shan", "age"=>"33"} => ok here
irb(main):007:0> su
=> {"name"=>"shan", "age"=>"33"} => ??
irb(main):010:0> sh["city"] = "Bangalore" => New example
=> "Bangalore"
irb(main):011:0> sh
=> {"name"=>"shan", "age"=>"33", "city"=>"Bangalore"} => ok
irb(main):012:0> su
=> {"name"=>"shan", "age"=>"33", "city"=>"Bangalore"} => ??
.delete 从内存中删除数据
你可以使用这个:su = Hash[sh]
clone 方法是 Ruby 进行浅拷贝的标准内置方法:
su = sh.clone
备注:以上解决方案仅适用于非嵌套哈希。在嵌套哈希的情况下,您需要编组
su = Marshal.load(Marshal.dump(sh))
如果通过引用或值传递,这不是问题。它只是指向同一个对象的两个变量,并且可以修改该对象(添加键、删除键、更改值)。
您可以使用 object_id
进行检查
3.0.0 :002 > sh.object_id
=> 260
3.0.0 :004 > su.object_id
=> 260
就是你程序中的这一行
su = sh
它告诉 Ruby 你希望你调用 sh
的哈希也被称为 su
。有点叫我的名字或昵称:-)
并非 object_id
的输出可能因 ruby 版本和程序运行而异。
有多种方法可以拥有两个单独的哈希值(或其他对象:
使用初始化程序创建两个单独的对象:
sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
su = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
创建克隆:
sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
su = sh.clone
#clone
是为标准 ruby 类 定义的(例如字符串和数字)。如果您在哈希中存储其他内容,那么您可能需要自己实现它才能获得正确的副本。
3.0.0 :005 > su = sh.clone
3.0.0 :006 > sh.object_id
=> 260
3.0.0 :007 > su.object_id
=> 280
不过现在它变得有趣了。您只克隆了 Hash
,而不是您存储在其中的对象:
sh = {a: "Hi"}
su = sh.clone
3.0.0 :010 > sh[:a].object_id
=> 300
3.0.0 :011 > su[:a].object_id
=> 300
这意味着如果您修改散列中的一个对象,它也会更改另一个散列引用的对象:
根据您的需要,您可以分配新对象:
sh = {a: "Hi"}
su = sh.clone
sh[:a] = "HI
sh[:a]
# => "HI"
su[:a]
# => "Hi"
或就地修改它们
sh = {a: "Hi"}
su = sh.clone
sh[:a].upcase! # this changes the string inplace
sh[:a]
# => "HI"
su[:a]
# => "HI"
clone
制作一个浅拷贝,如果你想要一个完整的拷贝,在每个对象上调用克隆,你可以使用 Denny Mueller 描述的 Marshal load/dump
技巧或查看 ActiveSupports #deep_dup
https://guides.rubyonrails.org/active_support_core_extensions.html#deep-dup
或者您可以自己编写一个实现并将其添加到您的散列中。
(那里也有一些宝石)
我知道标题不明确,所以让我们看看下面的例子。
我有一个名为 sh
的哈希,然后我将 sh
分配给一个新变量 su
,之后我正在修改 sh
,但是 su
也被修改了。我想 su
保留原始内容。
irb(main):001:0> sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):002:0> su = sh
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):003:0> su
=> {"name"=>"shan", "age"=>"33", "sex"=>"male"}
irb(main):005:0> sh.delete("sex")
=> "male"
irb(main):006:0> sh
=> {"name"=>"shan", "age"=>"33"} => ok here
irb(main):007:0> su
=> {"name"=>"shan", "age"=>"33"} => ??
irb(main):010:0> sh["city"] = "Bangalore" => New example
=> "Bangalore"
irb(main):011:0> sh
=> {"name"=>"shan", "age"=>"33", "city"=>"Bangalore"} => ok
irb(main):012:0> su
=> {"name"=>"shan", "age"=>"33", "city"=>"Bangalore"} => ??
.delete 从内存中删除数据
你可以使用这个:su = Hash[sh]
clone 方法是 Ruby 进行浅拷贝的标准内置方法:
su = sh.clone
备注:以上解决方案仅适用于非嵌套哈希。在嵌套哈希的情况下,您需要编组
su = Marshal.load(Marshal.dump(sh))
如果通过引用或值传递,这不是问题。它只是指向同一个对象的两个变量,并且可以修改该对象(添加键、删除键、更改值)。
您可以使用 object_id
3.0.0 :002 > sh.object_id
=> 260
3.0.0 :004 > su.object_id
=> 260
就是你程序中的这一行
su = sh
它告诉 Ruby 你希望你调用 sh
的哈希也被称为 su
。有点叫我的名字或昵称:-)
并非 object_id
的输出可能因 ruby 版本和程序运行而异。
有多种方法可以拥有两个单独的哈希值(或其他对象:
使用初始化程序创建两个单独的对象:
sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
su = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
创建克隆:
sh = {"name"=>"shan", "age"=>"33" , "sex"=>"male"}
su = sh.clone
#clone
是为标准 ruby 类 定义的(例如字符串和数字)。如果您在哈希中存储其他内容,那么您可能需要自己实现它才能获得正确的副本。
3.0.0 :005 > su = sh.clone
3.0.0 :006 > sh.object_id
=> 260
3.0.0 :007 > su.object_id
=> 280
不过现在它变得有趣了。您只克隆了 Hash
,而不是您存储在其中的对象:
sh = {a: "Hi"}
su = sh.clone
3.0.0 :010 > sh[:a].object_id
=> 300
3.0.0 :011 > su[:a].object_id
=> 300
这意味着如果您修改散列中的一个对象,它也会更改另一个散列引用的对象:
根据您的需要,您可以分配新对象:
sh = {a: "Hi"}
su = sh.clone
sh[:a] = "HI
sh[:a]
# => "HI"
su[:a]
# => "Hi"
或就地修改它们
sh = {a: "Hi"}
su = sh.clone
sh[:a].upcase! # this changes the string inplace
sh[:a]
# => "HI"
su[:a]
# => "HI"
clone
制作一个浅拷贝,如果你想要一个完整的拷贝,在每个对象上调用克隆,你可以使用 Denny Mueller 描述的 Marshal load/dump
技巧或查看 ActiveSupports #deep_dup
https://guides.rubyonrails.org/active_support_core_extensions.html#deep-dup
或者您可以自己编写一个实现并将其添加到您的散列中。
(那里也有一些宝石)