模式匹配第三弹: 自定义的模式匹配和语法糖

作者:Olivier Halligon,原文链接,原文日期:2015-04-24
译者:walkingway;校对:小锅;定稿:numbbbbb

在模式匹配系列文章第一弹第二弹中,我们已经看到关于 switch 搭配很多类型的用法包括元组tuples),范围(Range),字符串(String),符号(Character)和一些其他类型。但是假如我们使用自定义的类型和模式匹配,又能擦出怎样的火花呢?

Switch 和模式匹配操作符

如果你在 switch 实例中这样写 case 1900..<2000,那么 Swift 如何比较 switch 入口的单值与下面的范围?

答案非常简单:Swift 使用了 ~= 操作符。当你在 case 中使用 Range<I> 时,switch 可以对 I 进行匹配,这是因为 Range<I>I 二者之间定义了 ~= 操作符:

func ~=<I : ForwardindexType where I : Comparable>(pattern: Range<I>,value: I) -> Bool

事实上,如果你写 switch someI加上 case arangeOfI 语句时,Swift 会尝试调用 arangeOfI ~= someI 来做匹配操作(该表达式会返回一个 Bool 来通知是否匹配成功)

这就意味着你可以为自己的类型定义相同的操作符 ~=,这样就能保证这些自定义类型可以在 switch/case 语句中使用,我们也可以用相同的方式使用 Range

让你的自定义类型响应模式匹配

我们构造一个自定义的结构体:

struct Affine {
  var a: Int
  var b: Int
}

func ~= (lhs: Affine,rhs: Int) -> Bool {
  return rhs % lhs.a == lhs.b
}

switch 5 {
case Affine(a: 2,b: 0): print("Even number")
case Affine(a: 3,b: 1): print("3x+1")
case Affine(a: 3,b: 2): print("3x+2")
default: print("Other")
}

最终打印的结果是 3x+2

值得注意的一点是:在使用自定义类型时,Swift 不知道 switch 是否穷尽了所有可能。例如,即使我们添加case Affine(a: 2,b: 1)case Affine(a: 2,b: -1) 这两个子句,来覆盖到每一个正整数和负整数的情况,Swift 还是会强迫我们使用 default: 语句。

此外需要注意,不要搞混了参数的顺序:~= 的第一个参数(通常称为 lhs,译指左手边)是你将要在 case 子句中使用的对象,第二个参数(通常称为 rhs,译指右手边)是你使用 switch 传入的对象。

~= 的一些其他用途

~= 还有很多其他用途。

例如,我们可以在第二弹中登场的 Book 结构体中添加如下代码

func ~= (lhs: Range<Int>,rhs: Book) -> Bool {
  return lhs ~= rhs.year
}

现在测试一下:

let aBook = Book(title: "20,000 leagues under the sea",author: "Jules Vernes",year: 1870)
switch aBook {
case 1800..<1900: print("19th century book")
case 1900..<2000: print("20th century book")
default: print("Other century")
}

当然我不鼓励这样使用,将 Book 直接与一段整数范围比较并不能很清晰地展现我们的意图:『其实是想与 book 的出版年份进行比较』。更好的方式是在 switch 中直接传入 aBook.year。但我们举这个例子只是为了展示 ~= 操作符的强大(另一个原因是我暂时想不到更好的例子了

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...