Swift协议扩展实现具有共享关联类型的另一协议

时间:2023-01-23 22:19:36

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.

这段代码编译。但是如果我注释掉关联类型类型A = String的显式定义,那么由于某种原因,swiftc无法推断出类型。

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?

有人可以对此有所了解吗?

2 个解决方案

#1


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


0  

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:

为了符合所述协议,需要为协议中的关联类型提供显式值。这可以通过对类型进行硬编码来完成,就像你使用了typealias A = String,或者使用你提到的参数化类型,如下所示:

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.

Swift不会从协议的实现方法推断出您的关联类型,因为多种方法可能存在不一致类型的歧义。这就是必须在实现类中显式解析typealias的原因。

#1


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


0  

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:

为了符合所述协议,需要为协议中的关联类型提供显式值。这可以通过对类型进行硬编码来完成,就像你使用了typealias A = String,或者使用你提到的参数化类型,如下所示:

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.

Swift不会从协议的实现方法推断出您的关联类型,因为多种方法可能存在不一致类型的歧义。这就是必须在实现类中显式解析typealias的原因。