在阅读《 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
的函数吗?
答案 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)