[英]Swift 3 generics / associated types limitations with protocols
我有一个通用协议:
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)")
到目前为止,一切都很好,并且可以编译。 但是...这种方法至少有两个问题:
问题一:
仅从上面的两个示例中,就可以看到这种方法需要针对info
和items
类型的每种组合对SectionType协议进行“特定”实现。 这似乎不是很有效(每个实现都需要大量的代码)或通用的。
我需要的是SectionType
协议的一个更通用的实施例,其中info
和items
类型需要是协议(从外部API作为协议提供)。
一个完美的例子(但不能编译):
struct Section: SectionType {
typealias I = SectionInfoType
typealias T = SectionItemType
let info: I?
let items: [T]
}
问题2:
我需要能够将其传递给其他面向协议的API,例如f.ex .:作为函数的参数,例如:
func consume(section: SectionType<SectionInfoType, SectionItemType>) {}
但是上面的函数声明会产生: Cannot specialize non-generic type 'SectionType'
使用提出修正的Xcode来Cannot specialize non-generic type 'SectionType'
: 'Delete <SectionInfoType, SectionItemType>'
导致以下结果:
func consume(section: SectionType) {}
这既不会编译,也找不到使它起作用的方法。
可以做到还是有Swift 3的限制(我正在使用Swift 3.1 )?
我创建了展示这些问题的Git存储库。 随时合作:
https://github.com/lukaszmargielewski/swift3-learning-generics
如果我对问题2的理解正确,那么您希望您的函数使用一个也经过专门处理的通用变量,并遵守协议SectionType
。 尝试:
func consume<Section: SectionType>(section: Section) {
let foo = section.info
let foobar = section.items
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.