swift 函数中的嵌套泛型

Nested generics in a swift function

假设我有这段代码:

protocol MyProtocol {
}

struct MyStruct: MyProtocol {
}

class MyClass<P: MyProtocol> {
    // Required for compiling
    required init() {
    }
}

class MySpecialClass: MyClass<MyStruct> {
}

func foo<P: MyProtocol, C: MyClass<P>>(protocolType: P.Type) -> C {
    return C()
}

这样编译调用

let specialClass: MySpecialClass = foo(protocolType: MyStruct.self)

创建类型 MySpecialClass 的实例。

我想要的是不必传入 P 的类型,这样我就可以简单地调用

let specialClass: MySpecialClass = foo()

自动推导出P

有什么办法可以做到这一点吗?

我相信这会奏效:

protocol MyProtocol {
}

struct MyStruct: MyProtocol {
}

class MyClass<P: MyProtocol> {
  // added a typealias for P
  typealias ContainedProtocol = P
  // Required for compiling
  required init() {
  }
}

class MySpecialClass: MyClass<MyStruct> {
}

// added a default value for protocolType
func foo<P, C: MyClass<P>>(protocolType: P.Type = C.ContainedProtocol.self) -> C {
  return C()
}

let specialClass: MySpecialClass = foo()

通过在 MyClass<P: MyProtocol> 中为 P 添加类型别名,我们可以引用该类型。然后我们将其设置为 foo<P, C: MyClass<P>>(protocolType:) -> C 中的默认值。然后,编译器可以从该信息中推断出 P

Martin R 的版本似乎和我的一样好,所以选择你最喜欢的那个。他的看起来更简洁一些,因为它不需要 typealias 而且相当简洁。

这里是(之前是评论,现在是答案):

func foo<P, C: MyClass<P>>(dummy: P? = nil) -> C { ... }

正如@Hamish 已经提到的,

func foo<P, C: MyClass<P>>() -> C {
    return C()
}

let specialClass: MySpecialClass = foo()

在 Swift 4 中工作。但是 Swift 3 编译器抱怨

error: generic parameter 'P' is not used in function signature

一个可能的解决方法是添加一个类型的虚拟参数 P? 默认值:

func foo<P, C: MyClass<P>>(dummy: P? = nil) -> C {
    return C()
}

let specialClass: MySpecialClass = foo()