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

时间:2018-01-06 12:02:17

标签: swift enums metatype

给出方法

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

   return 3
}

使用如下

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

enumCaseCount(ofType: SimpleEnum.self)

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

可以通过这种方式测试类

class Test {}
Test.self is AnyClass // returns true

3 个答案:

答案 0 :(得分:2)

为了它的乐趣,作为(变通方法)黑客,我们可以实例化T的实例,并使用Mirror对其进行运行时检查,特别是{ {3}}财产。在我们继续之前,我们注意到我们只会将其用于调试目的

  

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

我还要指出,我们在这里真正追逐我们的尾巴,因为我们在编译时使用运行时来查询已知的内容(至少是编译器)。

无论如何,首先,我将enumCaseCount(...)重命名为isEnum(...),因为此问题仅涵盖查询元组类型是否为enum。对于查询给定enum的案例数量的类似(稍微脆弱)的黑客攻击,请参阅:

现在,T中的通用占位符isEnum(...)只知道它是符合How do I get the count of a Swift enum?的类型,它没有给我们任何直接的实例化方法。 T的实例(如果Hashable蓝图,例如,初始值设定项init(),我们可以很容易地构造T实例运行时内省的实例。相反,我们将为单个T实例(Hashable)手动分配原始内存,将其绑定到TUnsafeMutableRawPointer.allocate(bytes:alignedTo:)),最后取消分配内存(bindMemory(to:capacity:))一旦我们完成了对绑定内存指针引用的实例的运行时内省。至于运行时内省,我们只需使用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
}

使用示例:

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

答案 1 :(得分:1)

正如其他人所说,在Swift中没有很好的非hacky方法。但是,它是Sourcery的一个示例用例,一个元编程库(这意味着它会分析您的代码以生成其他代码)。您编写Stencil模板来描述其行为,并将其作为Xcode中的构建阶段执行。它可以为项目中找到的任何枚举自动生成此代码。

AutoCases enum example

答案 2 :(得分:1)

要检查某种类型是否实际上是枚举,可以使用:

func isEnum<T>(_ type: T.Type) -> Bool {
    let ptr = unsafeBitCast(T.self as Any.Type, to: UnsafeRawPointer.self)
    return ptr.load(as: Int.self) == 513
}

您可以像这样简单地使用它:

enum MyEnum {}
struct MyStruct {}
class MyClass {}

isEnum(MyEnum.self)   // this returns true
isEnum(MyStruct.self) // this returns false
isEnum(MyClass.self)  // this returns false

在您的示例中,您将像这样使用它:

func enumCaseCount<T: Hashable>(ofType type: T.Type) -> Int {
   isEnum(T.self) // returns true if enum
   return 3
}