【问题标题】:Swift Generic Implementation of protocol throws error `Type does not conform to protocol`协议的 Swift 通用实现抛出错误“类型不符合协议”
【发布时间】:2022-01-03 10:36:00
【问题描述】:

我有 3 个模型类:

protocol IncludedItem {
    var id: Int { get }
    var text: String { get }
}
protocol PrimaryItem {
    associatedtype Included: IncludedItem

    var id: Int { get }
    var canClose: Bool { get }
    var canDelete: Bool { get }
    var canSend: Bool { get }
    var includedItems: [Included] { get }
}
protocol QuoteItem {
    var id: Int { get }
    var isSelectable: Bool { get }
}

然后我想使用工厂模式来创建项目。这是我的工厂协议:

protocol QuoteItemFactory {
    associatedtype Item: PrimaryItem

    var delegate: QuoteItemFactoryDelegate? { get set }

    func create(item: Item) -> QuoteItem
}

这是工厂协议的一个实现:

class OrderQuoteItemFactory: QuoteItemFactory {

    weak var delegate: QuoteItemFactoryDelegate?

    func create<Item: PrimaryItem>(item: Item) -> QuoteItem {
        let viewModel = OrderQuoteViewModel(quote: item)
        viewModel.delegate = self

        return DefaultQuoteItem.quote(id: item.id, viewModel: viewModel)
    }
}

但是我总是收到以下错误: Type 'OrderQuoteItemFactory' does not conform to protocol 'QuoteItemFactory'.

我做错了什么?我知道如果我这样使用它:

class OrderQuoteItemFactory<Item: PrimaryItem>: QuoteItemFactory {

    weak var delegate: QuoteItemFactoryDelegate?

    func create(item: Item) -> QuoteItem {
        let viewModel = OrderQuoteViewModel(quote: item)
        viewModel.delegate = self

        return DefaultQuoteItem.quote(id: item.id, viewModel: viewModel)
    }
}

我知道像这样使用它会很完美。但我想知道为什么我不能在函数声明中使用泛型。

【问题讨论】:

  • 只是一个小问题……你需要在这里使用协议吗?绝对有必要吗?可能是,但我只是想先检查一下。
  • @Fogmeister 是的,出于单元测试的目的,我们正在使用协议
  • 但似乎协议没有定义行为。只有属性。除了工厂。我看不出使用协议来定义属性集有什么好处。将这些作为结构会更有意义。您仍然可以在不需要协议的情况下测试具有不同属性的结构。
  • 不符合因为你的实现功能和协议定义的不一样
  • 这些是精简的协议,目的是为了在堆栈溢出问题中的可读性。模型协议在我们的项目中有更多的行为。所以没有协议不是一种选择。

标签: swift generics factory-pattern


【解决方案1】:

如果你把你的工厂协议改成这个怎么办?

protocol QuoteItemFactory {

    var delegate: QuoteItemFactoryDelegate? { get set }

    func create<Item: PrimaryItem>(item: Item) -> QuoteItem

}

我注意到(至少从您的示例中)您实际上并不需要 associatedType,因此您可以将函数本身设为通用,而不是协议。

【讨论】:

  • 这确实有效,谢谢!从来没有想过我必须像在协议中那样在函数声明中定义它。
  • 这真的取决于你的需要。如果你在一个协议中有多个函数(和/或属性)并且它们都使用相同的泛型类型,你应该使用associatedType,否则你可以让函数本身泛型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多