swift4.1 系统学习十二 枚举

/*
枚举

swift的枚举类型也是一个很强大的类型,与其他语言相比,swift中枚举应用更加灵活、广泛。

例如:
像C或者OC中都有枚举类型,但是他们的枚举类型默认为整数类型int兼容。
而在swift中,我们可以自己指定一个枚举类型与哪种类型兼容。

注意:
swift中,枚举属于值类型,而不是引用类型。

*/

// 1. 枚举类型与枚举对象的一般定义
do {

// 定义简单的枚举类型
enum Type {
    case red
    case green
    case yellow
}

// 交通指示灯的枚举
enum TrafficLight {
    case red, yellow, green
}

let light = TrafficLight.green
var light2 = TrafficLight.red

// 根据类型推导,可以省略TrafficLight
light2 = .yellow
print("light = \(light), light2 = \(light2)")

switch light {
case .red:
    print("红灯")
case .yellow:
    print("黄灯")
case .green:
    print("绿灯")
}

//元组中使用枚举
let tuple: (TrafficLight, TrafficLight) = (.red, .yellow)
print(tuple.0)

}

// 2. 指定基本类型与原生值
/*
swift中,能够用于指定枚举的基本类型有:
1.各类整数类型
2.各类浮点数类型
3.字符类型
4.字符串类型

这些类型都遵循了rawrepresentable协议以及Equatable协议。

*/

do {

print("\n---------指定基本类型与原生值-----------")

enum IntEnum: Int {
    case zero
    case one = 1, two, three
    case six = 6, seven, eight
}

print("one = \(IntEnum.one.rawValue)")
print("two = \(IntEnum.two.rawValue)")
print("three = \(IntEnum.three.rawValue)")
print("six = \(IntEnum.six.rawValue)")
print("seven = \(IntEnum.seven.rawValue)")
print("eight = \(IntEnum.eight.rawValue)")

enum DoubleEnum: Double {
    case one = 1.0, two = 2.0
    case π = 3.141592653
    case e = 2.71828
}

print("one = \(DoubleEnum.one.rawValue)")
print("two = \(DoubleEnum.two.rawValue)")
print("π = \(DoubleEnum.π.rawValue)")
print("e = \(DoubleEnum.e.rawValue)")

enum CharEnum: Character {
    case apple = "🍎"
    case orange = "🍊"
    case banana = "🍌"
    case cherry = "🍒"
}

print("I like \(CharEnum.apple.rawValue), she likes \(CharEnum.cherry.rawValue).")
print("But we all like \(CharEnum.orange.rawValue).")
print("we don't like \(CharEnum.banana.rawValue).")

/*
 注意:
 如果我们用整型来指定一个枚举,那么枚举值的原生值是可以省略的,默认第一个值为0,以后每次加1.
 如果用字符串来指定枚举,也可以为枚举值省略原生值。对于制定了字符串类型的枚举中的某个枚举值
 不指定原生值,那么该枚举值的原生值就是该枚举值的标识符所构成的字符串字面量。
 
 枚举中的枚举值属于常量。
 
 */

print("\n")

do {
    enum TrafficLight: UInt {
        case red        // 默认值为0
        case yellow     // 值为1
        case green      // 值为2
    }
    
    // 使用初始化构造器来构造一个TrafficLight实例对象
    var light = TrafficLight(rawValue: 0)
    if let l = light {
        print("light is \(l)")
        print("light value is \(l.rawValue)")
    }
    
    // TrafficLight中没有值为5的枚举值,这里light得到一个空值
    light = TrafficLight(rawValue: 5)
    if light == nil {
        print("light is nil")
    } else {
        print("light is not nil")
    }
    
    enum MyNumber: Float {
        case 一 = 1.0
        case 二点五 = 2.5
        case 三 = 3.0
    }
    
    var num = MyNumber(rawValue: 2.5)
    
    if let n = num {
        print("num is \(n)")
        print("num value is \(n.rawValue)")
    }
}

}

// 3. 枚举关联值
/*
枚举关联值与原生值类似的是,它也是将某个值与指定的枚举case存放在一起。不过枚举关联值的语法对每个
case均可指定不同类型、不同个数的关联值。因此就所指定的值的类型与个数而言,枚举关联值比原生值要
灵活的多。
注意:
如果我们为一个枚举类型中的任意枚举case用上了枚举关联值,那么对于该枚举类型就不能为它指定一个
原生类型,也不能为其枚举case指定原生值。
*/
do {

print("\n")

enum MyTestEnum {
    // 这里的value1具有Void类型的关联值
    case value1(Void)
    // 这里的value2具有Int类型的关联值
    case value2(Int)
    case value3(Float, Int, Void, String)
    case value4(dict: [String: Int], array: [Double], tuple: (Int, Double))
    case value5
}

// 使用
let e1 = MyTestEnum.value1(())
print("e1 = \(e1)")

let e2 = MyTestEnum.value2(10)
print("e2 = \(e2)")

let e3 = MyTestEnum.value3(2.3, 4, (), "努力学习,天天向上")
print("e3 = \(e3)")

let e4 = MyTestEnum.value4(dict: ["one": 1, "two": 2],
                           array: [1.0, 2.0, 3.0],
                           tuple: (1, 2.0))
print("e4 = \(e4)")

func processMyTest(en: MyTestEnum) {
    switch en {
    case .value1(let v):
        print("value1 = \(v)")
    case .value2(var v):
        print("value2 = \(v)")
        v += 10
        print("new value2 = \(v)")
    case .value3(let a, let b, let c, let d):
        print("a = \(a)")
        print("b = \(b)")
        print("c = \(c)")
        print("d = \(d)")
    case .value4(let dict, let array, let tuple):
        print("dict: \(dict)")
        print("array: \(array)")
        print("tuple: \(tuple)")
        
    case .value5:
        print("这是第五个值")
    }
}

processMyTest(en: e1)
processMyTest(en: e2)
processMyTest(en: e3)
processMyTest(en: e4)

/*
 从swift3.0开始,swift引入了通过if语句以及guard语句来捕获枚举关联值的语法形式。在这种
 语法体系下,是将if或guard与case关键字连用指定一个枚举case,然后对该枚举case的关联值进行捕获。
 */
if case let .value1(value) = e1 {
    print("value1 = \(value)")
}

if case let .value2(value) = e2 {
    print("value2 = \(value)")
}

guard case .value4(let dict, var arr, let tup) = e4 else{
    exit(0)
}

print("dict = \(dict)")
arr = [2.2, 3.4, 5.9]
print("array = \(arr)")
print("tuple = \(tup)")

// 通过逗号对if中的捕获的值做进一步的判断
if case let .value2(value) = e2, value > 5 {
    print("哈哈哈哈,捕获的值大于五")
} else {
    print("哎哟")
}

// 也可以在一个if中用两个case捕获两个值,这两个case是“并且”的关系。
if case let .value2(value) = e2,
    case let .value3(x, y, z, w) = e3,
    value > 5, x > 1.0 {
    print("哇卡卡卡卡")
}

// switch-case也有丰富的匹配特性
func fetch(enum en: MyTestEnum) {
    switch en {
    case .value1(()), .value5:
        print("没有关联值或者关联值为空")
    case  .value2(10...20):
        if case let .value2(v) = en {
            print("value2 = \(v)")
        }
    case .value2(var value) where value >= 50 :
        print("哈哈哈哈")
        value -= 20
        print("value = \(value)")
    default:
        print("没有匹配的")
        break
    }
}

fetch(enum: e1)
let e5 = MyTestEnum.value5
fetch(enum: e5)

fetch(enum: e2)
fetch(enum: .value2(30))
fetch(enum: .value2(60))

fetch(enum: .value2(100))

}

// 4. 递归枚举
/*
如果一个枚举类型中某一个枚举case的其中一个关联值的类型为该枚举类型本身,那么我们称之为“递归枚举”。
我们在声明该枚举case的时候需要在它前面加上indirect关键字,该关键字指示编译器在当前枚举case中
插入了一个间接层。
*/

do {

print("\n")

enum MyEnum {
    case value1(Int)
    indirect case value2(MyEnum)
}

// 也可以在枚举的最前面加上indirect关键字,表示这里的每一个case都插入了间接层。
indirect enum indEnum {
    case value1(Int)
    case value2(indEnum)
}

// 使用举例
enum FoodAndDrink {
    case name(String)
    indirect case eat(FoodAndDrink)
    indirect case drink(FoodAndDrink)
}

func treatFoodAndDrink(item: FoodAndDrink) {
    switch item {
    case .name(let str):
        print("name = \(str)")
    case let .eat(food):
        if case let .name(foodName) = food {
            let newItem = FoodAndDrink.name("eat \(foodName)")
            treatFoodAndDrink(item: newItem)
        } else {
            print("不合法的食物")
        }
    case let .drink(drinks):
        if case let .name(drinkName) = drinks {
            let newItem = FoodAndDrink.name("drink \(drinkName)")
            treatFoodAndDrink(item: newItem)
        } else {
            print("不合法的饮品")
        }
    }
}

let orange = FoodAndDrink.name("橘子")
let wine = FoodAndDrink.name("🍷")

let eatOrange = FoodAndDrink.eat(orange)
let drinkWine = FoodAndDrink.drink(wine)

let awfulCombination = FoodAndDrink.drink(eatOrange)

treatFoodAndDrink(item: orange)
treatFoodAndDrink(item: wine)
treatFoodAndDrink(item: eatOrange)
treatFoodAndDrink(item: drinkWine)
treatFoodAndDrink(item: awfulCombination)

}

//5. 枚举中的属性和方法
/*
swift中枚举类型十分的灵活,我们还可以为其定义属性和方法,与结构体中的属性和方法类似。
不过我们在枚举中不能为它定义存储式实例属性,其他都可以。
*/
do {

print("\n")

enum MyEnum {
    case one(Int)
    case two(Int)
    case three(Int)
    
    init() {
        self = .one(0)
    }
    
    func fetchValue() -> (Int, String) {
        switch self {
        case let .one(value):
            return (value, "one")
        case .two(let value):
            return (value, "two")
        case .three(let value):
            return (value, "three")
        }
    }
    
    static func makeEnum(with value: Int) -> MyEnum {
        switch value {
        case 0..<10:
            return .one(value)
        case 20..<30:
            return .two(value)
        default:
            return .three(value)
        }
    }
    
    // 这里定义了一个计算式实例属性
    var p: Int {
        set(i){
          self = .two(i)
        }
        get {
            return self.fetchValue().0
        }
    }
    
    // 这里定义了一个存储式属性
    static var storedP: Int = 100
    
    static var p2: Int {
        set(i) {
            storedP = i
        }
        get {
            return storedP
        }
    }
}

func process(enum value: MyEnum) {
    let (value, name) = value.fetchValue()
    print("value = \(value), name is \(name)")
}

process(enum: .makeEnum(with: 5))
process(enum: .makeEnum(with: 26))
process(enum: .makeEnum(with: -1))

var e = MyEnum()
process(enum: e)

e.p = 20
print("e = \(e)")

MyEnum.storedP += 10
print("s = \(MyEnum.storedP)")

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容