提问者:小点点

如何以通用方式知道具有关联值的枚举的类型?


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

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

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)
}

现在,用冷血分析,这似乎完全是黑魔法。

开关没有参数怎么比较东西?

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

像这样的东西

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

这将不起作用。Xcode将需要从.3开始的参数。

因为我不明白到目前为止我有什么,我不知道如何做到这一点。


共3个答案

匿名用户

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

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)
}

匿名用户

Swift枚举很特别,有很多别人没有的特性。然而,它是一个枚举,就像C样式的枚举和整数一样简单。枚举的实例只是一个值。

在你的例子中,

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
    }
}

我猜上面是你要求的。

通知,

具有包装值的底层枚举实例有一个哈希用于比较。因此,如果您想使用==相等运算符执行相等,编译器会警告您您的枚举需要符合Hasable。

例如,如果你想比较,

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

MyEnum.three(user: "SomeValue") == MyEnum.three(user: "AnotherValue")

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

在您的情况下,具有包装值的枚举,包装值需要是可Has可处理的。由于String已经是Has可处理的,因此您只需要声明可散列一致性。

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

读数

语言指南#枚举

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

匿名用户

据我所知,你想知道为什么你的转换声明

        case (.three, .three):
            return true

作品找到,但是

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

导致编译器错误。

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

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

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

这正是switch语句所做的-它忽略分配的值。

如果要调用函数,需要传入枚举的具体实例,由于用户被isOfType忽略,因此在以下语句中使用虚拟值将起作用:

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