如何用ruby制作深度拷贝(make deep copies in ruby)

通常需要在Ruby中复制一个值。虽然这看起来很简单,但对于简单的对象来说,只要您必须在同一个对象上使用多个数组或散列创建数据结构的副本,您就会很快发现存在许多陷阱。...

通常需要在Ruby中复制一个值。虽然这看起来很简单,但对于简单的对象来说,只要您必须在同一个对象上使用多个数组或散列创建数据结构的副本,您就会很快发现存在许多陷阱。

Woman at a computer

对象和引用

为了理解发生了什么,让我们看一些简单的代码。首先,赋值运算符使用Ruby中的POD(普通旧数据)类型。

a = 1 b = a a += 1 puts b

这里,赋值运算符复制a的值,并使用赋值运算符将其赋值给b。对a的任何更改都不会反映在b中。但是更复杂的事情呢?考虑一下这个。

a = [1,2] b = a a << 3 puts b.inspect

在运行上述程序之前,请尝试猜测输出是什么以及为什么。这与前面的示例不同,对a所做的更改反映在b中,但为什么?这是因为数组对象不是POD类型。赋值运算符不复制值,它只是将引用复制到数组对象。a和b变量现在是对同一数组对象的引用,任何一个变量的更改都将在另一个变量中看到。

现在您可以了解为什么复制引用到其他对象的非平凡对象会很棘手。如果您只是复制对象,那么您只是将引用复制到更深的对象,因此您的副本被称为“浅层副本”

ruby提供的功能:dup和克隆

Ruby提供了两种复制对象的方法,包括一种可以进行深度复制的方法。Object#dup方法将生成对象的浅拷贝。为此,dup方法将调用该类的initialize\u copy方法。它的具体功能取决于类。在某些类(如Array)中,它将使用与原始数组相同的成员初始化新数组。然而,这不是一个深度复制。考虑下面的问题。

a = [1,2] b = a.dup a << 3 puts b.inspect a = [ [1,2] ] b = a.dup a[0] << 3 puts b.inspect

这里发生了什么事?Array#initialize_copy方法确实会创建数组的副本,但该副本本身是浅层副本。如果阵列中有任何其他非POD类型,则使用dup只能是部分深度副本。它将只与第一个数组一样深,任何更深的数组、散列或其他对象将只被浅拷贝。

还有一种方法值得一提,克隆。克隆方法与dup做的事情相同,但有一个重要的区别:预期对象将使用能够进行深度复制的方法覆盖此方法。

那么在实践中这意味着什么呢?这意味着您的每个类都可以定义一个克隆方法,该方法将生成该对象的深度副本。这还意味着您必须为创建的每个类编写一个克隆方法。

诀窍:编组

“编组”对象是表示“序列化”对象的另一种方式。换句话说,将该对象转换为一个字符流,该字符流可以写入一个文件中,您可以稍后“解组”或“取消序列化”以获得相同的对象。可以利用此漏洞获取任何对象的深度副本。

a = [ [1,2] ] b = Marshal.load( Marshal.dump(a) ) a[0] << 3 puts b.inspect

这里发生了什么事?Marshal.dump创建存储在中的嵌套数组的“转储”。此转储是一个二进制字符串,用于存储在文件中。它包含数组的全部内容,一个完整的深度副本。接下来,Marshal.load执行相反的操作。它解析这个二进制字符数组并创建一个全新的数组,其中包含全新的数组元素。

但这是一个骗局。它效率低下,无法在所有对象上运行(如果您尝试以这种方式克隆网络连接会发生什么情况?),而且速度可能也不太快。但是,这是制作深度拷贝的最简单方法,而不是自定义的initialize\u copy或clone方法。此外,如果加载了库以支持像to_yaml或to_xml这样的方法,也可以做同样的事情。

  • 发表于 2021-09-28 21:22
  • 阅读 ( 232 )
  • 分类:IT

你可能感兴趣的文章

红宝石(ruby)和python(python)的区别

关键区别——ruby与python Ruby和Python是高级编程语言,因为它们遵循与英语语言相似的语法。因此,程序员很容易理解这些语言。Ruby和Python都是解释语言。两种语言都有大量的社区支持。Ruby和Python的一个主要优点是这些语言支...

  • 发布于 2020-10-19 17:41
  • 阅读 ( 338 )

最适合新手的ruby互动介绍

Ruby和Python之间正在进行一场皇家之战。这两个伟大的竞争对手背后都有庞大的社区,即使移动语言成为人们关注的焦点,这两种语言在web开发中仍然很受欢迎。 ...

  • 发布于 2021-03-13 09:52
  • 阅读 ( 214 )

使用静态站点生成器快速构建网站

This guide is available to download as a free PDF. Download this file now. Feel free to copy and share this with your friends and family. ...

  • 发布于 2021-03-25 19:23
  • 阅读 ( 306 )

python(python)和红宝石(ruby)的区别

Python和Ruby都是高级服务器端脚本语言,主要关注高性能的更清晰的代码,广泛用于开发web应用程序和原型。他们也是社区中最受欢迎的第一语言候选人。Ruby于1993年在日本推出,2001年在美国推出主要版本,虽然Python是由Guido van R...

  • 发布于 2021-06-25 22:26
  • 阅读 ( 246 )

perl语言(perl)和红宝石(ruby)的区别

Perl和Ruby的主要区别在于,Ruby比Perl提供了更多的面向对象支持。 Perl和Ruby是两种高级通用语言。这两种语言都支持过程编程和面向对象编程等范式,但是Ruby比Perl更面向对象。然而,这两种语言都有简单易用的语法。它们通常用...

  • 发布于 2021-07-01 12:05
  • 阅读 ( 368 )

浅拷贝(shallow copy)和深度复制(deep copy)的区别

...复制和深复制的区别-主要区别比较 关键术语 复制模块,深度复制,浅层复制 什么是复制模块(copy module)? 为了使浅拷贝或深拷贝工作,程序应该由一个拷贝模块组成。程序员可以使用“导入副本”模块。此外,copy()返回对...

  • 发布于 2021-07-01 23:59
  • 阅读 ( 391 )

红宝石(ruby)和ruby on rails(ruby on rails)的区别

关键区别:Ruby是一种功能强大的编程语言,而rubyonrails是一种基于Ruby编程语言的web框架。这个框架用于开发基于数据的网站。 Ruby是松本幸弘在20世纪90年代中期开发的一种脚本语言。这种语言可以在多种操作系统平台上运行,...

  • 发布于 2021-07-12 08:27
  • 阅读 ( 249 )

如何在ruby中组合数组(combine arrays in ruby)

“组合数组的最佳方式是什么?”这个问题相当模糊,可能意味着一些不同的事情。 串联 连接是将一个事物附加到另一个事物上。例如,将数组[1,2,3]和[4,5,6]连接起来将得到[1,2,3,4,5,6]。这可以在Ruby中通过几种方式实现。 ...

  • 发布于 2021-09-12 07:29
  • 阅读 ( 210 )

ruby编程语言初学者指南

Ruby在面向对象脚本语言中是独一无二的。从某种意义上说,对于那些热爱面向对象语言的人来说,它是一种纯粹的语言。所有东西,毫无例外,都自动成为对象,而在其他编程语言中,情况并非如此。 什么是物体?嗯,从某...

  • 发布于 2021-09-12 07:30
  • 阅读 ( 196 )

ruby中的“require”方法

为了创建可重用的组件,即可以在其他程序中轻松使用的组件,编程语言必须能够在运行时顺利导入代码。在Ruby中,require方法用于加载另一个文件并执行其所有语句。这用于导入文件中的所有类和方法定义。除了简单地执行文...

  • 发布于 2021-09-12 23:04
  • 阅读 ( 151 )
MOU73271872
MOU73271872

0 篇文章

相关推荐