简体   繁体   中英

Protocol conforming

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM