我需要保留Swift元类型的集合并编写一个函数,该函数将检查给定对象是否是其中之一的实例。我可以在Java中轻松做到这一点:
Class c = x.getClass();
c.isInstance(someObj)
但是,我不知道如何在Swift中做到这一点:
var isInt = 7 is Int.Type // compiles
let x = Int.self
var isInt = 7 is x // compiler error - Use of undeclared type 'x'
这甚至可以在Swift中完成吗?
不幸的是,您目前只能对is
运算符使用命名类型,还不能对其使用任意的元类型值(尽管实际上 应该 可以使用IMO )。
假设您可以控制要与之进行比较的元类型的创建,则达到相同结果的一种解决方案是创建一个包装器类型,该包装器类型具有一个初始化器,该初始化器存储一个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
会D.self
。
但是,在您的情况下这应该不成问题,因为我们只是AnyType
从编译时已知的元类型构造而来。
但是,如果您无法控制元类型的创建(即您从API获得元类型),那么您在使用元数据时所受的限制就更大了。
如@adev所说,您可以使用type(of:)
来获取给定实例的动态元类型,并使用==
运算符确定两个元类型是否等效。但是,这种方法的一个问题是它同时忽略了类的层次结构和协议,因为子类型的元类型不会与父类型的元类型进行比较。
关于类的一种解决方案是使用Mirror
,如本问答中所示:
/// 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
我们正在使用sequence(first:next:)
从动态类型x
到它可能具有的任何超类元类型来创建元类型序列。
但是,此方法仍不适用于协议。希望该语言的未来版本将提供更丰富的反射API,使您能够比较两个元类型值之间的关系。
然而,考虑到能够使用上面的知识Mirror
,我们可以用它来解除上述限制T.self == base
从我们的AnyType
包装由单独处理类元类型:
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
是一个类元类型应该是其中唯一的情况下T.self != base
,与协议,当T
是一些协议P
,T.Type
是P.Protocol
,它是协议本身的类型。目前,此类型只能保存valueP.self
。
我有一个数组,它由组成。我想对它进行迭代,并找到所有作为数组实例的元素。 如何在Swift中检查对象是否属于给定类型?
问题内容: 我有一个由组成的数组。我想遍历它,并找到所有属于数组实例的元素。 如何在Swift中检查对象是否为给定类型? 问题答案: 如果要检查特定类型,可以执行以下操作: 您可以使用“ as!” 如果类型不正确,则会引发运行时错误 您也可以一次检查一个元素:
对于这个示例: null 是否有类似这样的语句用于此检查?或者我应该使用
web3.utils.isBN()方法用来检查给定的参数是否是一个BN.js实例对象。 调用: web3.utils.isBN(bn) 参数: bn - Object: 要检查的对象 返回值 Boolean:如果参数为BN对象则返回true,否则返回false 实例代码: var number = new BN(10); web3.utils.isBN(number); > true
问题内容: 通过使用Java反射,我们可以轻松知道对象是否为数组。判断对象是否为集合(Set,List,Map,Vector …)的最简单方法是什么? 问题答案:
使用web3.utils.isBigNumber()方法检查给定的参数是否是一个 BigNumber.js对象表示的大数。 调用: web3.utils.isBigNumber(bignumber) 参数: bignumber - Object: 要检查的对象 返回值: Boolean:如果参数是BigNumber.js对象则返回true,否则返回false 实例代码: var number =