从 枚举(enum) 到 Swift ,初学者就刚恰好

枚举入门git

来,小明 给我说说什么是枚举

小明: 你把手举起来

而后呢?

小明: 你看个人手 举没举 ?
复制代码

 

基本定义

枚举做为 Swift 的 一等类型, 咱们正好能够经过枚举, 来 一一列举 Swift 其它 强有力的 类型swift

首先写出枚举的 2种表达方式bash

它们被放在一个大括号里,纵向排列,互不干扰app

enum SwiftType {
    case protocol
    case enum
    case struct
    case class
    case tuple
    case function
}
复制代码

  固然它们也能够抱团相拥在一块儿, 以 逗号 来互相敬畏工具

enum ProgrammingLanguage {
    case protocol, enum, struct, class, tuple, function
}
复制代码

掌握以上几种类型,即可呼风唤雨ui

那么我就以初学者的姿态记录一下枚举吧spa

 

原始值 rawValue

Swift 的枚举 并不会像 OC 那样固定的赋予一个默认的整形值,并无所谓的从上到下,原始值 也不是 从0到5debug

它们的原始值(rawValue)也能够是其它类型code

enum RawValueType {
    case 整形
    case 字符
    case 字符串
    case 浮点型
}
复制代码

可是它们必须拥有一个共同的类型原始值惟一  ip

像 ProgrammingLanguage 这种没有指明原始值类型的枚举 没有原始值,

它们的实例 也无法用点语法 点出 rawValue

 

赋予原始值类型

若是想像OC 同样 拿到原始值,咱们能够指定类型

enum ProgrammingLanguage: Int {
    case Swift 
    case OC
    case Python
    case Java
}
复制代码

一旦咱们给定整形,也就意味着它们默认是从0开始的

 

下一个枚举的原始值 = 上一个枚举的原始值 + 1

 

⚠️只有整形是这样 依次累加哦  

var p = ProgrammingLanguage.OC.rawValue

print(p)
// 打印 1,由于 Swift 默认是 0
复制代码

如今 咱们作一些改动

enum ProgrammingLanguage: Int {
    case Swift = 2
    case OC
    case Python = 6
    case Java
}

var p = ProgrammingLanguage.OC.rawValue
print(p)
// 打印 3,由于 Swift 是 2

print(p1)
// 打印 7,由于 Python 是 6
复制代码

 

字符串隐式原始值

若是咱们指定枚举类型 是 String,那么其中的 case 对应的rawValue,就是它们的字符串化

enum Song: String {
    case 夏日漱石
    case 有暖气
}

var s = Song.夏日漱石.rawValue
debugPrint(s)

// 打印 字符串 "夏日漱石"
复制代码

 

rawValue 初始化

枚举能够经过原始值 rawValue 来初始化

enum Drinking: String {
    case cola
    case sprite
    case orangeJuice
}

var dg = Drinking(rawValue: "cola")

# 注意: 这里的dg 是可选型,由于 枚举并不知道 你传进去的 rawValue 是否存在

# 下面会说到,这种方式的实例化 是一个可失败的构造器
复制代码

 

Switch 匹配枚举值

通常来讲,咱们写出枚举 是为了区分不一样的case,和 OC 同样 Switch就成了咱们 匹配枚举值的 首选

Swift 的 枚举状况 分为2种

// 登陆方式的枚举
enum LoginWay {
    case Apple
    case QQ
    case Wechat
    case Weibo
}

let way = LoginWay.Apple
复制代码

第一种: 穷尽全部

* 遍历全部大括号内的case,一个不漏,不用写defult

* 若是遗漏了,而且没有defult 将会报错

switch way {
case .Apple:
    print("apple")
case .QQ:
    print("qq")
case .Wechat:
    print("wechat")
case .Weibo:
    print("weibo")
}

// 打印 "apple"
复制代码

第二种: 投其所好

* 只展现部分我关心的case,其他的 用 defult 表明

* 不用展现所有

switch way {
case .QQ:
    print("qq")
case .Weibo:
    print("weibo")
default:
    print("其它")
}

// 打印 "其它"
复制代码

* 关联值

什么是关联值 ?

咱们来看一个栗子

// 定义一个不一样交通工具 上班时间 ,咱们能够自由选择上班方式

enum OnTheWayTime {
    case bicycle(Int)     // Int    类型关联值    的  bicycle
    case taxi(Int)        // Int    类型关联值    的  taxi
    case bus(time: Int)   // Int    类型关联值    的  bus
    case horse(String)    // String 类型关联值    的  horse
}

var t = OnTheWayTime.bicycle(60)
// "实例化一个变量",而且给成员变量 bicycle 关联 Int值 60
复制代码

若是咱们想要 改变 t ,也就是咱们的出行方式

在t 的类型已经肯定的状况下,咱们能够不用带枚举名称,直接 .

t = .taxi(30)

 

咱们去 Switch 遍历 这个枚举,看一下关联值使用方式

switch t {
case .bicycle(let bic):
    print("骑自行车上班要 \(bic) 分钟")
case .taxi(let ti):
    print("打出租车上班要 \(ti) 分钟")
case .bus(time: let bs):
    print("坐公交上班要 \(bs) 分钟")
case .horse(let str):
    print("骑马要 \(str)")
}

能够提取关联值 用 "let / var" 修饰
经过值绑定,生成的 "局部变量"  就与 "关联值" 相链接
复制代码

 

修改t ,再去遍历,t 是能够任意变化的

t = .horse("好久")

打印:骑马要好久

 

optional 关联值

optional(可选型) 是比较经常使用的枚举,它的成员值 .some 也是经过关联值的方式

var age: Int?
age = 17

switch age {
case .none:
  print("age 为 nil")
case .some(let value):
  print("age 的值是: \(value)")
}
// 打印: age 的值是 17
复制代码

 

问题

关联值 的成员 有rawValue 吗?

答案是 没有的

由于 rawValue 是听从了 RawRepresentable 协议,协议中经过 associatedtype来关联 rawValue, associatedtype 是用来定义 在协议中使用的 关联类型,虽然这个关联类型是不肯定的,可是它们是统一的。

有关联值的 枚举,它们的类型是不统一的,因此没法使用 rawValue

 

结论

  • 咱们能够把关联值当作一个变量,关联以后的成员值 是可变的
  • 关联值 和 原始值不一样,原始值的值 从开始 就是肯定的,没法改变  
  • 关联值 没法使用 rawValue 属性,由于它们类型没法 统一

 

枚举的构造过程

构造过程:保证新实例在第一次使用前完成正确的初始化

除了在上述中 提到 的 rawValue 初始化,是一种隐藏了 init? 的可失败的 构造器以外,

咱们还能够自定义 不隐藏的 init? 初始化器

enum Drinking: String {
    case cola
    case sprite
    case orangeJuice
    
    init?(str: String) {
        switch str {
        case "c":
            self = .cola
        case "s":
            self = .sprite
        case "o":
            self = .orangeJuice
        default:
        return nil
        }
    }
}

下次2种方式均可以完成初始化:

let dg = Drinking(rawValue: "cola")
// print(dg!)  cola

let gc  = Drinking(str: "s") 
// print(gc!)  sprite
复制代码

 

问题

咱们不是列举了全部的状况,case "c","s","o",能够不用在init后面 加 问号吗?能够不加defult 吗?

答案是 不能够的

虽然 咱们列举的case 是 一一俱全的,可是咱们并不能保证 初始化构造的时候 你会传入什么东西,因此这个构造是可能会失败的,结果是可选的,因此就得加 ? ,就须要defult来 处理不存在的 case

 

枚举的属性

计算属性

来,看栗子

吃开封菜的时候到了

经过对 kfc 的点单方式 单点/套餐 咱们写了一个枚举,外界经过调用实例的 description 来得到 描述

enum KFCFood {
    case familyFood(Int)
    case Other(String, String, String)
    
    var description: String {
        switch self {
        case .familyFood(let num):
            return "今天我一我的吃了 \(num) 个全家桶"
        case let .Other(s1, s2, s3):
            return "今天晚餐吃了\(s1) \(s2) 还有 \(s3)"
        }
    }
}

var k = KFCFood.familyFood(2)
print(k.description) // 今天我一我的吃了 2 个全家桶


k = .Other("汉堡", "可乐", "薯条")
print(k.description) // 今天晚餐吃了汉堡  可乐 还有 薯条
ps: 可乐 汉堡 和薯条 不也是套餐吗 你个low 狗
复制代码

咱们定义了一个 KFC 的枚举

经过 关联值 + 计算属性 来 存储 以及 得到 description

 

小结

  • 由于这里有关联值,因此无法经过 rawValue的方式 初始化,也就是说若是经过关联值初始化,就意味着 获得的实例 都是存在的,switch 里 不须要 defult

case let .Other(s1, s2, s3):

  • 若是说关联值得个数 不止一个,那么咱们使用的时候,能够把修饰 局部变量的let/var 提到 最前面

 

扩展 和协议 的第二种写法

咱们也能够 使用协议(Protocols)和协议扩展(Protocol Extension)

高大上 有没有

经过协议 以及 协议扩展能够更好的 将 成员值 与 属性/方法 实现分离开, 代码也就天然而然的 通俗易懂了

enum KFCFood {
    case familyFood(Int)
    case Other(String, String, String)
}

protocol EatFood {
    var description: String { get }
}

extension KFCFood: EatFood {
    var description: String {
         switch self {
         case .familyFood(let num):
             return "今天我一我的吃了 \(num) 个全家桶"
         case let .Other(s1, s2, s3):
             return "今天晚餐吃了\(s1) \(s2) 还有 \(s3)"
         }
     }
}
复制代码

 

枚举的方法

咱们能够像在类中定义方法同样,在枚举中咱们也能够定义方法

enum Song: String {
    case chinese
    case english
    func getName() -> String {
        switch self {
        case .chinese:
            return "chinese"
        case.english:
            return "english"
        }
    }
}

let s  = Song.chinese
print(s.getName())
// 打印 chinese
复制代码

那么若是咱们想在方法内改变 自身的值呢?

好比 咱们想中文歌 和 英文歌 来回切换

相似这样

enum Song: String {
    case chinese
    case english
     func getChange() {
        switch self {
        case .chinese:
            self = .english
            // 切换英文歌
        case.english:
            self = .chinese
            // 切换中文歌
        }
    }
}

当咱们编译的时候 就会发现 报错了

# Cannot assign to value: 'self' is immutable
复制代码

这个时候咱们就用到 mutating了

mutating

func 前面加上 mutating ,咱们就能够在值类型中 改变自身的值了

总结

参考连接

SwiftGG

若是有新的知识 我还会补充进来

以上都是我我的的一些见解,可能有不对的地方

都是第一次学Swift ,还请多多指教!!
复制代码
相关文章
相关标签/搜索