| Swift
switch
匹配自定义类型的实例Equatable
协议~=
运算符~=
运算符~=
运算符与 ==
运算符~=
运算符
switch
是我们在使用 Swift 进行开发时经常用到的语句。基于 switch
,我们可以很惬意地匹配枚举类型实例。然而,可能有一些朋友像我一样不明白 switch 的匹配原理。
如果您也想弄清楚 switch 的匹配原理,那么 Ficow 希望这篇文章可以帮到您。
为了弄清楚 switch 如何工作,我们先定义一个自定义类型。不使用枚举类型可以排除干扰,因为这样可以免去编译器自动为我们做的很多工作。
先定义自定义类型,然后使用 switch 来匹配自定义类型的zopz实例:
struct Container {
let id: String
}
let container1 = Container(id: "1")
let container2 = Container(id: "2")
switch container1 {
case container2:
print("container2")
case container1:
print("container1")
default:
print("default")
}
代码写好了,然而 Xcode 却给出了错误提示:
根据这个错误提示,我们可以得到以下信息:
switch
匹配基于 ~=
运算符;switch
中进行匹配的值,其类型需要遵循 Equatable
;现在,我们其实可以有两种方式来为这个自定义类型解决 switch 匹配问题。
让 struct 遵循 Equatable
协议非常简单:
struct Container: Equatable { // 遵循 Equatable 协议
let id: String
}
let container1 = Container(id: "1")
let container2 = Container(id: "2")
switch container1 {
case container2:
print("container2")
case container1:
print("container1")
default:
print("default")
}
修改后运行这个代码片段,Xcode 上输出了:
container1
如果 Container
为 class,编译器不会自动为其生成 ==
方法。我们可以自行定义这个方法:
final class Container: Equatable {
let id: String
static func == (lhs: Container, rhs: Container) -> Bool {
return lhs.id == rhs.id
}
init(id: String) {
self.id = id
}
}
Ficow 推荐您采用这种方式来解决 switch 匹配问题,为什么呢? 答案在后文中,请您继续阅读~
~=
运算符
~=
运算符
看到 ~=
运算符,可能会有朋友想起类似这样的代码 200...299 ~= response.statusCode
。
其实,Swift 官方文档中有讲解关于 ~=
运算符的内容:
我们可以利用 ~=
运算符来进行范围匹配:
print(200...299 ~= 404)
现在,我们可以为 Container
类型自定义 ~=
运算符:
struct Container {
let id: String
static func ~= (lhs: Self, rhs: Self) -> Bool {
return lhs.id == rhs.id
}
}
也可以这样定义:
func ~= (lhs: Container, rhs: Container) -> Bool {
return lhs.id == rhs.id
}
struct Container {
let id: String
}
但是,您不能同时采用两种方式来自定义 ~=
运算符,编译器会无法确定最终的结果。
~=
运算符与 ==
运算符如果您同时定义了 ~=
运算符和 ==
运算符,编译器会采用 ~=
运算符来进行 switch 匹配:
struct Container: Equatable {
let id: String
static func ~= (lhs: Self, rhs: Self) -> Bool {
print("~=")
return lhs.id == rhs.id
}
static func == (lhs: Self, rhs: Self) -> Bool {
print("==")
return lhs.id == rhs.id
}
}
let container1 = Container(id: "1")
let container2 = Container(id: "2")
switch container1 {
case container2:
print("container2")
case container1:
print("container1")
default:
print("default")
}
运行结果如下:
~=
~=
container1
这里的 switch 用 ~=
运算符进行了 2 次比对。
~=
运算符假如,我们在框架 A 中定义了 Container 类型,然后在框架 B 中使用:
// framework A
public struct Container: Equatable {
let id: String
public static func == (lhs: Self, rhs: Self) -> Bool {
print("==")
return lhs.id == rhs.id
}
}
// framework B
let container1 = Container(id: "1")
let container2 = Container(id: "2")
switch container1 {
case container2:
print("container2")
case container1:
print("container1")
default:
print("default")
}
但是,现在我们想在框架 B 中改写 Container 类型的 switch 匹配逻辑。如果我们没有在框架 A 中为 Container 类型定义 ~=
运算符,此时我们可以直接在框架 B 中为Container 类型的扩展添加 ~=
运算符:
extension Container {
static func ~= (lhs: Self, rhs: Self) -> Bool {
print("~=")
return lhs.id == rhs.id
}
}
如果我们提前在框架 A 中为 Container 类型定义了 ~=
运算符,此时编译器将会阻止我们进行重复的定义:
不在框架 A 中提前为 Container 类型定义 ~=
运算符,这样我们就可以给调用方留下一定的决策空间。如果您不希望给调用方留下决策空间,您可以反其道而行之~ 😹
如果您需要修改 switch 中的匹配逻辑,那就让该类型遵循 Equatable 协议并重写 ==
运算符即可!
如无必要,请不要自定义 ~=
运算符。
如果您有任何建议或者疑问,欢迎您给我留言~
参考内容:
觉得不错?点个赞呗~
本文链接:Swift 中的 switch 如何匹配正确的 case,你真的明白吗?
转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog