【问题标题】:In Swift, can Types (not instances) conform to protocols?在 Swift 中,类型(不是实例)可以符合协议吗?
【发布时间】:2015-08-29 21:53:46
【问题描述】:

我有一个 ViewController,它使用我无法控制的框架中的一个类(称为 A)。 A 提供了我需要的类函数(称之为f)。我想让A 在测试中易于模拟。

所以我的想法是创建一个与A具有相同签名的协议P,扩展A以实现P,然后创建一个模拟类M,它也实现P并有一个虚拟实现的f。然后在我的测试中,我可以只做viewController.dependency = M,一切都应该是花花公子。

说起来容易做起来难,原因我希望你能帮助我理解。

在我的 viewController 中,很容易声明一个包含符合协议的实例的变量,然后将该变量重新分配给另一个符合协议的实例:

// works
var dependency: P = A()
dependency.f()
dependency = M()
dependency.f()

但是只用类型做同样的事情是行不通的:

// doesn't work
var dependency = A.self
dependency = M.self  // cannot assign value of M.Type to a value of type A.Type

// also doesn't work
var dependency: P = A.self // type A.Type does not conform to protocol P

有没有办法让它工作?我想也许我可以为dependency 使用泛型类型,但我无法弄清楚为变量赋值声明泛型类型的语法。

【问题讨论】:

  • 为什么dependency = M() 不足以满足您的需求?
  • 我宁愿避免实例化类,因为我只在它上面使用类方法。此外,Swift 不允许您在实例上调用类方法,因此 dependency = M(); dependency.f() 不会编译。我可以做dependency = M(); dependency.dynamicType.f(),但那闻起来很糟糕......而且我必须用dependency.dynamicType.f() 替换我的VC 代码中每个现有的dependency.f() 调用。

标签: swift generics types polymorphism


【解决方案1】:

如果你真的想存储类型本身,你可以使用P.Type。以下适用于 Swift 2:

protocol P {
    static func foo()
}

class A: P {
    static func foo() { print("A foo") }
}
class M: P {
    static func foo() { print("M foo") }
}

var dependency: P.Type = A.self
dependency = M.self

dependency.foo()

【讨论】:

  • 万岁!这看起来正是我想要的。遗憾的是,它在 Swift 1.2 中不起作用,因为没有实现访问协议类型的成员。但几周后,这应该会很好地工作。
【解决方案2】:

它不起作用,因为当您说var dependency = A.self 时,编译器从右侧推断出dependency 的类型是A。这意味着如果dependency 被重新分配,它只能分配给A 类类型的其他实例。当您创建具有与A 相同签名的协议P,然后是实现P 的类M,您仍然没有(也不能,因为它超出了您的控制范围) A 实现协议P。 Swift 和 Objective-C 运行时的工作方式是每个对象都包含一个指向其 type 类的指针。分配时会检查此类型,如果将右侧值分配给左侧声明,则右侧值必须在其继承层次结构中的某个位置具有左侧的类型。

一些语言(例如Ruby)具有所谓的duck typing,如果一个对象或类像鸭子一样行走,那么它 em> 一只鸭子,即使它真的不是一只鸭子的实例。这就是你在这里寻找的东西,但是 Swift(和 Objective-C)不是这样工作的。 Duck 类型是一种伪多态。它不是真的多态的。

【讨论】:

  • 对不起,我应该提到我还将扩展 A 以实现 P。我编辑了问题以澄清这一点。如果 A 确实实现了 P,编译器足够聪明,可以让我将依赖项重新分配给 M()(实例,如我的第一个示例),而不是原始类型 M
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-06
  • 2014-11-08
  • 1970-01-01
相关资源
最近更新 更多