服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Swift - 深入解析Swift中switch语句对case的数据类型匹配的支持

深入解析Swift中switch语句对case的数据类型匹配的支持

2020-12-25 15:55bestswifter Swift

这篇文章主要介绍了Swift中switch语句对case的数据类型匹配的支持,Swift中switch...case语句支持多种数据类型的匹配判断,十分强大,需要的朋友可以参考下

Swift可以对switch中不同数据类型的值作匹配判断:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var things = Any[]()
 
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name:"Ghostbusters", director:"Ivan Reitman"))
 
for thing in things {
 switch thing {
 case 0 as Int:
 println("zero as an Int")
 case 0 as Double:
 println("zero as a Double")
 case let someInt as Int:
 println("an integer value of (someInt)")
 case let someDouble as Double where someDouble > 0:
 println("a positive double value of (someDouble)")
 case is Double:
 println("some other double value that I don't want to print")
 case let someString as String:
 println("a string value of "(someString)"")
 case let (x, y) as (Double, Double):
 println("an (x, y) point at (x), (y)")
 case let movie as Movie:
 println("a movie called '(movie.name)', dir. (movie.director)")
default:
 println("something else")
}
}
 
// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of"hello"
// an (x, y) point at 3.0, 5.0
// a movie called 'Ghostbusters', dir. Ivan Reitman

这里面会根据thing的值进行匹配,到对应的case当中。

今天突然想到一个问题,让我觉得有必要总结一下switch语句。我们知道swift中的switch,远比C语言只能比较整数强大得多,但问题来了,哪些类型可以放到switch中比较呢,对象可以比较么?

官方文档对switch的用法给出了这样的解释:

Cases can match many different patterns, including interval matches, tuples, and casts to a specific type.
也就是说除了最常用的比较整数、字符串等等之外,switch还可以用来匹配范围、元组,转化成某个特定类型等等。但文档里这个including用的实在是无语,因为它没有指明所有可以放在switch中比较的类型,文章开头提出的问题依然没有答案。

我们不妨动手试一下,用switch匹配对象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A {
 
}
 
var o = A()
var o1 = A()
var o2 = A()
 
switch o {
case o1:
  print("it is o1")
case o2:
  print("it is o2")
default:
  print("not o1 or o2")
}

果然,编译器报错了:“Expression pattern of type 'A' cannot match values of type 'A'”。至少我们目前还不明白“expression pattern”是什么,怎么类型A就不能匹配类型A了。

我们做一下改动,在case语句后面加上let:

?
1
2
3
4
5
6
7
8
switch o {
case let o1:
  print("it is o1")
case let o2:
  print("it is o2")
default:
  print("not o1 or o2")
}

OK,编译运行,结果是:it is o1。这是因为case let不是匹配值,而是值绑定,也就是把o的值赋给临时变量o1,这在o是可选类型时很有用,类似于if let那样的隐式解析可选类型。没有打出it is o2是因为swift中的switch,只匹配第一个相符的case,然后就结束了,即使不写break也不会跳到后面的case。

扯远了,回到话题上来,既然添加let不行,我们得想别的办法。这时候不妨考虑一下switch语句是怎么实现的。据我个人猜测,估计类似于用了好多个if判断有没有匹配的case,那既然如此,我们给类型A重载一下==运算符试试:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {}
 
func == (lhs: A, rhs: A) -> Bool { return true }
 
var o = A(); var o1 = A() ;var o2 = A()
 
switch o {
case o1:
  print("it is o1")
case o2:
  print("it is o2")
default:
  print("not o1 or o2")
}

很显然,又失败了。如果这就能搞定问题,那这篇文章也太水了。报错信息和之前一样。可问题是我们已经重载了==运算符,为什么A类型还是不能饿匹配A类型呢,难道switch不用判断两个变量是否相等么。

switch作为一个多条件匹配的语句,自然是要判断变量是否相等的,不过它不是通过==运算符判断,而是通过~=运算符。再来看一段官方文档的解释:

An expression pattern represents the value of an expression. Expression patterns appear only in switch statement case labels.
以及这句话:

The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator.
第一句解释了之前的报错,所谓的“express pattern”是指表达式的值,这个概念只在switch的case标签中有。所以之前的报错信息是说:“o1这个表达式的值(还是o1)与传入的参数o都是类型A的,但它们无法匹配”。至于为什么不能匹配,答案在第二句话中,因为o1和o的匹配是通过调用标准库中的~=运算符完成的。

所以,只要把重载==换成重载~=就可以了。改动一个字符,别的都不用改,然后程序就可以运行了。Swift默认在~=运算符中调用==运算符,这也就是为什么我们感觉不到匹配整数类型需要什么额外处理。但对于自定义类型来说,不重载~=运算符,就算你重载了==也是没用的。

除此以外,还有一种解决方法,那就是让A类型实现Equatable协议。这样就不需要重载~=运算符了。答案就在Swift的module的最后几行:

?
1
2
@warn_unused_result
public func ~=<T : Equatable>(a: T, b: T) -> Bool

Swift已经为所有实现了Equatable协议的类重载了~=运算符。虽然实现Equatable协议只要求重载==运算符,但如果你不显式的注明遵守了Equatable协议,swift是无法知道的。因此,如果你重载了==运算符,就顺手标注一下实现了Equatable协议吧,这样还有很多好处,比如SequenceType的split方法等。

最后总结一句:

能放在switch语句中的类型必须重载~=运算符,或者实现Equatable协议。

延伸 · 阅读

精彩推荐
  • Swiftswift相册相机的权限处理示例详解

    swift相册相机的权限处理示例详解

    在iOS7以后要打开手机摄像头或者相册的话都需要权限,在iOS9中更是更新了相册相关api的调用,那么下面这篇文章主要给大家介绍了关于swift相册相机权限处...

    hello老文12682021-01-08
  • SwiftSwift 基本数据类型详解总结

    Swift 基本数据类型详解总结

    在我们使用任何程序语言编程时,需要使用各种数据类型来存储不同的信息。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。在声明...

    Lucky_William4672021-12-26
  • Swift浅谈在Swift中关于函数指针的实现

    浅谈在Swift中关于函数指针的实现

    这篇文章主要介绍了浅谈在Swift中关于函数指针的实现,是作者根据C语言的指针特性在Swifft中做出的一个实验,需要的朋友可以参考下...

    Swift教程网4372020-12-21
  • SwiftSwift中排序算法的简单取舍详解

    Swift中排序算法的简单取舍详解

    对于排序算法, 通常简单的, 为大家所熟知的有, 选择排序, 冒泡排序, 快速排序, 当然还有哈希, 桶排序之类的, 本文仅比较最为常见的选择, 冒泡和快排,文...

    Castie111012021-01-10
  • SwiftSwift网络请求库Alamofire使用详解

    Swift网络请求库Alamofire使用详解

    这篇文章主要为大家详细介绍了Swift网络请求库Alamofire的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    lv灬陈强56682021-01-06
  • Swift详解Swift 之clipped是什么如何用

    详解Swift 之clipped是什么如何用

    这篇文章主要介绍了详解Swift 之clipped是什么如何用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    iCloudEnd8532021-05-28
  • SwiftSwift算法之栈和队列的实现方法示例

    Swift算法之栈和队列的实现方法示例

    Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列。下面这篇文章就来给大家详细介绍了Swift算法之栈和队列的实现方法,需要...

    李峰峰10002021-01-05
  • Swift分析Swift性能高效的原因

    分析Swift性能高效的原因

    绝大多数公司选择Swift语言开发iOS应用,主要原因是因为Swift相比Objc有更快的运行效率,更加安全的类型检测,更多现代语言的特性提升开发效率;这一系...

    louis_wang9092021-01-16