检查给定的元类型是否是枚举

Bin*_*ian 5 enums swift metatype

给定方法

func enumCaseCount<T: Hashable>(ofType type: T.Type) -> Int {
    // Needed check if type is an enum type

   return 3
}
Run Code Online (Sandbox Code Playgroud)

使用如下

private enum SimpleEnum: String {
    case a = "A"
    case b = "B"
    case c = "C"
}

enumCaseCount(ofType: SimpleEnum.self)
Run Code Online (Sandbox Code Playgroud)

知道如何检查给定的元类型是否是枚举吗?


可以通过这种方式测试类

class Test {}
Test.self is AnyClass // returns true
Run Code Online (Sandbox Code Playgroud)

dfr*_*fri 4

为了它的乐趣,作为一种(解决方法) hack,我们可以实例化 的实例T并使用Mirror,特别是它的displayStyle属性对其执行运行时自省。在继续之前,我们注意到我们只会将其用于调试目的

镜子由游乐场和调试器使用。

我还要指出,我们实际上是在追尾,因为我们求助于运行时来查询编译时已知的事物(至少是编译器已知的)。


无论如何,首先,我将重命名enumCaseCount(...)isEnum(...),因为这个问题仅涉及查询元类型是否是 an enum。对于类似(有点脆弱)的黑客来查询给定的案例数enum,请参阅:

现在,通用占位符TinisEnum(...)只知道它是符合 的类型Hashable,这并没有为我们提供任何直接的方法来实例化 的实例T(如果是Hashable蓝图,例如初始化程序init(),我们可以轻松构造 的实例T对其执行运行时内省)。相反,我们将手动为单个T实例分配原始内存 ( UnsafeMutableRawPointer.allocate(bytes:alignedTo:)),将其绑定到T( bindMemory(to:capacity:)),最后deallocate(bytes:alignedTo:)在完成对由指向绑定的指针引用的实例的运行时内省后释放内存 ( )记忆。至于运行时自省,我们只是用来Mirror检查它是否displayStyle存在enum

func isEnum<T: Hashable>(_: T.Type) -> Bool {
    var result = false
    // Allocate memory with size and alignment matching T.
    let bytesPointer = UnsafeMutableRawPointer.allocate(
        bytes: MemoryLayout<T>.size,
        alignedTo: MemoryLayout<T>.alignment)
    // Bind memory to T and perform introspection on the instance
    // reference to by the bound memory.
    if case .some(.`enum`) = Mirror(reflecting:
        bytesPointer.bindMemory(to: T.self, capacity: 1).pointee)
        .displayStyle {
        print("Is an enum")
        result = true
    } else { print("Is not an enum") }
    // Deallocate the manually allocate memory.
    bytesPointer.deallocate(bytes: MemoryLayout<T>.size,
                            alignedTo: MemoryLayout<T>.alignment)
    return result
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

enum SimpleEnum { case a, b, c }

enum SimpleStrEnum: String {
    case a = "A"
    case b = "B"
    case c = "C"
}

enum SimpleExplicitIntEnum: Int { case a, b, c }

struct SimpleStruct: Hashable {
    let i: Int
    // Hashable
    var hashValue: Int { return 0 }
    static func ==(lhs: SimpleStruct, rhs: SimpleStruct) -> Bool { return true }
}

print(isEnum(SimpleEnum.self))            // true
print(isEnum(SimpleStrEnum.self))         // true
print(isEnum(SimpleExplicitIntEnum.self)) // true
print(isEnum(SimpleStruct.self))          // false
Run Code Online (Sandbox Code Playgroud)