Swift中强大的模式匹配

Swift中的模式匹配语法是一个亮点,Swift里switch比OC里面强大很多,switch的主要特性就是模式匹配,所以本文会主要结合switch来讲强大好用的模式匹配。

swift中模式有以下几种:

  • 通配符模式(Wildcard Pattern)
  • 标识符模式(Identifier Pattern)
  • 值绑定模式(Value-Binding Pattern)
  • 元组模式(Tuple Pattern)
  • 枚举用例模式(Enumeration Case Pattern)
  • 可选模式(Optional Pattern)
  • 类型转换模式(Type-Casting Pattern)
  • 表达式模式(Expression Pattern)

通配符模式

如果在Swift中使用了_通配符,就表示你是使用了通配符模式,_用于匹配并忽略任何值。这又分为两种情况:

  • _:完全不关心这个值,甚至可以为nil
    enum Moblie {
        case Man(name: String, age: Int, height: Int?)
        case Woman(name: String, age: Int, height: Int?)
    }
    
    let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
    
    switch Roy {
    case .Man(name: let name, age: let age, height: let height):
        print("\(name) -- \(age) -- \(String(describing: height))")
    default:
        break
    }

  • _?:虽然这个值不使用,但是要确保是非nil的
    switch Roy {
    case .Man(name: let name, age: _, height: _?):
        print("\(name)")
    default:
        break
    }

标识符模式

匹配一个具体的值或者定义变量或者常量时候,可以认为变量名和常量名就是一个标识符模式,用于接收和匹配一个特定类型的值。这种比较简单。

let i = 21 // i 就是一个标识符模式

值绑定模式

值绑定在if语句和switch语句中用的较多

    switch Roy {
    case .Man(name: let name, age: let age, height: let height):
        print("\(name) -- \(age) -- \(String(describing: height))")
    default:
        break
    }

也可以这样写

    switch Roy {
    case let .Man(name: name, age: age, height: height):
        print("\(name) -- \(age) -- \(String(describing: height))")
    default:
        break
    }

元组模式

    let error = (statusCode: 404, statusMessage: "Not Found")
            
    switch error {
    case (let code, _):
        print("\(code)")
    default:
        break
    }

这个是在详解 Swift 模式匹配中看到的示例,很赞

    let age = 23
    let job: String? = "Operator"
    let payload: AnyObject = NSDictionary()
    
    switch (age, job, payload) {
      case (let age, _?, _ as NSDictionary):
      print(age)
      default: ()
    }

枚举用例模式

    enum Result {
        case error(String)
        case image(UIImage)
        case data(Data)
    }
    
    let result = Result.error("没有找到资源")
    
    switch result {
    case let .image(image):
        print(image)
    case let .data(data):
        print(data)
    case .error(let err):
        print("Failed; error message is \(err)")
    }

可选模式

可选模式就是包含可选变量定义模式,在 if casefor caseswitch-case 会用到。注意 if case letif let的区别

    // 使用可选模式匹配
    if case let x? = someOptional {
        print(x)
    }
    
    let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5]
    // 只匹配非 nil 的元素
    for case let number? in arrayOfOptinalInts {
        print("Found a \(number)")
    }
    // Found a 2
    // Found a 3
    // Found a 5
    let count: Int? = 5
    switch count {
    case 1?:
      print("1")
    case 3?:
      print("3")
    case 5?:
      print("5")
    case _:
      print("nil")
    default:
      break
    }

类型转换模式

  • is类型:匹配右手边内容的运行时类型(或者类型的子类)。它会做类型转换但是不关注返回值。所以你的case块不知道所匹配的类型是什么。
  • as类型:和is模式做同样的匹配操作,但是如果成功的话会把类型转换到左侧指定的模式中。
    let a: Any = 5
    switch a {
        // 这会失败因为它的类型仍然是 `Any`
    // 错误: binary operator '+' cannot be applied to operands of type 'Any' and 'Int'
    case is Int: print (a + 1)
    // 有效并返回 '6'
    case let n as String: print ("result: "+n)
    default: ()
    }

表达式模式

可以把 switch 的值和实现了 ~= 操作符的表达式进行匹配

  • 范围匹配
    let point = (1, 2)
    switch point {
    case (0, 0):
        print("(0, 0) is at the origin.")
    case (-2...2, -2...2):
        print("(\(point.0), \(point.1)) is near the origin.")
    default:
        print("The point is at (\(point.0), \(point.1)).")
    }
  • 自定义~=运算符
    struct Score {
        let Math: Int
        let Chinese: Int
        let English: Int
    }
    
    func ~= (pattern: Int, value: Score) -> Bool {
        return value.Math > pattern && value.Chinese > pattern && value.English > pattern
    }
    
    
    let score = Score(Math: 80, Chinese: 40, English: 70)
            
    switch score {
    case 90:
        print("优秀")
    default:
        break
    }

其他用法

在条件中使用where语句

    let people = (age: 27, name: "karl")
    switch people {
    case (let age, _) where age > 30:
        print(age)
    default:
        break
    }

if case let

当只有一个条件的时候,用switch会显得冗余,直接用if case let会使代码读起来更便捷。

   let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
           
   if case let .Man(name, _, _?) = Roy {
       print(name)
   }

for case let

let array: [Any?] = [1,2,nil,4,54,65,76, ""]

输出这个数组里面大于10的数字

常规写法

for item in array {
  if let element = item as? Int, element > 10 {

  }
}

for case写法

for case let x? as Int? in array where x > 10 {
  print(x)
}

用Moblie作为例子

let Roy = Moblie.Man(name: "Roy", age: 27, height: 178)
let Kelly = Moblie.Woman(name: "Kelly", age: 28, height: nil)
let Frank = Moblie.Man(name: "Frank", age: 29, height: nil)
let Arvin = Moblie.Man(name: "Arvin", age: 28, height: nil)

let moblieArray = [Roy, Kelly, Frank, Arvin]
    
for case let .Man(name, age, _?) in moblieArray where age < 29 {
    print(name)
}

参考文章:

Swift中的模式匹配
详解 Swift 模式匹配

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

推荐阅读更多精彩内容