如何快速检查对象是否为动态类类型?

ing

我正在实现一个名为的函数ofType该函数可以过滤出给定类型的所有元素。

这是我的代码:

class Animal {}
class Mammal: Animal {}
class Monkey: Mammal {}
class Pig: Mammal {}
class Human: Mammal {}

extension Array {
    func ofType<T>(_ metatype: T.Type) -> [T] {
        return flatMap { type(of: $0) == metatype ? $0 as? T : nil }
//      return flatMap { $0 as? T } // This is not working as the T is always the static type of the parameter, which is Animal in this example.
//      return flatMap { $0 as? metatype } // This is not working either because of the grammar restriction.
    }
}

let animals = [Monkey(), Pig(), Human(), Mammal(), Animal()]
func animalType() -> Animal.Type {
    return Mammal.self
}
animals.ofType(animalType()).count // returns 1, expect to be 4.

在Objc中,我可以isKindOf()用来检查对象是类的实例还是子类的实例。swiftis和中也有类似的操作as,但是它们后面的类型应该是静态类型,而不是动态类型值(例如,我可以写is Mammal,但是不能is Mammal.self)。

我也不能使用type参数T,因为在此示例中,T等于Animal,这不是我想要的。

您对如何实现此功能有任何想法吗?

哈米什

我个人认为@JeremyP的使用建议Mirror是最好的。尽管我会对其进行一些调整:

/// Conditionally cast `x` to a given dynamic metatype value, taking into consideration
/// class inheritance hierarchies.
func conditionallyCast<T, U>(_ x: T, to destType: U.Type) -> U? {

  if type(of: x) is AnyClass && destType is AnyClass { // class-to-class

    let isCastable = sequence(
      first: Mirror(reflecting: x), next: { $0.superclassMirror }
    )
    .contains { $0.subjectType == destType }

    return isCastable ? (x as! U) : nil
  }

  // otherwise fall back to as?
  return x as? U
}

在这里,我们正在使用它sequence(first:next:)来创建从动态类型x到它可能具有的任何超类元类型的一系列元类型(可能是我所见过的函数的第一次使用,看上去并不可怕:P)。另外,as?当我们知道我们没有在进行类到类的转换时,我们会转而进行转换,这使函数也可以使用协议元类型。

然后,您可以简单地说:

extension Sequence {
  func ofType<T>(_ metatype: T.Type) -> [T] {
    return flatMap { conditionallyCast($0, to: metatype) }
  }
}

protocol P {}
class Animal {}
class Mammal: Animal {}
class Monkey: Mammal, P {}
class Pig: Mammal {}
class Human: Mammal, P {}

let animals = [Monkey(), Pig(), Human(), Mammal(), Animal()]

let animalType: Animal.Type = Mammal.self
print(animals.ofType(animalType)) // [Monkey, Pig, Human, Mammal]

print(animals.ofType(P.self)) // [Monkey, Human]

假设您使用的是Apple平台(例如,可以访问Objective-C运行时),另一种选择是使用Objective-C元类方法isSubclass(of:)来检查给定的元类型是否相等,或者是否是另一个的子类。 :

import Foundation

/// Conditionally cast `x` to a given dynamic metatype value, taking into consideration
/// class inheritance hierarchies.
func conditionallyCast<T, U>(_ x: T, to destType: U.Type) -> U? {

  let sourceType = type(of: x)

  if let sourceType = sourceType as? AnyClass,
     let destType = destType as? AnyClass { // class-to-class

    return sourceType.isSubclass(of: destType) ? (x as! U) : nil
  }

  // otherwise fall back to as?
  return x as? U
}

之所以可行,是因为在Apple平台上,Swift类是在Obj-C类的基础上构建的-因此,Swift类的元类型是Obj-C元类对象。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章