Swift泛型-协议不符合协议

时间:2018-07-04 17:11:34

标签: swift generics swift4

我试图获得一个实现一组协议的容器,这些协议作为参数传递给原始容器上的函数。

struct Container {
  let someProperty: String
  let otherProperty: String
}

// Subcontainers
protocol Base {}
protocol SomePropertyContainer: Base {
  var someProperty: String { get }
}

protocol OtherPropertyContainer: Base {
  var otherProperty: String { get }
}

extension Container: SomePropertyContainer, OtherPropertyContainer {}


// Sub Container Provisioning Protocol
protocol SubContainerProviderProtocol {
  func subContainer<T: Base>(protos: T.Type) -> T?
}

extension Container: SubContainerProviderProtocol {

  func subContainer <T: Base>(protos: T.Type) -> T? {
    return self as? T
  }
}

// Example container
let subContainerProvider: SubContainerProviderProtocol = Container(someProperty: "Why does this not work!", otherProperty: "Seriously.")

启动并运行它可以让我将ContainerProviderProtocol注入消费者,同时让他们可以自己指定他们实际想要的SubContainer

例如一个只对someProperty感兴趣的类可能看起来像这样

// Example Container Provider consumer
class SomeClass {

  let subContainerProvider: SubContainerProviderProtocol

  init(subContainerProvider: SubContainerProviderProtocol) {
    self.subContainerProvider = subContainerProvider
  }

  func printSomeProperty() {
    let someProperty = subContainerProvider
      .subContainer(protos: SomePropertyContainer.self)?
      .someProperty
    print(someProperty)
  }
}

// Example call
let someClass = SomeClass(subContainerProvider: subContainerProvider)
someClass.printSomeProperty() // "Why does this not work!"

对于依赖注入和可测试性,此解决方案将是不可思议的。

但是限制T: Base导致编译器错误

  

在参数类型'SomePropertyContainer.Protocol'中,'SomePropertyContainer'不符合预期的类型'Base'

未指定与Base的一致性将进行编译,但也允许将任何类型作为T传递。

我在附加协议中尝试了关联类型,但是还没有弄清楚。尽管这个问题非常有趣,但我的想法已用尽。

可能与https://bugs.swift.org/browse/SR-55相关(但不完全相同)

1 个答案:

答案 0 :(得分:0)

这是问题所在:在某些时候,您必须开始使用实际类型,而不仅仅是协议。您的行:

func container<T: Base>(protos: T.Type) -> T?

告诉编译器您将给此函数一个类型,通常为T,它符合协议Base,而不是另一个协议。您需要这样的东西:

class SPC: SomePropertyContainer {
    var someProperty: String = ""
}

class SomeClass {
    let containerProvider: ContainerProviderProtocol
    init(containerProvider: ContainerProviderProtocol) {
        self.containerProvider = containerProvider
    }

    func printSomeProperty() {
        let someProperty = containerProvider
            .container(protos: SPC.self)?
            .someProperty
        print(someProperty)
    }
}

SPC是一种符合SomePropertyContainer协议的类型,该协议本身也符合Base协议,因此这就是您的代码所期望的。

相关问题