Swift5 _03 枚举、可选项

枚举

枚举的基本用法

enum Direction {
  case north
  case south
  case east
  case west
}
等价于
enum Direction {
  case north,south,east,west
}

var dir = Direction.west
dir = Direction.east
dir = .north
print(dir) /// north


switch dir {
  case .north:
    print("north")
  case .south:
    print("south")
  case .east:
    print("east")
  case .west:
    print("west")
}

关联值
有时会将枚举的成员值其他类型的关联存储在一起,会非常有用

enum Score {
  case points(Int)
  case grade(Character)
}

var score = Score.points(96)
score = .grade("A")

switch score {
  case let .points(i):
    print(i,"points")
  case let .grade(i):
    print("grade",i)
}
/// 打印结果:grade A
enum Date {
  case digit(year: Int , month: Int , day: Int)
  case string(String)
}

var date = Date.digit(year: 2020, month:12, day: 12)
date = .string("2020-01-01")

switch date {
  case .digit(let year,let month, let day) :
    print(year,month,day)
  case let .string(value)
    print(value)
}

原始值(Raw Value)
枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做: 原始值

/// : String 是指枚举关联原始值的类型
enum PokerSuit : String {
  case spade = "黑桃"
  case heart = "红心"
  case diamond = "方块"
  case club = "梅花"
 }
var suit = PokerSuit.spade
print(suit)    /// spade
print(suit.rawValue)  /// 黑桃
print(PokerSuit.club.rawValue)  /// 梅花

隐式原始值
如果枚举的原始值是Int,String,Swift会自动分配原始值

/// 如果原始值的类型是String,那么Swift默认会将其`成员值`作为`原始值字符串`
enum Direction : String {
  case north
  case south
  case east
  case west
}
等价于
enum Direction : String {
  case north  = "north"
  case south  = "south"
  case east = "east"
  case west = "west"
}
enum Season : Int {
  case spring, summer , autumn , winter
}

print(Season.spring.rawValue)  /// 0
print(Season.summer.rawValue)  /// 1
print(Season.autumn.rawValue)  /// 2
print(Season.winer.rawValue) /// 3


enum Season : Int {
  case spring = 1, summer , autumn = 4 , winter
}
print(Season.spring.rawValue)  /// 1
print(Season.summer.rawValue)  /// 2
print(Season.autumn.rawValue)  /// 4
print(Season.winer.rawValue) /// 5

MemoryLayout

可以使用MemoryLayout获取数据类型占用的内存大小

var age = 10

MemoryLayout.size
MemoryLayout.stride
MemoryLayout.alignment

等价于

MemoryLayout.size(ofValue:age)
MemoryLayout.stride(ofValue:age)
MemoryLayout.alignment(ofValue:age)
enum Password {
  case number(Int, Int , Int, Int)
  case other
}

MemoryLayout.size          /// 33 ,  实际使用的空间大小
MemoryLayout.stride    /// 40 ,分配占用的空间大小
MemoryLayout.alignment  /// 8 , 对齐参数

可选项Optional

可选项,一般也叫可选类型,它允许将值设置为nil
类型名称后面加个问号? 来定义一个可选项

/// 这样定义一个变量,是没有默认值的,而且不可以将其设置为nil
var age: Int

/// age 是可选类型,默认值是nil
var age: Int?
等价于
var age: Int? = nil

var name: String? = "Jack"
name = nil


var array = [1,15,40,29]
func get(_ index: Int) -> Int? {
  if index < 0 || index >= array.count {
    return nil
  }
  return array[index]
}
print(get(1))  /// Optional(15)
print(get(-1))  /// nil

强制解包

可选项是对其他类型的一层包装,可以将它理解为一个盒子
如果为nil,那么它就是个空盒子
如果不是nil,那么盒子里装的是: 被包装类型的数据

如果要从可选项中取出被包装的数据(将盒子里装的东西取出来),需要使用感叹号!进行强制解包

var age: Int?  = 10
let ageInt: Int = age!
ageInt += 10

如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误

let number = Int("123")
if number != nil {
  print("字符串转换整数成功: \(number!)")
}else{
  print("字符串转换整数失败")
}

可选项绑定

可以使用可选项绑定来判断可选项是否包含值
如果包含就自动解包,把值赋给一个临时的常量(let)或者 变量(var),并返回true ,否则返回false

if let number = Int("123") {
  print("字符串转整数成功:\(number)")
  /// number 是强制解包之后的Int值
  /// number 作用域仅限于这个大括号
} else {
  print("字符串转换整数失败")
}
enum Season : Int {
  case spring = 1, summer, autumn, winter
}

if let season = Season(rawValue: 6) {
  switch season {
    case .spring : 
      print("the season is spring")
    default : 
      print("the season is other")
  }
} else {
  print("no such season")
}
if let first = Int("4") {
  if let second = Int("42") {
    if first < second && second < 100 {
      print("\(first) < \(second) < 100")
    }
  }
}

等价于

/// 注意: 这里是用逗号, 隔开的,不能使用 && ,因为这里使用可选项绑定
/// 这是语法规定的
if let first = Int("4"),
    let second = Int("42"),
      first < second && second < 100 {
        print("\(first) < \(second) < 100")
      }

while 循环中使用可选项绑定

/// 遍历数组,将遇到的正数都加起来,如果遇到了负数或非数字,停止遍历
var strs = ["10","20","abc","-10","30"]

var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
  sum += num 
  index += 1
}
print(sum)

空合并运算符??

a ?? b
a 是 可选项
b 是 可选项 或者 不是可选项
b 跟 a 的存储类型必须相同
如果 a 不为 nil, 就返回a
如果 a 为 nil, 就返回b
如果 b 不是可选项,返回a时会自动解包

let a: Int? = 1
let b: Int? = 2
let c = a ?? b  // 结果:c是Int? , Optional(1)

let a: Int? = nil
let b: Int? = 2
let c = a ?? b  // 结果:c是Int? , Optional(2)

let a: Int? = nil
let b: Int? = nil
let c = a ?? b  // 结果:c是Int? , nil

let a: Int? = 1
let b: Int = 2
let c = a ?? b  // 结果:c是Int , 1

let a: Int? = 1
let b: Int = 2
let c = a ?? b ?? 3  // 结果:c是Int , 1

?? 跟 if let 配合使用

let a : Int? = nil
let b : Int? = 2
if let c = a ?? b {
  print(c)
}
/// 类似于 if a != nil || b != nil 

if let c=a , let d =b {
  print(c)
  print(d)
}
/// 类似于 if a != nil && b != nil 
/// 实例

func login(_ info: [String : String]) {
  let username: String
  if let tmp = info["username"] {
    username = tmp
  }else {
    print("请输入姓名")
    return
  }
  let password : String
  if let tmp = info["password"] {
      password = tmp
  }else {
    print("请输入密码")
    return
  }

  print("用户名: \(username)  密码: \(password) ",“登录ing”)
}

隐式解包

在某种情况下,可选项一旦被设定值之后,就会一直拥有值
在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
可以在类型后面加个感叹号! 定义一个隐式解包的可选项

/// num1 依然是一个可选项,不过当它遇到Int类型的时候,会自动解包
/// 注意: num1 不能为nil,因为nil解包会报错

let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
  print(num1 + 6)
}

guard 语句

guard语句的条件为false时,就会执行大括号里面的代码
guard 语句的条件为true时,就会跳出guard语句
gurad语句特别适合用来“提前退出”

gurad 条件 else {
  /// do something...
  退出当前作用域
  /// return 、break、continue、throw error
}

当guard语句进行可选项绑定时,绑定的常量、变量也能在外层作用域中使用

func login(_ info: [String: String]) {
  guard let username = info["username"] else {
    print("请输入用户名")
    return
  }

  guard let pasword = info["password"] else {
     print("请输入密码")
     return
  }

  print("用户名: \(username)  密码: \(password) ",“登录ing”)
 }

你可能感兴趣的:(Swift5 _03 枚举、可选项)