转:swift中结构体和类的区别(值类型和引用类型的区别)

在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换。我们可以先看看官方文档的描述:

Unlike other programming languages, Swift doesn’t require you to create separate interface and implementation files for custom structures and classes. In Swift, you define a structure or class in a single file, and the external interface to that class or structure is automatically made available for other code to use.

An instance of a class is traditionally known as anobject. However, Swift structures and classes are much closer in functionality than in other languages, and much of this chapter describes functionality that applies to instances ofeithera class or a structure type. Because of this, the more general terminstanceis used.

Comparing Structures and Classes

Structures and classes in Swift have many things in common. Both can:

  • Define properties to store values
  • Define methods to provide functionality
  • Define subscripts to provide access to their values using subscript syntax
  • Define initializers to set up their initial state
  • Be extended to expand their functionality beyond a default implementation
  • Conform to protocols to provide standard functionality of a certain kind

简单翻译过来就是:

与其他编程语言不同,Swift不需要为自定义结构体和类创建单独的接口和实现文件。在Swift中,您在单个文件中定义一个结构体或类,该类或结构体的外部接口将自动提供给其他代码使用。

类的实例传统上称为对象。然而,Swift结构体和类在功能上比在其他语言中更接近

比较结构和类

Swift中的结构体和类有很多共同点。都可以:

  • 定义属性来存储值
  • 定义方法来提供功能
  • 定义下标以使用下标语法提供对其值的访问
  • 定义初始化器来设置它们的初始状态
  • 扩展以扩展其功能,使其超出默认实现
  • 遵守协议以提供某种标准功能

结构体和类最大的区别就是结构体是值类型,类是引用类型。

这里提醒一下Swift值类型列表:

  • 结构体
  • 枚举
  • 元组(tuple)
  • 基本类型(Int,Double,Bool等)
  • 集合(Array, String, Dictionary, Set)

引用类型最常用的就是类和闭包。

在 Swift 中,值类型,存放在栈区;引用类型,存放在堆区。但是有些值类型,如字符串或数组,会间接地将项保存在堆中。所以它们是由引用类型支持的值类型。

Swift 中,值类型的赋值为深拷贝(Deep Copy),值语义(Value Semantics)即新对象和源对象是独立的,当改变新对象的属性,源对象不会受到影响,反之同理。

引用类型的赋值是浅拷贝(Shallow Copy),引用语义(Reference Semantics)即新对象和源对象的变量名不同,但其引用(指向的内存空间)是一样的,因此当使用新对象操作其内部数据时,源对象的内部数据也会受到影响。

struct Boy {
    var name = "Lilei"
    var age = 12
}
var boyA = Boy()
print("boyA.name -> \(boyA.name)")
        
var boyB = boyA
boyB.name = "Tom"
print("boyA.name -> \(boyA.name)")

控制台输出结果为:boyA.name -> Lilei
               boyA.name -> Lilei

Boy为结构体的时候更改boyB的name boyA.name 并没有改变

class Boy: NSObject {
    var name = "Lilei"
    var age = 12
}
var boyA = Boy()
print("boyA.name -> \(boyA.name)")
        
var boyB = boyA
boyB.name = "Tom"
print("boyA.name -> \(boyA.name)")
print(Unmanaged.passUnretained(boyA).toOpaque())
print(Unmanaged.passUnretained(boyB).toOpaque())

控制台输出结果为:boyA.name -> Lilei
               boyA.name -> Tom
               0x0000600002e2b9e0
               0x0000600002e2b9e0

Boy为class的时候更改boyB的name boyA也会改变,同时boyA的地址和boyB的地址相同可见在class中拷贝为指针拷贝,从中即可发现,两个变量指向的是同一块内存空间。

在swift4.0中 可以用==来判断两个对象是否是同一个对象

if boyA == boyB {
    print("boyA == boyB")
 }
控制台输出结果为:boyA == boyB

嵌套类型

在使用过程中会存在嵌套的情况

值类型嵌套值类型:

struct Boy {
    var name = "Lilei"
    var age = 12
    var dog = Dog()
    
}

struct Dog {
    var weight = 40
    var name = "littleDog"
    
}
var boyA = Boy()
var boyB = boyA

boyB.name = "Tom"
boyB.dog.name = "bigDog"
boyB.dog.weight = 100
        
print(boyA,boyA.dog)
print(boyB,boyB.dog)

控制台输出:Boy(name: "Lilei", age: 12, dog: swift_test.Dog(weight: 40, name: "littleDog")) Dog(weight: 40, name: "littleDog")
          Boy(name: "Tom", age: 12, dog: swift_test.Dog(weight: 100, name: "bigDog")) Dog(weight: 100, name: "bigDog")


结构体嵌套结构体,很显然赋值时创建了新的变量,两者是独立的,嵌套的值类型变量也会创建新的变量,这两者也是独立的。boyA和boyB 不同,dogA和dogB也不同

值类型嵌套引用类型:

把Dog改成Class

struct Boy {
    var name = "Lilei"
    var age = 12
    var dog = Dog()
}

class Dog:NSObject {
    var weight = 40
    var name = "littleDog"
}
var boyA = Boy()
var boyB = boyA
boyB.name = "Tom"
boyB.dog.name = "bigDog"
boyB.dog.weight = 100
        
print(boyA,boyA.dog,boyA.dog.name)
print(boyB,boyB.dog,boyB.dog.name)
控制台输出结果:Boy(name: "Lilei", age: 12, dog: <swift_test.Dog: 0x600001d110e0>) <swift_test.Dog: 0x600001d110e0> bigDog
             Boy(name: "Tom", age: 12, dog: <swift_test.Dog: 0x600001d110e0>) <swift_test.Dog: 0x600001d110e0> bigDog

可以看出boyB发生了变化,boyB的dog和boyA的dog为同一个对象,值类型嵌套引用类型时,赋值时创建了新的变量,两者是独立的,但嵌套的引用类型指向的是同一块内存空间,当改变值类型内部嵌套的引用类型变量值时(除了重新初始化),其他对象的该属性也会随之改变。

引用类型嵌套值类型:

Boy改成class,Dog为struct

class Boy: NSObject {
    var name = "Lilei"
    var age = 12
    var dog = Dog()
}

struct Dog {
    var weight = 40
    var name = "littleDog"
}
var boyA = Boy()
var boyB = boyA
boyB.name = "Tom"
boyB.dog.name = "bigDog"
boyB.dog.weight = 100
        
print(boyA,boyA.dog,boyA.dog.name)
print(boyB,boyB.dog,boyB.dog.name)
控制台输出:<swift_test.Boy: 0x600003853480> Dog(weight: 100, name: "bigDog") bigDog
          <swift_test.Boy: 0x600003853480> Dog(weight: 100, name: "bigDog") bigDog


引用类型嵌套值类型时,赋值时创建了新的变量,但是新变量和源变量指向同一块内存,因此改变源变量的内部值,会影响到其他变量的值。

引用类型嵌套引用类型:

class Boy: NSObject {
    var name = "Lilei"
    var age = 12
    var dog = Dog()
}

struct Dog {
    var weight = 40
    var name = "littleDog"
}
var boyA = Boy()
var boyB = boyA
boyB.name = "Tom"
boyB.dog.name = "bigDog"
boyB.dog.weight = 100
        
print(boyA,boyA.dog,boyA.dog.name)
print(boyB,boyB.dog,boyB.dog.name)
控制台输出:<swift_test.Boy: 0x6000029c4120> <swift_test.Dog: 0x6000027d0fa0> bigDog
          <swift_test.Boy: 0x6000029c4120> <swift_test.Dog: 0x6000027d0fa0> bigDog

引用类型嵌套引用类型时,赋值时创建了新的变量,但是新变量和源变量指向同一块内存,内部引用类型变量也指向同一块内存地址,改变引用类型嵌套的引用类型的值,也会影响到其他变量的值。

总结:

类和结构体的选择:

  • 该数据结构的主要目的是用来封装少量相关简单数据值;
  • 有理由预计该数据结构的实例在被赋值或传递时,封装的数据将会被拷贝而不是被引用;
  • 该数据结构中储存的值类型属性,也应该被拷贝,而不是被引用;
  • 该数据结构不需要去继承另一个既有类型的属性或者行为。

当有上面的一种情况或多种情况请选择结构体,结构体比类更简单,也就是更轻便
原文链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容