I am experimenting some swift features.( Collection protocols). I would like to implement a structure that implements CollectionType. My code :
struct Book {
let id : String
let name : String
init(id: String, name: String) {
self.id = id
self.name = name
}
}
struct BookCollection {
var books : [Book]
}
First attempt :
extension BookCollection : CollectionType {
}
Compiler error : "Type BookCollection does not conform to the protocol Indexable"
Ok compiler let's conform to Indexable :
extension BookCollection : CollectionType {
var startIndex: Int {return 0}
var endIndex: Int {return books.count}
subscript(idx: Int) -> Book {
return books[idx]
}
}
The code is working now.
My Question is : if we forget the compiler errors, is there an easy way to know what functions/properties we should implement when conforming to a protocol in swift ? Thanks
PS : I don't want to read all the extensions to see if there are a default implementation or no, it's painful
The compiler errors will tell you. I put your code in a playground and saw the following errors
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>
Starting from the top, I see we need a type for the associated index type and then there is a whole load of errors that relate to it not being defined, so I add a typealias
for protocol Indexable in the extension and that gives me a whole load more errors, so I change CollectionType
to Indexable
temporarily
extension BookCollection: Indexable
{
typealias Index = Int
}
And now i have the following:
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
is supposed to be an implementation detail (it starts with an underscore), but let's roll with it for now and add a type alias for it too.
extension BookCollection: Indexable
{
typealias Index = Int
typealias _Element = Book
}
Now I have the following
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 }
So now I implement the two properties and the subscript. I notice that implementing the subscript would allow the compiler to infer the two type alias types so I can delete those declarations.
extension BookCollection: Indexable
{
var startIndex: Int { return books.startIndex }
var endIndex: Int { return books.endIndex }
subscript(index: Int) -> Book
{
return books[index]
}
}
This gives no errors, so we change the protocol back to CollectionType
and we still have no errors so we must be done.
There is no easy way other than to use what the compiler errors out on. Why? Because protocols support default implementations and you can't know what protocol functions have a default implementation (except that the compiler does not complain about them).
For example, SequenceType
has many functions defined. Do you implement them all? No, because most have default implementations. The only thing needed is func generate() -> GeneratorType
and the associated GeneratorType
. After that, your subtype of SequenceType
is done - you might choose to override some default implementations, but need not. For CollectionType
it is Indexable
(and GeneratorType
defaults to IndexingGenerator<Self>
)
Of course, if you have the source code, then you can identify the default protocol implementations but, by the time you've done that, you might as well let the compiler tell you. Or, the Apple documentation does list some functions with 'Default Implementation' which might indicate what does not need to be implemented. Or, as noted in a comment, swiftdoc.org identifies the required types/functions in a clear form.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.