SE-0244 Opaque Result Types 提案前一段时间经过了 review 而且在 Swift 5.1 里完成了实现,我最先阅读这份提案的时候理解不是很透彻,今天比较仔细地读了这篇 Improving the UI of generics 以后有了更多的认识,并且发现本身以前发的 tweet 里有一些错误的认知,因此这里写篇文章,但愿用最直白的方式解释清楚提案的内容,跟你们分享一下我本身的理解。git
用最最简单的一句话来介绍这个提案的内容,就是它能让被调用者选择泛型返回值的具体类型。github
这是什么意思呢?让咱们来看目前最多见的泛型函数声明:swift
protocol Shape { ... }
func generic<T: Shape>() -> T { ... }
let x: Rectangle = generic() // type(of: x) == Rectangle, 调用方决定返回值类型
复制代码
这很好,但有时候咱们不但愿暴露出具体的返回类型,也不想让调用者去依赖具体的类型,以前咱们能够直接使用泛型类型:app
func generic() -> Shape { ... }
let x = generic() // type(of: x) == Shape
复制代码
虽然这样确实能达成咱们的目的,但也会带来一些反作用,例如说性能问题,由于实际上 generic
返回的是一个实例的容器。dom
咱们更但愿的是可以像第一种声明那样,在编译时就肯定返回值的具体类型,而且由被调用方去决定:函数
func reverseGeneric() -> some Shape { return Rectangle(...) }
let x = reverseGeneric()
// type(of: x) == Rectangle
// 而且 x 的类型根据 reverseGeneric 的具体实现决定
复制代码
经过引入 some
这个关键字去修饰返回值,就可让被调用方选择具体的返回值类型,而且是在编译时肯定下来的,这意味着咱们不须要额外的容器去存放返回的实际值。性能
另外它还能够做为属性使用:ui
func someNumber() -> some Numeric { ... }
var number: some Numeric = someNumber()
复制代码
在这里咱们须要先确立一个条件,经过 some 修饰的类型,都会在编译时肯定下来,能够简单地理解为被调用方负责传入的一个泛型参数,相关的功能和限制都是基于这个特性延伸出来的。spa
根据前面的条件,若是返回值使用了 some
修饰,编译器能够推导出两件很重要的事情:3d
这意味着什么?在以前,两个遵循了 Equatable
的实例不能判断是否相等,由于咱们并不知道它们具体的类型是否同样,但若是使用了 some
,而且是由同一个函数返回的,那就彻底不是问题了:
func randomNumber() -> some Equatable {
let i: Int = 32
return i
}
let x = randomNumber()
let y = randomNumber()
// 在这里使用 == 是没问题的
// 由于 x 跟 y 都是由 randomNumber 返回的
// 因此它们的具体类型必然一致
print(x == y)
复制代码
可是控制返回值类型的是调用方,因此你不可以依赖调用方的具体实现:
func randomNumber() -> some Equatable {
let i: Int = 32
return i
}
var otherNumber: Int = 38
var x = randomNumber()
x = otherNumber // error
复制代码
虽然你知道 randomEquatableNumber
的实现里使用的是 Int
,但具体的实现有可能随时被调整,因此你不能依赖它。
在这里只是简单地介绍了一些比较核心的内容,想了解更多细节的朋友能够看提案。实际上这个提案只是整个泛型语法改进计划里的第一步,以后等我有了更加深刻的了解再作更多分享。
以为文章还不错的话能够关注一下个人博客。