美文网首页
从 枚举(enum) 到 Swift

从 枚举(enum) 到 Swift

作者: overla5 | 来源:发表于2019-11-09 08:50 被阅读0次

    枚举入门

    来,小明 给我说说什么是枚举
    
    小明: 你把手举起来
    
    然后呢?
    
    小明: 你看我的手 举没举 ?
    

     

    基本定义

    枚举作为 Swift 的 一等类型, 我们正好可以通过枚举, 来 一一列举 Swift 其它 强有力的 类型

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

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

    enum SwiftType {
        case protocol
        case enum
        case struct
        case class
        case tuple
        case function
    }
    

     
    当然它们也可以抱团相拥在一起, 以 逗号 来互相敬畏

    enum ProgrammingLanguage {
        case protocol, enum, struct, class, tuple, function
    }
    

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

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

     

    原始值 rawValue

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

    它们的原始值(rawValue)也可以是其它类型

    enum RawValueType {
        case 整形
        case 字符
        case 字符串
        case 浮点型
    }
    

    但是它们必须拥有一个共同的类型原始值唯一
     

    像 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 ,还请多多指教!!
    

    相关文章

      网友评论

          本文标题:从 枚举(enum) 到 Swift

          本文链接:https://www.haomeiwen.com/subject/tcywbctx.html