如何以泛型方式知道具有关联值的enum的类型?



几天前,我问过这个问题。

这个绝妙的解决方案是这样的:

enum MyEnum {
case one
case two
case three(user: String)

func isOfSameType(_ other: MyEnum) -> Bool {
switch (self, other) {
case (.one, .one):
return true
case (.two, .two):
return true
case (.three, .three):
return true
default:
return false
}
}
}

var array: [MyEnum] = []
func add(_ value: MyEnum) {
if array.contains(where: { value.isOfSameType($0) }) { return }
array.append(value)
}

现在,冷静地分析一下,这似乎完全是黑魔法。

如果没有参数,开关如何比较事物?

但是现在我需要检查stack上的最后一个元素是否属于three

之类的
if array!.last.isOfType(.three) {
}

这行不通。Xcode将需要.three.

中的参数因为到目前为止我还不明白我所拥有的,所以我不知道该怎么做。

Swift Enum是非常特殊的,有很多其他类型的没有的特性。然而,它是一个枚举,就像c风格的枚举一样简单,就是整数。enum的实例只是一个值。

在你的例子中,

enum MyEnum {
case one
case two
case three(user: String)
}

假设你有一个数组

let arrayMyEnum: [MyEnum] = [.one, .two, .three(user: "Mike"), .two, .three(user: "John")]

那么,你可以,

// basic approach
arrayMyEnum.contains {
switch $0 {
case .three(let user):
return true
default:
return false
}
}
// Using optional pattern
arrayMyEnum.contains {
if case .three(let user) = $0 {
return true
} else {
return false
}
}

或者正如你在评论中所描述的那样,你不关心包装的值,而只是想检查实例是否为特定情况。然后你可以忽略被包装的值

arrayMyEnum.contains {
switch $0 {
case .three:
return true
default:
return false
}
}
arrayMyEnum.contains {
if case .three = $0 {
return true
} else {
return false
}
}

我猜以上就是你想要的。

,

底层,具有包装值的枚举实例具有用于比较的哈希值。因此,如果你想使用==相等操作符执行相等操作,编译器会警告你,你的enum需要符合Hashable。

例如,如果要比较,

enum MyEnum: Hashable {
case one
case two
case three(user: String)
}
MyEnum.three(user: "SomeValue") == MyEnum.three(user: "AnotherValue")

Swfit类型的枚举本身是可哈希的,是隐式可哈希的。

在你的例子中,带包装值的enum,包装值需要是可哈希的。因为String已经是可哈希的,你只需要声明哈希一致性。

只有当包装的类型不是Hashable时,您才需要自己编写==hasher方法,这在大多数情况下非常直接。

阅读

语言指南#枚举

语言参考#枚举大小写模式,可选模式。

您只需要使枚举符合Equatable并比较相关值是否相等:

enum MyEnum: Equatable {
case one
case two
case three(user: String)
}

var array: [MyEnum] = []
func add(_ value: MyEnum) {
if array.contains(value) { return }
array.append(value)
}

add(.one)
add(.one)
array
add(.three(user: "a"))
add(.three(user: "b"))
add(.three(user: "a"))
array[0]  // one
array[1]  // three(user: "a")
array[2]  // three(user: "b")

检查最后一个元素是否为case . 3:

if case .three = array.last {
print(true)
}

据我所知,您想知道为什么使用

的switch语句
case (.three, .three):
return true

可以找到,但是

if array!.last.isOfType(.three) { /* ... */ }

导致编译器错误。

这个问题是由于switch语法有点特殊(模式匹配),不能在函数调用中使用。

由于您似乎想忽略user的值,您可以执行以下操作:

if case .three = array!.last { /* ... */ }

,这正是switch语句所做的——它忽略了赋值。

如果你想调用一个函数,你需要传入你的enum的concrete实例,并且由于用户被isOfType忽略,在下面的语句中使用一个值将工作:

if array!.last.isOfSameType(.three(user:"dummy")) { /* ... */ }

请试试:

实现三个协议Equatable, Hashable和CustomStringConvertible

public enum MyEnum: Equatable, Hashable, CustomStringConvertible {
case one
case two
case three(user: String)

//    CustomStringConvertible
// create unique string for each case
public var description: String {
switch self {
case .one:
return "one"

case .two:
return "two"

case .three:
return "three"

}
}

//    Hashable
public func hash(into hasher: inout Hasher) {
hasher.combine(self.description)
}

//    Equatable
public static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
var array: [MyEnum] = []

func add(_ value: MyEnum) {

// option one
//    if array.last!.hashValue == value.hashValue {
//        return
//    }

// option two
if array.contains(value) {
return
}

array.append(value)
}
add(.one)
add(.one)
add(.two)
add(.two)
add(.three(user: "hello"))
add(.three(user: "hi"))
for item in array {
print(item.description)
}

结果打印:

one
two
three

相关内容

  • 没有找到相关文章

最新更新