我必须在 didSet 内的开关语句中两次解包可选


var test: Int! {
didSet {
switch test {
case 1: print("one")
case 2: print("two")
default: print("something else")
}
}
}
var toupleTest: (one: Int, two: Int)! {
didSet {
switch toupleTest! {
case (1, 1): print("one, one")
case (2, 2): print("two, two")
default: print("something else")
}
}
}
test = 2 // prints "two"
toupleTest = (1, 1) // prints "one, one"

在 Int 值的情况下,一切都很好.
但是在元组的情况下,我必须解开两次可选包!否则我有一个编译错误.
看起来 swift 逻辑不一致。还是错误?

这是不一致的,但原因有点复杂。

为了使类型在switch语句中使用,它需要符合Equatable

使用新的struct类型查看此示例:

struct MyType: Equatable {
let x: Int

static func ==(lhs: MyType, rhs: MyType) -> Bool {
return lhs.x == rhs.x
}
}
var mytypeTest: MyType! {
didSet {
switch mytypeTest {
case MyType(x: 1): print("one")
case MyType(x: 2): print("two")
default: print("something else")
}
}
}
mytypeTest = MyType(x: 1)

这有效,但是如果您从MyType中删除: Equatable,则会出现错误运算符函数"~="要求"MyType"符合"等值"。

所以这是第一个提示。switch使用~=运算符进行比较,并且类型必须Equatable

那么如果我们尝试使用 '~=' 比较两个元组会发生什么:

if (1, 3) ~= (1, 3) {
print("same")
}

这给出了错误:类型"(Int,Int("不能符合"Eequalable";只有结构/枚举/类类型可以符合协议

因此,这意味着元组不能在switch中使用,我们知道这不是真的。

嗯,元组在switch中有一个特殊的位置,它们用于模式匹配以解构元组。 例如:

let a = (1, 2)
switch a {
case let (x, y):
print("the tuple values are (x) and (y)")
}

这将打印the tuple values are 1 and 2.

因此,元组在switch中使用,用于使用模式匹配进行匹配和解构。 因此,您可以在switch中使用元组,即使它不符合Equatable,因为它具有这种特殊用途。

您的示例的问题在于模式与您正在打开的类型不匹配。 值的类型为(Int, Int)?,模式为(Int, Int)

那么,如何在不强制解开元组值的情况下解决此问题? 通过向模式添加?来更改模式以匹配:

var toupleTest: (one: Int, two: Int)! {
didSet {
switch toupleTest {
case (1, 1)?: print("one, one")
case (2, 2)?: print("two, two")
default: print("something else")
}
}
}

注意:添加?也适用于您的Int示例:

var test: Int! {
didSet {
switch test {
case 1?: print("one")
case 2?: print("two")
default: print("something else")
}
}
}

但这不是必需的,因为IntEquatable的,而且 Swift 知道如何将Int?与平等Int进行比较。

我认为这是因为元组在 swift 中是值类型。默认类型也是默认类型。基本上,您的解包什么都不做,您只需标记此值将是非可选的。但是要访问其中的值,您必须解开可选的元组并到达值

最新更新