站在汇编角度深入了解 Swift(三)

334 阅读3分钟

枚举

  • 基本用法
enum Direction {
    case north, south, east, west
}
  • 关联值
    • 有时会将枚举的成员值跟其他类型的关联存储在一起,会非常有用
enum Score {
    case points(Int)
    case grade(Character)
}
var score = Score.points(96)
score = .grade("A")
switch score {
    case let .points(i):
    print("points", i)
    case let .grade(i):
    print("grade", i)
}
比如在用户密码的设置
enum Password {
    case number(Int, Int, Int, Int)
    case gesture(String) // 如果是手势,你不知道他到底是怎么画的,画了几个,用 number 存会麻烦一点
}
  • 原始值(rawValue)
    • 枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做:原始值
    • 隐式原始值
      • 如果枚举的原始值是 Int、String,Swift 会自动分配原始值
    • 递归枚举
enum Grade: String {
    case perfect = "A"
    case great = "B"
    case good = "C"
    case bad = "D"
}
递归枚举:
enum ArithExpr {
    case number(Int)
    indirect case sum(ArithExpr, ArithExpr)
    indirect case difference(ArithExpr, ArithExpr)
}

MemoryLayout

  • 可以使用 MemoryLayout 获取数据类型占用的内存大小
// 类型实际使用的大小
MemoryLayout<Int>.size
// 
// 类型分配的内存空间大小
MemoryLayout<Int>.stride
// 类型的内存对齐
MemoryLayout<Int>.alignment
let age = 10
MemoryLayout.size(ofValue: age)
MemoryLayout.stride(ofValue: age)
MemoryLayout.alignment(ofValue: age)

可选项(Optional)

  • 可选项,一般也叫可选类型,它允许将值设置为 nil
  • 在类型名称后面加个问号?来定义一个可选项
  • 可选项绑定
    • 可以使用可选项绑定来判断可选项是否包含值
    • 如果包含就自动解包,把值赋值给一个临时的常量或者变量,并返回 true,否则返加 false
if let number = Int("123") {
    
} else {
    
}
  • 空合并运算符
    • a ?? b
    • a 是可选项
    • b 跟 a 的存储类型必须相同,可以是可选,也可以是不可选
    • 如果 b 不是可选项,返回 a 时会自动解包(这一点要注意,就是返回值是不是可选主要看后面的是不是可选项)
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throw -> T?) rethrows -> T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throw -> T) rethrows -> T
if let c = a ?? b { }
等于
if a != nil || b != nil { }

guard 语句

  • 一般用来“提前退出”
  • 当使用 guard 语句进行可选项绑定时,绑定的常量,变量也能在外层作用域中使用
guard 条件 else {
    退出当前作用域
}

隐式解包

  • 在某些情况下,可选项一旦敲定值之后,就会一直拥有值
  • 在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
  • 可以在类型后面加个感叹号 ! 定义一个隐式解包的可选项
// 隐式解包的可选项
// 这个类型基本上没啥用
var num1: Int! = 10
num1 = nil
print(num1)
这个地方发打印 nil,不会发生崩溃

字符串插值

  • 可选项在字符串插值或者直接打印时,编译器会发出警告
  • 至少有3种方法消除警告
var age: Int? = 10
// String interpolation produces a debug description for an optional value; did you mean to make this explicit?
print("My age is \(age)")

// 解决方式
print("My age is \(age!)")
print("My age is \(String(describing: age))")
print("My age is \(age ?? 0)")

多重可选项

  • 可以利用 frame variable -R 查看区别
var num1: Int? = nil 
var num2: Int?? = 10 
var num3: Int?? = nil

print(num2 == num3) // false
print(num1 == num3) // false
(num2 ?? 1) ?? 2 // 2
(num3 ?? 1) ?? 2 // 1

frame variable -R 变成了
(Swift.Optional<Swift.Int>) num1 = none {
  some = {
    _value = 0
  }
}
(Swift.Optional<Swift.Optional<Swift.Int>>) num2 = some {
  some = some {
    some = {
      _value = 10
    }
  }
}
(Swift.Optional<Swift.Optional<Swift.Int>>) num3 = none {
  some = some {
    some = {
      _value = 0
    }
  }
}