Swift编译器为什么不能推断带有关联项的协议的返回类型?

时间:2019-11-01 18:02:03

标签: swift compiler-construction protocols

在阅读《 Swift语言指南》中关于Opaque Types的文档时,代码片段的尽头是

// Error: Not enough information to infer C.
func makeProtocolContainer<T, C: Container>(item: T) -> C {
    return [item]
}

Container具有关联的类型Item,并且Array被扩展为符合Container。为什么编译器缺少信息来推断这是Array<T>

另一个令人困惑的问题是,对于泛型函数,通常将其编写为使用客户端代码指定的任何类型。因此,客户端代码不应该是指示C是什么的代码,而不是强制其返回类型为Array的函数吗?

1 个答案:

答案 0 :(得分:1)

这就是我向团队解释不透明类型的方式。

您的典型通用功能(如您共享的代码段)看起来很清晰。为什么编译器不会将以下代码解释为返回Array<T>

// Error: Not enough information to infer C.
func makeProtocolContainer<T, C: Container>(item: T) -> C {
    return [item]
}

发生错误的原因是因为如何使用C作为返回值。当您看到-> C形式的内容作为通用返回值时,该类型的定义将留给调用者

因此,假设Array符合Container,那么您将可以执行以下操作:

let array: Array<Int> = makeProtocolContainer(Int(5))

您的呼叫站点正在定义C的类型。

但是,如果您希望函数本身定义该怎么办?那就是不透明类型出现的地方。

在上面的示例中,makeProtocolContainer函数应返回调用方可以定义的常规值。但是该函数本身正在定义一个符合C的具体实现,这与返回泛型类型不同。

如果您希望函数本身指定类型,则只需在Swift中使用新的some关键字对其进行修改。

func makeProtocolContainer<T>(item: T) -> some Container {
    return [item]
}

现在,该函数可以返回具体类型。结果,即使它们可能相等,调用方也只能将其称为该不透明类型。

/// Error: Cannot convert value of type 'some Container' to specified type 'Array<String>'
let container: Array<String> = makeProtocolContainer(item: "A")

您也不能使用通用类型来保留不透明类型。

/// Error: Protocol 'Container' can only be used as a generic constraint because it has Self or associated type requirements
let container: Container = makeProtocolContainer(item: 5)

但是您可以做的是允许类型推断或自己指定不透明类型。

let container = makeProtocolContainer(item: 5)
// Same as
let container: some Container = makeProtocolContainer(item: 5)