前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift5.7 支持结构化不透明结果类型

Swift5.7 支持结构化不透明结果类型

原创
作者头像
DerekYuYi
发布2022-07-04 11:36:58
6470
发布2022-07-04 11:36:58
举报
文章被收录于专栏:Swift-开源分析

介绍

当前提议主要是讲苹果在 Swift5.7 支持不透明结果类型的结构化表达,目前在 Swift5.7 已经实现。

不透明结果类型可以用作函数的结果类型,变量的类型和下标元素的结果类型。在这三种情况下,不透明结果类型必须是整个类型。比如用于函数的整个返回结果类型。本篇提议建议取消这种限制,并允许在“结构”位置使用不透明的结果类型。

目的

当前语法中对不透明结果类型的限制阻止了它们在许多常见的 API 模式中使用。可以看下面四个常见的例子:

代码语言:Swift
复制
// ❌,函数的不透明结果返回值有可能失败
func f0() -> (some P)?  {  /* ... */ }

// ❌,不能把不透明结果类型作为多个返回值中的一个,必须是对应单个且整个返回值
func f1() -> (some P, some Q)  {  /* ... */ }

// ❌,不能返回一个懒加载的计算 some 类型。(当 f2 调用完成且返回结果时,返回类型是`() -> some P`,此时返回值中并不确定 some 类型)
func f2() -> () -> some P  {  /* ... */ }

// ❌,不能把不透明结果类型嵌入到更大的结构中
func f3() -> S<some P>  {  /* ... */ }

上面四个调用示例都是之前的语法约定,如果解除这些限制,就可以使用不透明结果类型来表达更多 API 模式。所以我们应该允许在函数的结果类型、下标元素的类型和变量的类型,这三种类型的结构位置中使用不透明结果类型。

详细设计实现

可选语法

不透明结果类型的可选必须使用(some P)?表示,一个已经解包的不透明结果类型的可选必须使用(some P)! 表示。

为什么不用 some P?some P! 呢?some P?这种表达会被解释为some Optional<P>,由于不透明类型一定是Any, AnyObject, 组合的协议,或者基类中的一种,所以some P?这种表达一定错误。some P!也是同样的道理。

高阶函数

如果函数的结果类型、下标的结果类型和变量的类型是函数类型,那么该函数类型只能在返回位置包含结构不透明类型。例如,func f() -> () -> some P合法,但是func g() -> (some P) -> ()会直接报错,这里主要因为some不能出现在函数结果类型的参数位置:

代码语言:Swift
复制
protocol P {}
func g() -> (some P) -> () {  ...  } // 'some' 不能出现在 '(some P) -> ()' 的参数位置
约束推断能力

当泛型参数类型用在函数签名(可以简单理解为函数名加参数的唯一标识)的结构位置时,编译器会根据使用泛型参数的上下文来隐式约束泛型参数类型。例如下面例子中f函数中泛型参数会被推断为Hashable

代码语言:Swift
复制
struct H<T: Hashable> {  init(_ t: T) { } }
struct S<T>{  init(_ t: T) { }  }

// 与 'f<T: Hashable>' 等价,因为返回值 'H<T>' 就是指 'T: Hashable'
func f<T>(_ t: T) -> H<T> {
    var h = Hasher()
    h.combine(t)        // 可以编译通过, 这里推断知道 'T: Hashable'(combine 是 Hashble 的实例方法)
    let _ = h.finalize()
    return H(0)
}

// 'S<T>' 没有实现任何 'T' 相关的协议
func g<T>(_ t: T) -> S<T> {
    var h = Hasher()
    h.combine(t) // ❌ERROR - 'combine' 是 'Hashable'的实例方法,调用者泛型 'T'' 实必须实现 'Hashable' 协议
    let _ = h.finalize()
    return S(0)
}

但不透明结果类型没有类型推断的特性,例如把f函数的返回值使用不透明结果类型H<some P>表示,由于some没有类型推断能力,T无法根据上下文推断是否遵守Hashable,此时f函数会直接报错。例如:

代码语言:Swift
复制
// ❌,类型 'some P' 没有遵守协议 'Hashable'
func f<T>(_ t: T) -> H<some P> {  /* ... */  }

对源代码兼容性的影响

新增特性,没有兼容性影响。

SE-0244 中讨论的一样:

如果在库中采用不透明类型,则一开始会破坏源代码[...]兼容性, 因为不支持可变参数。但是由于向客户端暴露的细节很少,实际上可以对源代码和 ABI 稳定性来说长期受益。对源代码兼容性也有一些缓解措施,比如,原类型的弃用周期更长,或者用新的函数签名(返回的不透明结果类型)重载旧的函数签名(返回命名类型)。

对 ABI 稳定性的影响

新增特性,对 ABI 无影响。

对 API 扩展性的影响

新增特性,没有扩展性相关的影响。 SE-0244 提议已经说明:

不透明结果类型是函数的结果类型,变量类型,下标的元素类型,这三种类型的一部分。在不破坏API/ABI 稳定性的前提下,无法更改不透明结果类型的要求。但是,底层的具体类型可以在不破坏 ABI 的情况下从一个版本更改到下一个版本,因为 API 上层并不知道底层的具体类型。

Rust 的Impl Trait特性

Swift 中的不透明结果类型是受 Rust 中的impl Trait特性启发而来。SE-0244 中对比了someimpl Trait的异同点。其中一个不同点是impl Trait允许在结构位置使用,这个特性与当前提议基本相同。impl Trait与当前提议特性有个不同点,是impl Trait不会出现在闭包特性或者函数指针的返回类型中。

总结

通过当前提议 SE-0328,你应当知道:

  • 结果类型支持(some P)?(some P)!
  • 返回结果类型是函数类型时,支持() -> (some P)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 目的
  • 详细设计实现
    • 可选语法
      • 高阶函数
        • 约束推断能力
        • 对源代码兼容性的影响
        • 对 ABI 稳定性的影响
        • 对 API 扩展性的影响
        • Rust 的Impl Trait特性
        • 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档