玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
结构是值类型,类是引用类型
值类型比引用类型快 值类型实例在多线程环境中是安全的 多线程可以改变实例,而不必担心 关于竞争条件或死锁 与引用类型不同,值类型没有引用;因此, 就是没有内存泄漏。
在以下情况使用值类型:
你希望副本有独立的状态,数据才会被使用 跨多线程的代码
在以下情况使用引用类型:
您希望创建共享的、可变的状态。
更多的信息也可以在苹果文档中找到
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
额外的信息
Swift值类型保存在堆栈中。在进程中,每个线程都有自己的堆栈空间,因此没有其他线程能够直接访问您的值类型。因此,没有竞争条件、锁、死锁或任何相关的线程同步复杂性。
值类型不需要动态内存分配或引用计数,这两者都是昂贵的操作。同时,值类型上的方法是静态分派的。就性能而言,这为值类型创造了巨大的优势。
作为提醒,这里有一个Swift列表
值类型:
结构体 枚举 元组 基本类型(Int, Double, Bool等) 集合(数组,字符串,字典,集合)
引用类型:
类 任何来自NSObject的东西 函数 关闭
其他回答
以下是一些值得考虑的其他原因:
struct有一个自动初始化式,你根本不需要在代码中维护它。 struct MorphProperty { var类型:MorphPropertyValueType var键:字符串 var值:AnyObject enum MorphPropertyValueType { case字符串,Int, Double } } var m = MorphProperty(类型:.Int,键:“什么”,值:“blah”)
要在类中得到这个,你必须添加初始化式,并维护初始化式…
Basic collection types like Array are structs. The more you use them in your own code, the more you will get used to passing by value as opposed to reference. For instance: func removeLast(var array:[String]) { array.removeLast() println(array) // [one, two] } var someArray = ["one", "two", "three"] removeLast(someArray) println(someArray) // [one, two, three] Apparently immutability vs. mutability is a huge topic, but a lot of smart folks think immutability -- structs in this case -- is preferable. Mutable vs immutable objects
结构和类之间的相似之处。
我用简单的例子来创建主旨。 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代替,这是一个有效的表达式。因为在一个类中,不可变常量是对类本身的引用,而不是它的实例变量(除非那些变量定义为常量)
Structure and class are user defied data types By default, structure is a public whereas class is private Class implements the principal of encapsulation Objects of a class are created on the heap memory Class is used for re usability whereas structure is used for grouping the data in the same structure Structure data members cannot be initialized directly but they can be assigned by the outside the structure Class data members can be initialized directly by the parameter less constructor and assigned by the parameterized constructor
我不会说结构体提供的功能更少。
当然,self是不可变的,除了在突变函数中,但仅此而已。
继承可以很好地工作,只要您坚持每个类都应该是抽象的或最终的。
将抽象类实现为协议,将最终类实现为结构。
struct的好处是你可以在不创建共享可变状态的情况下使你的字段可变,因为写时复制会照顾到这一点:)
这就是为什么下面例子中的属性/字段都是可变的,我不会在Java或c#或swift类中这样做。
示例继承结构,在底部名为" Example "的函数中有一点脏和直接的用法:
protocol EventVisitor
{
func visit(event: TimeEvent)
func visit(event: StatusEvent)
}
protocol Event
{
var ts: Int64 { get set }
func accept(visitor: EventVisitor)
}
struct TimeEvent : Event
{
var ts: Int64
var time: Int64
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
}
protocol StatusEventVisitor
{
func visit(event: StatusLostStatusEvent)
func visit(event: StatusChangedStatusEvent)
}
protocol StatusEvent : Event
{
var deviceId: Int64 { get set }
func accept(visitor: StatusEventVisitor)
}
struct StatusLostStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var reason: String
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
struct StatusChangedStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var newStatus: UInt32
var oldStatus: UInt32
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
func readEvent(fd: Int) -> Event
{
return TimeEvent(ts: 123, time: 56789)
}
func example()
{
class Visitor : EventVisitor
{
var status: UInt32 = 3;
func visit(event: TimeEvent)
{
print("A time event: \(event)")
}
func visit(event: StatusEvent)
{
print("A status event: \(event)")
if let change = event as? StatusChangedStatusEvent
{
status = change.newStatus
}
}
}
let visitor = Visitor()
readEvent(1).accept(visitor)
print("status: \(visitor.status)")
}
这个答案最初是关于结构和类之间性能的差异。不幸的是,关于我使用的测量方法有太多的争议。我把它留在下面,但请不要过多地去理解它。我认为经过这么多年,在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倍)
推荐文章
- 如何分配一个行动UIImageView对象在Swift
- 在iOS8中使用Swift更改特定视图控制器的状态栏颜色
- 打印一个可变内存地址在swift
- 我如何使一个enum可解码在Swift?
- HTTP请求在Swift与POST方法
- 静态嵌套类在Java,为什么?
- 盎格鲁- ngcloak / ngg展示blink元素
- 如何在Python中使用方法重载?
- 将类代码分离为头文件和cpp文件
- c++中的结构继承
- 获取用户当前位置/坐标
- 'datetime'模块没有'strptime'属性
- 如何在Java中找到给定类的所有子类?
- 在SwiftUI中创建一个VStack填充屏幕宽度
- 移动文本字段时,键盘出现迅速