Swift通用枚举函数检查大小写

时间:2022-01-23 08:57:00

Is it possible to create a Generic enum function that returns a boolean if an enum instance is an enum Type or does this already exist and I don't know about it?

是否可以创建一个泛型枚举函数,它返回一个布尔值,如果枚举类型是枚举类型,或者已经存在,我不知道?


I use a ton of enums in my projects. Very often I define enums with associated values.

我在项目中使用了大量的枚举。我经常用关联的值定义枚举。

Simple Example:

简单的例子:

enum Mode {
    case new
    case edit(Record)    // Record is a struct type
}

I regularly check whether an enum instance is a specific enum case. Many times, however, I don't need to check the associated value. I'm looking for a convenient way to check the case. Each method I know about has a downside.

我经常检查enum实例是否是特定的enum案例。但是,很多时候,我不需要检查关联的值。我在找一个方便的方法来检查这个箱子。我知道的每个方法都有缺点。

Method 1-2: If Case pattern matching or Switch case

let myMode = Mode.edit
if case Mode.edit(_) = myMode {
    // do something
}

switch mode {
case .edit:
    // do something
default:
    break    
}

Downsides:

缺点:

  • Cannot assign the check to a variable directly. Must do so in closure
  • 无法将支票直接分配给变量。必须这样做吗?
  • cannot use this pattern directly as an argument to a function
  • 不能将此模式直接用作函数的参数

Method 3-5 Implement an enum function or check value of computed property or Equatable protocol

Downsides:

缺点:

  • must be implemented for each enum type
  • 每个enum类型必须实现吗?

Instead, I'm looking for a way to write a Generic function that returns a boolean if a enum instance matches an enum case. Something that can be written once and be applied to all enums. Similar to Generic function for Struct and Class Types:

相反,我正在寻找一种方法来编写一个泛型函数,如果enum实例与enum实例匹配,它将返回一个布尔值。可以写一次并应用于所有enum的内容。类似于结构和类类型的泛型函数:

func checkType<T, S> (a: T, _: S.Type) -> Bool {

    return a is S   // though you could just call this directly
}

1 个解决方案

#1


1  

I don't think there is a good idiomatic way of achieving this. The only thing that comes to mind is to compare the raw memory of your enum instance against a dummy instance with the desired case.

我不认为有什么好方法可以达到这个目的。我唯一想到的是将enum实例的原始内存与所需的虚拟实例进行比较。

As we don't care about associated values we would only need to require their respective last byte to be identical.

因为我们不关心关联的值,我们只需要要求它们各自的最后一个字节是相同的。

func unsafeEqualityLastByteOnly<A>(_ lhs: A, _ rhs: A) -> Bool {
    var (lhs, rhs) = (lhs, rhs)

    let offset = MemoryLayout<A>.size - 1

    return withUnsafePointer(to: &lhs) { lhsPtr in
        withUnsafePointer(to: &rhs) { rhsPtr in
            let lhsPtr = unsafeBitCast(lhsPtr, to: UnsafeRawPointer.self)
            let rhsPtr = unsafeBitCast(rhsPtr, to: UnsafeRawPointer.self)

            return memcmp(lhsPtr.advanced(by: offset), rhsPtr.advanced(by: offset), 1) == 0
        }
    }
}

This is far from pretty, but it works.

这远非漂亮,但确实有效。

enum Test {
    case a(Int)
    case b(Int)
}

let a1 = Test.a(1)
let a2 = Test.a(2)

let b1 = Test.b(1)
let b2 = Test.b(2)

unsafeEqualityLastByteOnly(a1, a1) // true
unsafeEqualityLastByteOnly(a1, a2) // true
unsafeEqualityLastByteOnly(a2, a2) // true

unsafeEqualityLastByteOnly(b1, b1) // true
unsafeEqualityLastByteOnly(b1, b2) // true
unsafeEqualityLastByteOnly(b2, b2) // true

unsafeEqualityLastByteOnly(a1, b1) // false
unsafeEqualityLastByteOnly(a1, b2) // false
unsafeEqualityLastByteOnly(a2, b1) // false
unsafeEqualityLastByteOnly(a2, b2) // false

Use your own judgement to decide whether or not this is something you want in your project. It's obviously not a technique that should be recommended without any reservations.

用你自己的判断来决定这是否是你在你的项目中想要的东西。这显然不是一种应该毫无保留地推荐的技术。

#1


1  

I don't think there is a good idiomatic way of achieving this. The only thing that comes to mind is to compare the raw memory of your enum instance against a dummy instance with the desired case.

我不认为有什么好方法可以达到这个目的。我唯一想到的是将enum实例的原始内存与所需的虚拟实例进行比较。

As we don't care about associated values we would only need to require their respective last byte to be identical.

因为我们不关心关联的值,我们只需要要求它们各自的最后一个字节是相同的。

func unsafeEqualityLastByteOnly<A>(_ lhs: A, _ rhs: A) -> Bool {
    var (lhs, rhs) = (lhs, rhs)

    let offset = MemoryLayout<A>.size - 1

    return withUnsafePointer(to: &lhs) { lhsPtr in
        withUnsafePointer(to: &rhs) { rhsPtr in
            let lhsPtr = unsafeBitCast(lhsPtr, to: UnsafeRawPointer.self)
            let rhsPtr = unsafeBitCast(rhsPtr, to: UnsafeRawPointer.self)

            return memcmp(lhsPtr.advanced(by: offset), rhsPtr.advanced(by: offset), 1) == 0
        }
    }
}

This is far from pretty, but it works.

这远非漂亮,但确实有效。

enum Test {
    case a(Int)
    case b(Int)
}

let a1 = Test.a(1)
let a2 = Test.a(2)

let b1 = Test.b(1)
let b2 = Test.b(2)

unsafeEqualityLastByteOnly(a1, a1) // true
unsafeEqualityLastByteOnly(a1, a2) // true
unsafeEqualityLastByteOnly(a2, a2) // true

unsafeEqualityLastByteOnly(b1, b1) // true
unsafeEqualityLastByteOnly(b1, b2) // true
unsafeEqualityLastByteOnly(b2, b2) // true

unsafeEqualityLastByteOnly(a1, b1) // false
unsafeEqualityLastByteOnly(a1, b2) // false
unsafeEqualityLastByteOnly(a2, b1) // false
unsafeEqualityLastByteOnly(a2, b2) // false

Use your own judgement to decide whether or not this is something you want in your project. It's obviously not a technique that should be recommended without any reservations.

用你自己的判断来决定这是否是你在你的项目中想要的东西。这显然不是一种应该毫无保留地推荐的技术。