【问题标题】:Pass dynamic type as parameter传递动态类型作为参数
【发布时间】:2018-03-02 23:54:28
【问题描述】:

我想要完成的是将对象的动态类型作为参数传递给泛型函数。我可以通过type(of:) 看到我想要的正确类型,但我无法将它作为参数传递,因为在泛型函数中我仍然得到静态类型。 这是我想做的一个例子:

protocol SomeUsefulProtocol {}

struct MyType1: SomeUsefulProtocol {}
struct MyType2: SomeUsefulProtocol {}

let objects: [SomeUsefulProtocol] = [MyType1(), MyType2()]

let someClosureToWorkWithMyType: Any = { (object: MyType1) in
    //Do some great things
}

func someMethod<T>(type: T.Type, object: Any) {
    typealias ClosureType = (T) -> Void

    if let closure = someClosureToWorkWithMyType as? ClosureType, let object = object as? T {
        closure(object)
    }
}

for object in objects {
    someMethod(type: type(of: object), object: object)
}

这里我希望在对象的类型为“MyType1”时调用闭包 someClosureToWorkWithMyType,但在方法内部,对象的类型是静态类型 (SomeUsefulProtocol)。

【问题讨论】:

  • 您的代码似乎比它需要的要复杂一些。你为什么将关闭声明为Any?其次,您可以简单地迭代数组并为 MyType1 的对象执行闭包,无需中间函数。

标签: swift generics reflection swift-protocols


【解决方案1】:

这里的问题是object 被声明为协议SomeUsefulProtocol 的一个实例。协议的实例不是任何特定的具体类型,而是可能是许多具体类型之一。

Swift 的泛型系统在编译时需要已知的具体类型来创建正确的特化。有许多博客文章和 StackOverflow 问题和答案深入探讨了尝试同时使用 Swift 协议和 Swift 泛型的技巧(而且往往是徒劳的)。

在您的具体示例中,您的方法可以通过以下两种方式之一工作:要么不将 object 声明为协议实例,而是使其成为具体类型,例如

let object: MyType = MyType()

或保持原样声明,但在将其传递给您的函数时将其转换为具体类型,例如

(object as? MyType).flatMap{ someMethod(type: type(of: $0), object: $0) }

【讨论】:

  • 我已经编辑了这个问题。该解决方案将不起作用,因为在我使用该对象时,确切的类型(动态类型)是未知的。这就是我使用泛型和类型转换的原因。我唯一的问题是将对象的动态类型传递给方法。
  • @Ruben 这是关键问题:Swift 泛型要求在编译时 知道任何泛型参数或参与者的精确 具体类型。这是因为编译器需要发出专门的类型/函数实现并知道如何相应地分配内存。这就是为什么它们不能很好地与协议一起工作,这些协议有效地消除了具体类型并使其具有多态性。所以简短的回答是:没有办法让 Swift 泛型与没有显式具体类型的参数一起工作,这些参数在编译时是已知的。
猜你喜欢
  • 1970-01-01
  • 2021-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
相关资源
最近更新 更多