Swift protocol extension implementing another prot

2019-06-18 19:09发布

问题:

Consider the following:

protocol Foo {
  typealias A
  func hello() -> A
}
protocol FooBar: Foo {
  func hi() -> A
}
extension FooBar {
  func hello() -> A {
    return hi()
  }
}

class FooBarClass: FooBar {
  typealias A = String
  func hi() -> String {
    return "hello world"
  }
}

This code compiles. But if I comment out explicit definition of associated type typealias A = String, then for some reason, swiftc fails to infer the type.

I'm sensing this has to do with two protocols sharing the same associated type but without a direct assertion through, for example, type parameterization (maybe associated type is not powerful/mature enough?), which makes it ambiguous for type inference.

I'm not sure if this is a bug / immaturity of the language, or maybe, I'm missing some nuances in protocol extension which rightfully lead to this behaviour.

Can someone shed some light on this?

回答1:

look at this example

protocol Foo {
    typealias A
    func hello() -> A
}
protocol FooBar: Foo {
    typealias B
    func hi() -> B
}
extension FooBar {
    func hello() -> B {
        return hi()
    }
}

class FooBarClass: FooBar {
    //typealias A = String
    func hi() -> String {
        return "hello world"
    }
}

with generics

class FooBarClass<T>: FooBar {
    var t: T?
    func hi() -> T? {
        return t
    }
}

let fbc: FooBarClass<Int> = FooBarClass()
fbc.t = 10
fbc.hello() // 10
fbc.hi()    // 10


回答2:

Providing explicit values for associated types in a protocol is required for conformance to said protocol. This can be accomplished by hard coding a type, as you've done with typealias A = String, or using a parameterized type as you mentioned, such as below:

class FooBarClass<T>: FooBar {
    typealias A = T
    ...
}

Swift will not infer your associated type from an implemented method of the protocol, as there could be ambiguity with multiple methods with mismatching types. This is why the typealias must be explicitly resolved in your implementing class.