swift中struct和class的区别

Structure 和Class 的差别

相同之处

1.拥有自己的属性(property)及方法(function)
2.可以自订建构子(initializer)

不同之处
  1. Structure无法继承
  2. Structure拥有成员建构子(Memberwise Initializer)
  3. Structure是Value Type , Class是Reference Type
  4. Structure不能直接修改内部属性,如果要修改必须加上mutating

大致意思就是说,虽然结构体和枚举可以定义自己的方法,但是默认情况下,实例方法中是不可以修改值类型的属性。
举个简单的例子,假如定义一个点结构体,该结构体有一个修改点位置的实例方法:

struct Point {
  var x = 0, y = 0
  
  func moveXBy(x:Int,yBy y:Int) {
    self.x += x
    // Cannot invoke '+=' with an argument list of type '(Int, Int)'
    self.y += y
    // Cannot invoke '+=' with an argument list of type '(Int, Int)'
  }
}

编译器抛出错误,说明确实不能在实例方法中修改属性值。

为了能够在实例方法中修改属性值,可以在方法定义前添加关键字 mutating

struct Point {
  var x = 0, y = 0
  mutating func moveXBy(x:Int,yBy y:Int) {
    self.x += x
    self.y += y
  }
}
var p = Point(x: 5, y: 5)
p.moveXBy(3, yBy: 3)

另外,在值类型的实例方法中,也可以直接修改self属性值。

enum TriStateSwitch {
  case Off, Low, High
  mutating func next() {
    switch self {
    case Off:
      self = Low
    case Low:
      self = High
    case High:
      self = Off
    }
  }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off”

TriStateSwitch枚举定义了一个三个状态的开关,在next实例方法中动态改变self属性的值。

当然,在引用类型中(即class)中的方法默认情况下就可以修改属性值,不存在以上问题。

7. 值类型和引用类型的区别

由于 Swift 中的 struct 为值类型,class 为引用类型,因此文中以这两种类型为代表来具体阐述

stack & heap

内存(RAM)中有两个区域,栈区(stack)和堆区(heap)。在 Swift 中,值类型,存放在栈区;引用类型,存放在堆区。

class RectClass {
    var height = 0.0
    var width = 0.0
}

struct RectStruct {
    var height = 0.0
    var width = 0.0
}

var rectCls = RectClass()
var rectStrct = RectStruct()

值类型(Value Type)

值类型,即每个实例保持一份数据拷贝。

在 Swift 中,典型的有 structenum,以及 tuple 都是值类型。而平时使用的 IntDoubleFloatStringArrayDictionarySet 其实都是用结构体实现的,也是值类型。
Swift 中,值类型的赋值为深拷贝(Deep Copy),值语义(Value Semantics)即新对象和源对象是独立的,当改变新对象的属性,源对象不会受到影响,反之同理。
在 Swift 中,双等号(== &!=)可以用来比较变量存储的内容是否一致,如果要让我们的struct 类型支持该符号,则必须遵守 Equatable协议。

extension CoordinateStruct: Equatable {
    static func ==(left: CoordinateStruct, right: CoordinateStruct) -> Bool {
        return (left.x == right.x && left.y == right.y)
    }
}

if coordA != coordB {
    print("coordA != coordB")
}

引用类型(Reference Type)

引用类型,即所有实例共享一份数据拷贝。

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

class Dog {
    var height = 0.0
    var weight = 0.0
}

var dogA = Dog()
var dogB = dogA

dogA.height = 50.0
print("dogA.height -> \(dogA.height)")
print("dogB.height -> \(dogB.height)")

// dogA.height -> 50.0
// dogB.height -> 50.0

如果声明一个引用类型的常量,那么就意味着该常量的引用不能改变(即不能被同类型变量赋值),但指向的内存中所存储的变量是可以改变的。
在 Swift 中,三等号(=== &!==)可以用来比较引用类型的引用(即指向的内存地址)是否一致。也可以在遵守 Equatable 协议后,使用双等号(==&!=)用来比较变量的内容是否一致。

函数传参

在 Swift 中,函数的参数默认为常量,即在函数体内只能访问参数,而不能修改参数值。具体来说:
1.值类型作为参数传入时,函数体内部不能修改其值
2.引用类型作为参数传入时,函数体内部不能修改其指向的内存地址,但是可以修改其内部的变量值

值类型

当值类型的变量作为参数被传入函数时,相当于创建了新的常量并初始化为传入的变量值,该参数的作用域及生命周期仅存在于函数体内。
当引用类型的变量作为参数被传入函数时,相当于创建了新的常量并初始化为传入的变量引用,当函数体内操作参数指向的数据,函数体外也受到了影响

你可能感兴趣的:(swift中struct和class的区别)