Swift 协议中的泛型

Swift generics in protocols

用 swift 解决以下示例的合适方法是什么?

我知道由于类型擦除,您不能在构造函数中将 StructB 分配给 item2。在 Java 等其他语言中,我会通过在 Container 结构中没有通用 class 参数 T 来解决问题,但是让vars itemitem2 只是 ProtocolA 的类型(如 var item2: ProtocolA)。 这是swift不允许的:协议'ProtocolA'只能作为泛型约束,因为它有Self或关联类型要求

我完成了 swift 文档中关于泛型的 this 部分,但到目前为止我无法针对我的简单问题调整解决方案:

protocol ProtocolA {
    associatedtype B
    
    func foo() -> B
}


struct StructA: ProtocolA {
    typealias B = String
    
    func foo() -> String {
        "Hello"
    }
}

struct StructB: ProtocolA {
    typealias B = Double
    
    func foo() -> Double {
        0.0
    }
}

struct Container<T: ProtocolA> {
    
    var item: T
    var item2: T
    
    init(item: T) {
        self.item = item
        self.item2 = StructB() // err: Cannot assign value of type 'StructB' to type 'T'
    }
}

我还想知道如果我根本不想为容器结构指定泛型类型参数,解决方案会是什么样子。这样我就可以写下:

func test() {
    let container = Container(StructA()) // no type given
}

做你想做的事情的唯一方法是:

struct Container<T: ProtocolA,U: ProtocolA> {

    var item: T
    var item2: U

    init(item: T, item2: U) {
        self.item = item
        self.item2 = item2
    }
}

对于描述的问题,答案很简单:

struct Container<T: ProtocolA> {

    var item: T
    var item2: StructB // This isn't T; you hard-coded it to StructB in init

    init(item: T) {
        self.item = item
        self.item2 = StructB()
    }
}

let container = Container(item: StructA()) // works as described

我觉得这个问题有更深层次的东西,这就是为什么 Alexander 要求提供更多背景信息。正如所写,问题的答案似乎太简单了,所以我们中的一些人认为还有更多您没有解释的内容,我们希望避免一轮“这是答案”,然后是“这不是我的意思”。

如您所写,您试图强制 itemitem2 具有相同的类型。这显然不是你的意思,因为 T 是由调用者给出的,而 item2 总是 StructB(它不必等于 T,正如错误所解释的那样)。

你打算用另一种方式调用这段代码吗?目前还不清楚调用 foo() 的代码会是什么样子。您是否有其他未在问题中解释的方式来初始化 Container?

也许您想要两种不同的类型,而您只想将 StructB 作为默认值?在那种情况下,它看起来像(基于 Ptit Xav 的回答):

struct Container<T: ProtocolA, U: ProtocolA> {

    var item: T
    var item2: U

    // Regular init where the caller decides T and U
    init(item: T, item2: U) {
        self.item = item
        self.item2 = item2
    }

    // Convenience where the caller just decides T and U is default
    init(item: T) where U == StructB {
       self.init(item: item, item2: StructB())
    }
}

where U == StructB 允许您为 U 设置默认类型。