浅层学习与深层学习

by Payal Gupta

通过Payal Gupta

深层副本与浅层副本-以及如何在Swift中使用它们 (Deep copy vs. shallow copy — and how you can use them in Swift)

Copying an object has always been an essential part in the coding paradigm. Be it in Swift, Objective-C, JAVA or any other language, we’ll always need to copy an object for use in different contexts.

复制对象一直是编码范例中必不可少的部分。 无论是Swift,Objective-C,JAVA还是其他任何语言,我们始终需要复制一个对象以用于不同的上下文。

In this article, we’ll discuss in detail how to copy different data types in Swift and how they behave in different circumstances.

在本文中,我们将详细讨论如何在Swift中复制不同的数据类型以及它们在不同情况下的行为。

值和引用类型 (Value and Reference types)

All the data types in Swift broadly fall into two categories, namely value types and reference types.

Swift中的所有数据类型大致分为两类,即值类型引用类型

  • Value type — each instance keeps a unique copy of its data. Data types that fall into this category include — all the basic data types, struct, enum, array, tuples.

    值类型 -每个实例都保留其数据的唯一副本。 属于此类的数据类型包括- all the basic data types, struct, enum, array, tuples

  • Reference type — instances share a single copy of the data, and the type is usually defined as a class.

    引用类型 -实例共享数据的单个副本,并且该类型通常定义为class

The most distinguishing feature of both the types lies in their copying behaviour.

两种类型的最大区别在于它们的复制行为。

什么是深浅复制? (What is Deep and Shallow copy?)

An instance, whether it’s a value type or a reference type, can be copied in one of the following ways:

实例,无论是值类型还是引用类型,都可以通过以下方式之一进行复制:

深度复制-复制所有内容 (Deep copy — Duplicates everything)

  • With a deep copy, any object pointed to by the source is copied and the copy is pointed to by the destination. So two completely separate objects will be created.对于深层副本,将复制源指向的任何对象,而副本将由目标指向。 因此,将创建两个完全独立的对象。
  • Collections — A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

    集合 - 集合的深层副本是两个集合,原始集合中的所有元素都重复了。

  • Less prone to race conditions and performs well in a multithreaded environment — changes in one object will have no effect on another object.

    较不容易出现竞争状况 ,并且在多线程环境中表现良好-一个对象的更改不会对另一对象产生影响。

  • Value types are copied deeply.

    值类型被深深复制。

In the above code,

在上面的代码中,

  • Line 1: arr1 — array (a value type) of Strings

    第1行arr1 —字符串数组(值类型)

  • Line 2: arr1 is assigned to arr2. This will create a deep copy of arr1 and then assign that copy to arr2

    第2行 :将arr1分配给arr2 。 这将创建arr1的深层副本,然后将该副本分配给arr2

  • Lines 7 to 11: any changes done in arr2 don’t reflect in arr1 .

    第7至11行 :在arr2所做的任何更改都不会反映在arr1

This is what deep copy is — completely separate instances. The same concept works with all the value types.

这就是深层副本-完全独立的实例。 相同的概念适用于所有值类型。

In some scenarios, that is when a value type contains nested reference types, deep copy reveals a different kind of behaviour. We’ll see that in upcoming sections.

在某些情况下,即当值类型包含嵌套的引用类型时,深拷贝显示了另一种行为。 我们将在接下来的部分中看到。

浅拷贝-尽可能少重复 (Shallow copy — Duplicates as little as possible)

  • With a shallow copy, any object pointed to by the source is also pointed to by the destination. So only one object will be created in the memory.对于浅表副本,目标指向的对象也指向源指向的任何对象。 因此,将在内存中仅创建一个对象。
  • Collections — A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.

    集合 - 集合的浅表副本是集合结构的副本,而不是元素。 对于浅表副本,现在两个集合共享各个元素。

  • Faster — only the reference is copied.

    更快 -仅复制参考。

  • Copying reference types creates a shallow copy.

    复制引用类型将创建浅表副本。

In the above code,

在上面的代码中,

  • Lines 1 to 8: Address class type

    第1至8行Address类别类型

  • Line 10: a1 — an instance of Address type

    第10行a1 Address类型的实例

  • Line 11: a1 is assigned to a2. This will create a shallow copy of a1 and then assign that copy to a2 , that is only the reference is copied into a2.

    第11行a1分配给a2 。 这将创建a1的浅表副本,然后将该副本分配给a2 ,即仅将引用复制到a2

  • Lines 16 to 19: any changes done in a2 will certainly reflect in a1 .

    第16至19行 :在a2所做的任何更改肯定会反映在a1

In the above illustration, we can see that both a1 and a2 point to the same memory address.

在上图中,我们可以看到a1a2指向相同的内存地址。

深度复制参考类型 (Copying Reference Types Deeply)

As of now, we know that whenever we try to copy a reference type, only the reference to the object is copied. No new object is created. What if we want to create a completely separate object?

到目前为止,我们知道,只要尝试复制引用类型,就只会复制对对象的引用。 没有创建新对象。 如果我们要创建一个完全独立的对象怎么办?

We can create a deep copy of the reference type using the copy() method. According to the documentation,

我们可以使用copy()方法创建引用类型的深层副本。 根据文档 ,

copy() — Returns the object returned by copy(with:).

copy()—返回copy(with:)返回的对象。

This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is no implementation for copy(with:).

对于采用NSCopying协议的类,这是一种便捷的方法。 如果没有实现copy(with:)则会引发异常。

Let’s restructure the Address class we created in Code Snippet 2 to conform to the NSCopying protocol.

让我们重组在代码片段2中创建的Address class ,使其符合NSCopying协议。

In the above code,

在上面的代码中,

  • Lines 1 to 14: Address class type conforms to NSCopying and implements copy(with:) method

    第1至14行Address类类型符合NSCopying并实现copy(with:)方法

  • Line 16: a1 — an instance of Address type

    第16行a1 Address类型的实例

  • Line 17: a1 is assigned to a2 using copy() method. This will create a deep copy of a1 and then assign that copy to a2 , that is a completely new object will be created.

    第17行 :使用copy()方法copy() a1分配给a2 。 这将创建a1的深层副本,然后将该副本分配给a2 ,这将创建一个全新的对象。

  • Lines 22 to 25: any changes done in a2 will not reflect in a1 .

    第22至25行 :在a2所做的任何更改都不会反映在a1

As is evident from the above illustration, both a1 and a2 point to different memory locations.

从上面的插图中可以明显看出, a1a2指向不同的存储位置。

Let’s look at another example. This time we’ll see how it works with nested reference types — a reference type containing another reference type.

让我们看另一个例子。 这次,我们将看到它如何与嵌套引用类型一起工作-包含另一个引用类型的引用类型

In the above code,

在上面的代码中,

  • Line 22: a deep copy of p1 is assigned to p2 using the copy() method. This implies that any change in one of them must not have any effect on the other one.

    第22行:使用copy()方法将p1的深层副本分配给p2 。 这意味着其中之一的任何更改都不得对另一方产生任何影响。

  • Lines 27 to 28: p2’s name and city values are changed. These must not reflect in p1.

    第27至28行: p2's namecity值已更改。 这些一定不能反映在p1

  • Line 30: p1’s name is as expected, but its city? It should be “Mumbai” shouldn’t it? But we can’t see that happening. “Bangalore” was only for p2 right? Yup…exactly.?

    第30行: p1's name符合预期,但其city ? 应该是“Mumbai”吗? 但是我们看不到这种情况。 “Bangalore”仅用于p2吧? 是的...是。

Deep copy…!? That was not expected from you. You said you’ll copy everything. And now you are behaving like this. Why oh why..?! What do I do now? ☠

深度复制...!没想到你会这样。 您说过要复制所有内容。 现在您的行为是这样的。 为什么哦为什么..?! 现在我该怎么做? ️️

Don’t panic. Let’s look at what memory addresses has to say in this.

不要惊慌 让我们看看在这方面要说的内存地址。

From the above illustration, we can see that

从上图可以看出

  • p1 and p2 point to different memory locations as expected.

    p1p2按预期指向不同的存储位置。

  • But their address variables are still pointing to the same location. This means that even after copying them deeply, only the references are copied — that is, a shallow copy of course.

    但是它们的address变量仍指向同一位置。 这意味着即使复制了很深的内容,也只会复制引用-即当然是浅表副本

Please note: every time we copy a reference type, a shallow copy is created by default until we explicitly specify that it should be copied deeply.

请注意:每次我们复制引用类型时,默认情况下都会创建一个浅表副本,直到我们明确指定应深度复制为止。

func copy(with zone: NSZone? = nil) -> Any{    let person = Person(self.name, self.address)    return person}

In the above method we implemented earlier for the Person class, we have created a new instance by copying the address with self.address . This will only copy the reference to the address object. This is the reason why both p1 and p2’s address point to the same location.

在我们之前为Person类实现的上述方法中,我们通过复制具有self.address的地址来创建了一个新实例。 这只会将引用复制到地址对象。 这就是为什么p1p2's address指向同一位置的原因。

So, copying the object using the copy() method won’t create a true deep copy of the object.

因此,使用copy()方法复制对象不会创建该对象的真实深层副本

To duplicate a reference object completely: the reference type along with all the nested reference types must be copied with the copy() method.

要完全复制参考对象:必须使用copy()方法复制参考类型以及所有嵌套的参考类型。

let person = Person(self.name, self.address.copy() as? Address)

Using the above code in the func copy(with zone: NSZone? = nil) -> Any method will get everything working. You can see that from the below illustration.

func copy(with zone: NSZone? = nil) ->使用上面的代码func copy(with zone: NSZone? = nil) ->任何方法都可以使一切工作。 从下图可以看到。

真正的深复制-引用和值类型 (True Deep Copy — Reference and Value types)

We’ve already seen how we can create a deep copy of the reference types. Of course we can do that with all the nested reference types.

我们已经了解了如何创建引用类型的深层副本。 当然,我们可以使用所有嵌套的引用类型来做到这一点。

But what about the nested reference type in a value type, that is an array of objects, or a reference type variable in a struct or maybe a tuple? Can we resolve that using copy() too? No we can’t, actually. The copy() method requires implementing NSCopying protocol which only works for NSObject subclasses. Value types don’t support inheritance, so we can’t use copy() with them.

但是,值类型中的嵌套引用类型(即对象数组)还是结构或元组中的引用类型变量呢? 我们也可以使用copy()解决该问题吗? 不,我们不能,实际上。 copy()方法需要实现NSCopying协议,该协议仅适用于NSObject子类。 值类型不支持继承,因此我们不能copy()它们与copy()一起使用。

In line 2, only the structure of arr1 is deep copied, but the Address objects inside it are still shallow copied. You can see that from the below memory map.

在第2行中,仅深度复制了arr1的结构,但内部的Address对象仍然被浅复制。 您可以从下面的内存映射中看到。

The elements in both arr1 and arr2 both point to the same memory locations. This is because of the same reason — reference types are shallow copied by default.

arr1arr2的元素都指向相同的存储位置。 这是由于相同的原因-默认情况下,引用类型是浅表复制。

Serializing and then de-serializing an object always creates a brand new object. It is valid for both value types as well as the reference types.

序列化然后反序列化对象总是会创建一个全新的对象。 对于值类型和引用类型均有效。

Here are some APIs that we can use to serialize and de-serialize data:

以下是一些我们可以用来序列化和反序列化数据的API:

  1. NSCoding — A protocol that enables an object to be encoded and decoded for archiving and distribution. It will only work with class type objects as it requires inheriting from NSObject .

    NSCoding —一种协议,用于对对象进行编码和解码以进行归档和分发。 它仅适用于class类型对象,因为它需要从NSObject继承。

  2. Codable — Make your data types encodable and decodable for compatibility with external representations such as JSON. It will work for both value types — struct, array, tuple, basic data typeswell as reference types — class .

    可编码 -使您的数据类型编码且可解码与外部表示,如JSON的兼容性。 它适用于两种值类型struct, array, tuple, basic data types以及引用类型class

Let’s restructure the Address class a bit further to conform to the Codable protocol and remove all the NSCopying code that we added earlier in Code Snippet 3.

让我们重组的Address类远一点,以符合Codable协议,并删除所有NSCopying代码,我们在代码段3前面添加。

In the above code, lines 11–13 will create a true deep copy of arr1. Below is the illustration that gives a clear picture of the memory locations.

在上面的代码中,第11-13行将创建arr1的真实深层副本。 下面的插图清晰地显示了内存位置。

写时复制 (Copy on Write)

Copy on write is an optimization technique that helps boost performance when copying value types.

写时复制是一种优化技术,可帮助您在复制值类型时提高性能。

Let’s say we copy a single String or Int or maybe any other value type — we won’t face any crucial performance issues in that case. But what about when we copy an array of thousands of elements? Will it still not create any performance issues? What if we just copy it and don’t make any changes to that copy? Isn’t that extra memory we used just a waste in that case?

假设我们复制一个String或Int或任何其他值类型-在这种情况下,我们将不会遇到任何关键的性能问题。 但是,当我们复制成千上万个元素的数组时呢? 仍然不会产生任何性能问题吗? 如果我们只是复制它而不对该副本做任何更改怎么办? 在这种情况下,难道我们只是浪费了额外的内存吗?

Here comes the concept of Copy in Write — when copying, each reference points to the same memory address. It’s only when one of the references modifies the underlying data that Swift actually copies the original instance and makes the modification.

这里有写复制的概念-复制时,每个引用都指向相同的内存地址。 只有当其中一个引用修改基础数据时,Swift才实际复制原始实例并进行修改。

That is, whether it’s deep copy or shallow copy, a new copy will not be created until we make a change in one of the objects.

也就是说,无论是深层副本还是浅层副本,在我们更改其中一个对象之前,都不会创建新副本。

In the above code,

在上面的代码中,

  • Line 2: a deep copy of arr1 is assigned to arr2

    第2行 :将arr1的深层副本分配给arr2

  • Lines 4 and 5: arr1 and arr2 still point to the same memory address

    第4和第5行arr1arr2仍指向相同的内存地址

  • Line 7: changes made in arr2

    第7行 :在arr2所做的更改

  • Lines 9 and 10: arr1 and arr2 now pointing to different memory locations

    第9和10行arr1arr2现在指向不同的内存位置

Now you know more about deep and shallow copies and how they behave in different scenarios with different data types. You can try them with your own set of examples and see what results you get.

现在,您进一步了解了深层副本和浅层副本,以及它们在不同数据类型的不同情况下的行为。 您可以使用自己的示例集来尝试使用它们,然后查看获得的结果。

进一步阅读 (Further reading)

Don’t forget to read my other articles:

不要忘记阅读我的其他文章:

  1. Everything about Codable in Swift 4

    Swift 4中有关Codable的一切

  2. Everything you’ve always wanted to know about notifications in iOS

    您一直想了解的有关iOS中通知的所有信息

  3. Color it with GRADIENTS — iOS

    使用GRADIENTS为它着色— iOS

  4. Coding for iOS 11: How to drag & drop into collections & tables

    iOS 11编码:如何拖放到集合和表格中

  5. All you need to know about Today Extensions (Widget) in iOS 10

    您需要了解的有关iOS 10中的Today Extensions(Widget)的所有信息

  6. UICollectionViewCell selection made easy..!!

    UICollectionViewCell选择变得简单.. !!

Feel free to leave comments in case you have any questions.

如有任何疑问,请随时发表评论。

翻译自: https://www.freecodecamp.org/news/deep-copy-vs-shallow-copy-and-how-you-can-use-them-in-swift-c623833f5ad3/

浅层学习与深层学习

浅层学习与深层学习_深层副本与浅层副本-以及如何在Swift中使用它们相关推荐

  1. java数位倒置递归_有人能解释一下这个递归代码如何在java中反转int吗?

    r根本不用 10*r+n%10 实际上,这是一件很棘手的事情,而且很酷. 这是一个很好的例子,说明变量命名不当会使代码难以理解.我们有3行代码可以实际执行某些操作,但它的工作原理并不明显. priva ...

  2. swift语言 数组定义_如何在Swift中声明弱引用数组?

    I'd like to store an array of weak references in Swift. The array itself should not be a weak refere ...

  3. 深度学习与神经网络关系(BP网络【浅层】与深层网络)

    文章目录 Deep Learning的基本思想 浅层学习(Shallow Learning)和深度学习(Deep Learning) 浅层学习是机器学习的第一次浪潮. 深度学习是机器学习的第二次浪潮. ...

  4. 大学计算机专业课程主体知识层,《计算机程序设计基础》论文,关于《计算机程序设计基础》课程中深层学习教学策略的实践相关参考文献资料-免费论文范文...

    导读:本论文是一篇免费优秀的关于<计算机程序设计基础>论文范文资料,可用于相关论文写作参考. 刘倩 (西南交通大学信息科学与技术学院,四川成都611756) 摘 要:在<计算机程序设 ...

  5. [DeeplearningAI笔记]改善深层神经网络_深度学习的实用层面1.10_1.12/梯度消失/梯度爆炸/权重初始化...

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.10 梯度消失和梯度爆炸 当训练神经网络,尤其是深度神经网络时,经常会出现的问题是梯度消失或者梯度爆炸,也就是说当你训练深度网络时,导数或坡 ...

  6. 3.6 BatchNorm 为什么起作用-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授

    ←上一篇 ↓↑ 下一篇→ 3.5 将 Batch Norm 拟合进神经网络 回到目录 3.7 测试时的 Batch Norm BatchNorm 为什么起作用? (Why does Batch Nor ...

  7. 深度学习笔记(5) 深层神经网络

    深度学习笔记(5) 深层神经网络 1. 深层神经网络 2. 前向传播和反向传播 3. 核对矩阵的维数 4. 参数和超参数 5. 深度学习和大脑的关联性 1. 深层神经网络 当算神经网络的层数时,不算输 ...

  8. 异常检测中的浅层模型与深度学习模型综述(A Unifying Review of Deep and Shallow Anomaly Detection)

    A Unifying Review of Deep and Shallow Anomaly Detection 异常检测中的浅层模型与深度学习模型综述 摘要:随着众多异常检测方法(基于生成模型,单分类 ...

  9. 神经网络与深度学习笔记 (五)深层神经网络

    摘要:本文知识点主要有简单介绍深层神经网络.深层神经网络的传播过程.保证矩阵维数的正确性.深度神经网络强大的原因.神经网络正向传播和反向传播的流程图.参数和超参数和神经网络与人脑机制的关系. 1.深层 ...

最新文章

  1. Tomaso A.Poggio教授丨人工智能的下一个突破点在何处?
  2. rust做嵌入式开发_Rust 嵌入式开发 STM32 amp; RISC-V
  3. 通过示例Hibernate–第2部分(DetachedCriteria)
  4. php中拼接html代码,如何利用ajax给html动态拼接代码
  5. html table设置行高_字号与行高
  6. MasterPage 变化了的 ClientID ctl00_
  7. python 视频转换为图像,图像转换为视频
  8. 七、数值微分与数值积分
  9. H5 微信分享显示标题和图标
  10. 思维导图怎么做计划的简单高效绘制方法
  11. Springboot课设旅游推荐系统
  12. Android6.0 Qualcomm Atheros QCA6174A WiFi Model Support
  13. Gluster分布式文件系统
  14. c语言 准确赋值浮点数,C语言浮点数
  15. Vue+JTopo(一)
  16. html5 足球比赛阵容图,HTML5/Velocity.js 3D足球阵容
  17. 基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r
  18. 什么是反射 反射怎么用
  19. linux用ifconfig查不到IP的解决办法
  20. ref使用之react / react hook

热门文章

  1. 安装虚拟环境virtualenv 适用于windows操作系统
  2. redis-python操作redis
  3. dj电商-数据表的设计-购物车表与订单表设计
  4. nginx 修改 max open files limits
  5. go标准库的学习-encoding/json
  6. 2.7.3-YARN-获取debug命令:resourceManager+nodeManager
  7. 爪哇国新游记之二十八----从url指定的地址下载文件到本地
  8. [20170508]listagg拼接显示字段.txt
  9. 织梦留言簿使用及修改
  10. Privacy Policy