不幸的是,你目前只能使用一個命名的類型與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