我正在试验一些快速的功能。(收集协议)。我想实现一个实现CollectionType的结构。我的代码:
struct Book {
let id : String
let name : String
init(id: String, name: String) {
self.id = id
self.name = name
}
}
struct BookCollection {
var books : [Book]
}
首次尝试:
extension BookCollection : CollectionType {
}
编译器错误:“类型BookCollection不符合协议可索引”
好的编译器让我们符合Indexable:
extension BookCollection : CollectionType {
var startIndex: Int {return 0}
var endIndex: Int {return books.count}
subscript(idx: Int) -> Book {
return books[idx]
}
}
代码现在正在运行。
我的问题是:如果我们忘记编译器错误,是否有一种简单的方法可以知道在符合swift协议时我们应该实现哪些功能/属性? 谢谢
PS:我不想阅读所有扩展程序以查看是否存在默认实现,否则很痛苦
答案 0 :(得分:1)
编译器错误会告诉你。我把你的代码放在游乐场,看到了以下错误
Playground execution failed: MyPlayground.playground:15:1: error: type 'BookCollection' does not conform to protocol 'Indexable'
extension BookCollection: CollectionType
^
Swift.Indexable:6:15: note: unable to infer associated type 'Index' for protocol 'Indexable'
typealias Index : ForwardIndexType
^
Swift.CollectionType:2:12: note: inferred type 'Range<BookCollection.Index>' (by matching requirement 'subscript') is invalid: does not conform to 'ForwardIndexType'
public subscript (bounds: Range<Self.Index>) -> Slice<Self> { get }
^
MyPlayground.playground:15:1: error: type 'BookCollection' does not conform to protocol 'SequenceType'
extension BookCollection: CollectionType
^
Swift.SequenceType:35:17: note: protocol requires function 'generate()' with type '() -> Generator'
public func generate() -> Self.Generator
^
Swift.SequenceType:2:17: note: candidate has non-matching type '<`Self`> () -> `Self`' (aka '<τ_0_0> () -> τ_0_0')
public func generate() -> Self
^
Swift.SequenceType:5:17: note: candidate has non-matching type '<`Self`> () -> `Self`.Base.Generator' (aka '<τ_0_0> () -> τ_0_0.Base.Generator')
public func generate() -> Self.Generator
^
Swift.CollectionType:2:17: note: candidate has non-matching type '<`Self`> () -> IndexingGenerator<`Self`>' (aka '<τ_0_0> () -> IndexingGenerator<τ_0_0>')
public func generate() -> IndexingGenerator<Self>
从顶部开始,我看到我们需要一个关联索引类型的类型,然后有一大堆错误与它没有被定义相关,所以我在协议中添加了typealias
协议扩展,这会给我带来更多错误,因此我暂时将CollectionType
更改为Indexable
extension BookCollection: Indexable
{
typealias Index = Int
}
现在我有以下内容:
Playground execution failed: MyPlayground.playground:15:1: error: type 'BookCollection' does not conform to protocol 'Indexable'
extension BookCollection: Indexable
^
Swift.Indexable:21:15: note: protocol requires nested type '_Element'
typealias _Element
^
_Element
应该是一个实现细节(它以下划线开头),但现在让它滚动它并为它添加一个类型别名。
extension BookCollection: Indexable
{
typealias Index = Int
typealias _Element = Book
}
现在我有以下
Playground execution failed: MyPlayground.playground:15:1: error: type 'BookCollection' does not conform to protocol 'Indexable'
extension BookCollection: Indexable
^
Swift.Indexable:12:16: note: protocol requires property 'startIndex' with type 'Index' (aka 'Int')
public var startIndex: Self.Index { get }
^
Swift.Indexable:20:16: note: protocol requires property 'endIndex' with type 'Index' (aka 'Int')
public var endIndex: Self.Index { get }
^
Swift.Indexable:22:12: note: protocol requires subscript with type 'Index -> _Element'
public subscript (position: Self.Index) -> Self._Element { get }
所以现在我实现了两个属性和下标。我注意到实现下标将允许编译器推断出两种类型的别名类型,因此我可以删除这些声明。
extension BookCollection: Indexable
{
var startIndex: Int { return books.startIndex }
var endIndex: Int { return books.endIndex }
subscript(index: Int) -> Book
{
return books[index]
}
}
这没有错误,因此我们将协议更改回CollectionType
,我们仍然没有错误,所以我们必须完成。
答案 1 :(得分:0)
除了使用编译器错误之外,没有简单的方法。为什么?因为协议支持默认实现,并且您无法知道哪些协议函数具有默认实现(除了编译器不抱怨它们)。
例如,SequenceType
定义了许多功能。你实现了它们吗?不,因为大多数都有默认实现。唯一需要的是func generate() -> GeneratorType
和相关的GeneratorType
。之后,您的子类型SequenceType
已完成 - 您可能会选择覆盖某些默认实现,但不需要。 CollectionType
为Indexable
(GeneratorType
默认为IndexingGenerator<Self>
)
当然,如果您有源代码,那么您可以识别默认协议实现,但是当您完成此操作时,您也可以让编译器告诉您。或者,Apple文档确实列出了一些带有“默认实现”的功能,这可能表明不需要实现的功能。或者,如评论中所述,swiftdoc.org以清晰的形式标识所需的类型/功能。