不幸的是,你目前只能使用一个命名的类型与is
操作,你还不能使用它的任意元类型值(虽然真的你应该能够)。
假设您可以控制要比较的元类型的创建,一个解决方案可以实现相同的结果,那就是创建一个包含初始化的包装类型,该初始化存储一个闭包,该闭包对照泛型执行is
检查占位符:
struct AnyType {
let base: Any.Type
private let _canCast: (Any) -> Bool
/// Creates a new AnyType wrapper from a given metatype.
/// The passed metatype's value **must** match its static value,
/// i.e `T.self == base`.
init<T>(_ base: T.Type) {
precondition(T.self == base, """
The static value \(T.self) and dynamic value \(base) of the passed \
metatype do not match
""")
self.base = T.self
self._canCast = { $0 is T }
}
func canCast<T>(_ x: T) -> Bool {
return _canCast(x)
}
}
protocol P {}
class C : P {}
class D : C {}
let types = [
AnyType(P.self), AnyType(C.self), AnyType(D.self), AnyType(String.self)
]
for type in types {
print("C instance can be typed as \(type.base): \(type.canCast(C()))")
print("D instance can be typed as \(type.base): \(type.canCast(D()))")
}
// C instance can be typed as P: true
// D instance can be typed as P: true
// C instance can be typed as C: true
// D instance can be typed as C: true
// C instance can be typed as D: false
// D instance can be typed as D: true
// C instance can be typed as String: false
// D instance can be typed as String: false
这种方法的唯一限制是考虑到我们正在执行的is
检查T.self
,我们必须执行那T.self == base
。例如,我们不能接受AnyType(D.self as C.Type)
,因为T.self
将为C.self
,而base
将为。
但是这不应该是一个问题,因为我们只是从编译时已知的元类型构造AnyType
。
然而,如果你不拥有控制权创建元类型的(即你得到从API递了),那么你相当多的限制与您可以与他们做什么。
由于@adev says,您可以使用type(of:)
来获得给定实例的动态元类型,并使用==
运算符来确定两个元类型是否相等。然而,这种方法的一个问题是它忽略了类层次结构和协议,因为子类型元类型不会与超类型元类型进行比较。在类的情况下
一种解决方案是使用Mirror
,同样如图in this Q&A:我们使用sequence(first:next:)
通过任何超类来创建从动态类型的x
元类型的序列元类型它
/// Returns `true` iff the given value can be typed as the given
/// **concrete** metatype value, `false` otherwise.
func canCast(_ x: Any, toConcreteType destType: Any.Type) -> Bool {
return sequence(
first: Mirror(reflecting: x), next: { $0.superclassMirror }
)
.contains { $0.subjectType == destType }
}
class C {}
class D : C {}
print(canCast(D(), toConcreteType: C.self)) // true
print(canCast(C(), toConcreteType: C.self)) // true
print(canCast(C(), toConcreteType: D.self)) // false
print(canCast(7, toConcreteType: Int.self)) // true
print(canCast(7, toConcreteType: String.self)) // false
可能有。
但是这种方法仍然不能用于协议。希望该语言的未来版本将提供更丰富的反射API,以便您可以比较两个元类型值之间的关系。
然而,考虑到能够通过单独处理类元类型使用Mirror
,我们可以用它来从我们AnyType
包装解除T.self == base
上述限制上述知识:
struct AnyType {
let base: Any.Type
private let _canCast: (Any) -> Bool
/// Creates a new AnyType wrapper from a given metatype.
init<T>(_ base: T.Type) {
self.base = base
// handle class metatypes separately in order to allow T.self != base.
if base is AnyClass {
self._canCast = { x in
sequence(
first: Mirror(reflecting: x), next: { $0.superclassMirror }
)
.contains { $0.subjectType == base }
}
} else {
// sanity check – this should never be triggered,
// as we handle the case where base is a class metatype.
precondition(T.self == base, """
The static value \(T.self) and dynamic value \(base) of the passed \
metatype do not match
""")
self._canCast = { $0 is T }
}
}
func canCast<T>(_ x: T) -> Bool {
return _canCast(x)
}
}
print(AnyType(D.self as C.Type).canCast(D())) // true
的其中T.self
是类metatype应该是唯一的情况,其中T.self != base
,与协议一样,当T
是某些协议P
,T.Type
是P.Protocol
,这是pro的类型tocol本身。而目前,这种类型只能保存价值P.self
。
'var isInt = 7 is Int.Type' does not actually does not work。你的意思是'var isInt = 7 is Int' – vadian
它的工作原理是检查“type”的语法,它包含“type - > metatype-type” - https://developer.apple.com/library/content/documentation /雨燕/概念/ Swift_Programming_Language /类型。html#// apple_ref/swift/grammar/type – frangulyan
哦,对不起,通过“作品”我的意思是“编译”:) – frangulyan