协议(protocol)的 Swift 3 泛型/关联类型限制

标签 swift generics protocols

我有一个通用协议(protocol):

protocol SectionType {
    associatedtype I: Equatable
    associatedtype T: Equatable
    var info: I? { get }
    var items: [T] { get }
}

和它的数组扩展:

/// Offers additional method(s) to process SectionType list.
extension Array where Element: SectionType {
    /// Dummy comparision method. Implementation is not that relevant but just to employ Equatable.
    /// - Parameter to: Another array of sections.
    /// - Returns: True if first info and first elemements in both arrays exist and both are equal.
    func dummyCompare(with otherArray: [Element]) -> Bool {
        guard
            let first = self.first,
            let firstOther = otherArray.first,
            let firstElement = first.items.first,
            let firstOtherElement = firstOther.items.first,
            let firstInfo = first.info, let firstOtherInfo = firstOther.info
            else { return false }
        return firstInfo == firstOtherInfo && firstElement == firstOtherElement
    }
}

与具体实现一起使用时没有问题:

示例 1: 使用内置字符串类型的特定实现:

声明:

struct StringSection: SectionType {
    let info: String?
    let items: [String]
}

用法:

let stringSection1 = StringSection(info: "Info 1", items: ["Item 1", "Item 2"])
let stringSection2 = StringSection(info: "Info 2", items: ["Item 3", "Item 4"])
let stringSections1 = [stringSection1, stringSection2]
let stringSections2 = [stringSection2, stringSection1]
var areEqual = stringSections1.dummyCompare(with: stringSections2)
print("String section 1 equals 2?: \(areEqual)")

示例 2 - 使用自定义类型的特定实现:

声明:

protocol SectionInfoType {
    var title: String { get }
}

/// BTW: This is just Swift's stragne way of implementing Equatable protocol for your type:
func == (lhs: SectionInfoType, rhs: SectionInfoType) -> Bool {
    return lhs.title == rhs.title
}

struct SpecificSectionInfo: SectionInfoType, Equatable {
    let title: String
    static func == (lhs: SpecificSectionInfo, rhs: SpecificSectionInfo) -> Bool {
        return lhs.title == rhs.title
    }
}

protocol SectionItemType {
    var text: String { get }
}

/// BTW: This is just Swift's stragne way of implementing Equatable protocol for your type:
func == (lhs: SectionItemType, rhs: SectionItemType) -> Bool {
    return lhs.text == rhs.text
}

struct SpecificSectionItem: SectionItemType, Equatable {
    let text: String
    static func == (lhs: SpecificSectionItem, rhs: SpecificSectionItem) -> Bool {
        return lhs.text == rhs.text
    }
}

struct SpecificSection: SectionType {
    let info: SpecificSectionInfo?
    let items: [SpecificSectionItem]
}

用法:

let specInfo1 = SpecificSectionInfo(title: "Info 1")
let specItem1 = SpecificSectionItem(text: "Specific item 1")
let specItem2 = SpecificSectionItem(text: "Specific item 2")
let specInfo2 = SpecificSectionInfo(title: "Info 2")
let specItem3 = SpecificSectionItem(text: "Specific item 3")
let specItem4 = SpecificSectionItem(text: "Specific item 4")
let specSection1 = SpecificSection(info: specInfo1, items: [specItem1, specItem2])
let specSection2 = SpecificSection(info: specInfo2, items: [specItem3, specItem4])
let specSections1 = [specSection1, specSection2]
let specSections2 = [specSection2, specSection1]
let areEqual = specSections1.dummyCompare(with: specSections2)
print("Specific section 1 equals 2?: \(areEqual)")

到目前为止,一切顺利,一切正常并编译通过。但是......这种方法至少有两个问题:

问题 1:

仅从上面的 2 个示例,可以看出这种方法需要为 info 的每个组合“特定”实现 SectionType 协议(protocol)。和 items类型。这似乎不是那么有效(每个实现都有大量代码)也不是通用的。

我需要的是 SectionType 的更一般化的体现info 类型的协议(protocol)和 items需要是协议(protocol)(由外部 API 作为协议(protocol)提供)。

一个完美的例子(但不编译):

struct Section: SectionType {
    typealias I = SectionInfoType
    typealias T = SectionItemType
    let info: I?
    let items: [T]
}

问题 2:

我需要能够将它传递给其他面向协议(protocol)的 API,例如:作为函数的参数,例如:

func consume(section: SectionType<SectionInfoType, SectionItemType>) {}

但是上面的函数声明产生: Cannot specialize non-generic type 'SectionType' Xcode 提出修复:'Delete <SectionInfoType, SectionItemType>'结果是:

func consume(section: SectionType) {}

这两个都不编译,我找不到让它工作的方法。

是否有可能或是否存在 Swift 3 限制(我使用的是 Swift 3.1)?

我创建了 Git 存储库来展示这些问题。欢迎合作:

https://github.com/lukaszmargielewski/swift3-learning-generics

最佳答案

如果我理解正确问题 2,您希望您的函数使用一个通用变量,该变量也是专门的,遵守协议(protocol) SectionType。尝试:

func consume<Section: SectionType>(section: Section) {
    let foo = section.info
    let foobar = section.items
}

关于协议(protocol)的 Swift 3 泛型/关联类型限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43576916/

相关文章:

c# - 类型参数中具有层次结构的受限泛型

c# - 通用列表比较器不适用于 list<keyvaluePair>

ios - 我可以在 Swift 中强制协议(protocol)符合吗?

10g 中的 Oracle 登录协议(protocol) (O3LOGON)

ios - 如果 index.row 在我的数组中,则为单元格设置图像

c# - 依赖注入(inject)机制以提供通用服务接口(interface)的最具体实现

ios - 通过操纵杆进行一致平稳的运动

c++ - C++ 中的运行时错误。重定位协议(protocol)版本 %d

ios - 是否可以强制 MapKit 在不聚类的情况下显示所有注释?

ios - CoreData 对成员 'id' Xcode 12 的模糊引用