玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
在Swift中,引入了一种新的编程模式,称为面向协议编程。
创建型模式:
在swift中,Struct是一种自动克隆的值类型。因此,我们可以免费获得实现原型模式所需的行为。
而类是引用类型,在赋值过程中不会自动克隆。为了实现原型模式,类必须采用NSCopying协议。
浅拷贝只复制指向那些对象的引用,而深拷贝复制对象的引用。
为每种引用类型实现深度复制已成为一项乏味的任务。如果类包含进一步的引用类型,我们必须为每个引用属性实现原型模式。然后我们需要通过实现NSCopying协议复制整个对象图。
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
通过使用结构体和枚举,我们使我们的代码更简单,因为我们不需要实现复制逻辑。
其他回答
这个答案最初是关于结构和类之间性能的差异。不幸的是,关于我使用的测量方法有太多的争议。我把它留在下面,但请不要过多地去理解它。我认为经过这么多年,在Swift社区中,struct(以及enum)由于其简单和安全而一直是首选。
如果性能对你的应用很重要,那就自己衡量。我仍然认为大多数时候结构性能更优越,但最好的答案就像有人在评论中说的那样:这要看情况。
===旧答案===
由于结构实例是在堆栈上分配的,而类实例是在堆上分配的,因此结构有时会快得多。
但是,您应该始终自己衡量它,并根据您独特的用例进行决定。
考虑下面的例子,它演示了使用结构和类包装Int数据类型的两种策略。我使用10个重复值是为了更好地反映现实世界,其中有多个字段。
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
func + (x: Int10Class, y: Int10Class) -> Int10Class {
return IntClass(x.value + y.value)
}
func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return IntStruct(x.value + y.value)
}
使用以下方法来衡量性能
// Measure Int10Class
measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}
// Measure Int10Struct
measure("struct (10 fields)") {
var y = Int10Struct(0)
for _ in 1...10000000 {
y = y + Int10Struct(1)
}
}
func measure(name: String, @noescape block: () -> ()) {
let t0 = CACurrentMediaTime()
block()
let dt = CACurrentMediaTime() - t0
print("\(name) -> \(dt)")
}
代码可以在https://github.com/knguyen2708/StructVsClassPerformance上找到
更新(2018年3月27日):
Swift 4.0, Xcode 9.2,在iPhone 6S, iOS 11.2.6上运行Release build, Swift编译器设置为-O -全模块优化:
类版本用时2.06秒 Struct版本耗时4.17e-08秒(快了50,000,000倍)
(我不再平均多次运行,因为方差非常小,低于5%)
注意:在没有整个模块优化的情况下,差异会小很多。如果有人能指出这面旗子到底是干什么的,我会很高兴。
更新(2016年5月7日):
Swift 2.2.1, Xcode 7.3,在iPhone 6S, iOS 9.3.1上运行Release build,平均运行5次,Swift编译器设置为-O -whole-module-optimization:
类版本花费了2.159942142s struct版本耗时5.83 e -08秒(快37,000,000倍)
注意:正如有人提到的,在现实场景中,一个结构中可能会有多个字段,我已经为结构/类添加了10个字段而不是1个字段的测试。令人惊讶的是,结果变化不大。
原始结果(2014年6月1日):
(在struct/class上运行,只有1个字段,而不是10个)
在Swift 1.2、Xcode 6.3.2、iPhone 5S和iOS 8.3上运行Release版本时,平均运行超过5次
类版本花费了9.788332333s Struct版本花费0.010532942秒(快900倍)
旧结果(未知时间)
(在struct/class上运行,只有1个字段,而不是10个)
在我的MacBook Pro上发布:
类版本花费了1.10082秒 struct版本花了0.02324秒(快了50倍)
结构和类之间的相似之处。
我用简单的例子来创建主旨。 https://github.com/objc-swift/swift-classes-vs-structures
和差异
1. 继承。
结构不能在swift中继承。如果你愿意
class Vehicle{
}
class Car : Vehicle{
}
参加一个培训班。
2. 经过
Swift结构按值传递,类实例按引用传递。
语境的差异
结构常量和变量
示例(用于2014年全球开发者大会)
struct Point{
var x = 0.0;
var y = 0.0;
}
定义一个名为Point的结构体。
var point = Point(x:0.0,y:2.0)
现在如果我试着改变x,它是一个有效的表达式。
point.x = 5
但如果我定义一个点为常数。
let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.
在这种情况下,整个点是不可变常数。
如果我使用类Point代替,这是一个有效的表达式。因为在一个类中,不可变常量是对类本身的引用,而不是它的实例变量(除非那些变量定义为常量)
对于类,您获得继承并通过引用传递,而结构则没有继承并通过值传递。
有很多关于Swift的WWDC会议,其中一个会议详细回答了这个问题。确保你看了这些,因为它会让你更快地跟上语言指南或iBook。
在这些回答中没有注意到的一点是,持有类和结构的变量可以是let,同时仍然允许对对象的属性进行更改,而对于结构则不能这样做。
如果你不希望变量指向另一个对象,但仍然需要修改对象,即在有许多实例变量的情况下,你希望一个接一个地更新,这是很有用的。如果它是一个结构,你必须允许变量被重置为另一个对象使用var,因为在Swift常量值类型正确地允许零突变,而引用类型(类)不这样做。
结构是值类型,类是引用类型
值类型比引用类型快 值类型实例在多线程环境中是安全的 多线程可以改变实例,而不必担心 关于竞争条件或死锁 与引用类型不同,值类型没有引用;因此, 就是没有内存泄漏。
在以下情况使用值类型:
你希望副本有独立的状态,数据才会被使用 跨多线程的代码
在以下情况使用引用类型:
您希望创建共享的、可变的状态。
更多的信息也可以在苹果文档中找到
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
额外的信息
Swift值类型保存在堆栈中。在进程中,每个线程都有自己的堆栈空间,因此没有其他线程能够直接访问您的值类型。因此,没有竞争条件、锁、死锁或任何相关的线程同步复杂性。
值类型不需要动态内存分配或引用计数,这两者都是昂贵的操作。同时,值类型上的方法是静态分派的。就性能而言,这为值类型创造了巨大的优势。
作为提醒,这里有一个Swift列表
值类型:
结构体 枚举 元组 基本类型(Int, Double, Bool等) 集合(数组,字符串,字典,集合)
引用类型:
类 任何来自NSObject的东西 函数 关闭
推荐文章
- 如何分配一个行动UIImageView对象在Swift
- 在iOS8中使用Swift更改特定视图控制器的状态栏颜色
- 打印一个可变内存地址在swift
- 我如何使一个enum可解码在Swift?
- HTTP请求在Swift与POST方法
- 静态嵌套类在Java,为什么?
- 盎格鲁- ngcloak / ngg展示blink元素
- 如何在Python中使用方法重载?
- 将类代码分离为头文件和cpp文件
- c++中的结构继承
- 获取用户当前位置/坐标
- 'datetime'模块没有'strptime'属性
- 如何在Java中找到给定类的所有子类?
- 在SwiftUI中创建一个VStack填充屏幕宽度
- 移动文本字段时,键盘出现迅速