“存在类型”在Swift中是什么意思

时间:2019-07-03 10:02:58

标签: swift

我正在阅读Swift Evolution proposal 244 (Opaque Result Types),但不理解以下含义:

  

...存在类型...

     

一个人可以通过   使用 现有类型 形状而不是通用参数,但是   这样做将意味着更多的动态性和运行时开销   希望的。

1 个答案:

答案 0 :(得分:0)

演进提案本身提供了一个存在类型的示例:

protocol Shape {
  func draw(to: Surface)
}

使用protocol Shape作为存在类型的示例看起来像

func collides(with: Shape) -> Bool

与使用通用参数Other相对:

func collides<Other: Shape>(with: Other) -> Bool

在这里需要特别注意的是,协议Shape本身不是存在类型,仅在"protocols-as-types"上下文中使用它,如上,从协议“创建”存在类型。参见this post from the member of Swift Core Team

  

此外,协议目前还作为存在类型的拼写检查者,但这种关系一直是造成混淆的常见原因。

还引用Swift Generics Evolution文章(我建议阅读全文,这将对此进行更详细的解释):

  

区分协议类型和存在类型的最好方法是查看上下文。问自己:当我看到对诸如Shape之类的协议名称的引用时,它是在类型级别还是在值级别出现?回顾一些先前的示例,我们看到:

     
func addShape<T: Shape>() -> T
// Here, Shape appears at the type level, and so is referencing the protocol type

var shape: Shape = Rectangle()
// Here, Shape appears at the value level, and so creates an existential type

深潜

为什么将它称为“存在的”?我从没看到过明确的确认,但我认为该功能是受具有更高级类型系统的语言启发的,例如考虑Haskell's existential types

class Buffer -- declaration of type class `Buffer` follows here

data Worker x y = forall b. Buffer b => Worker {buffer :: b, input :: x, output :: y}

大致相当于这个Swift代码段(如果我们假设Swift的协议或多或少代表了Haskell的类型类):

protocol Buffer {}

struct Worker<X, Y> {
  let buffer: Buffer
  let input: X
  let output: Y
}

请注意,Haskell在此处使用了forall existential quantifier。您可以将其理解为“对于所有符合类型类的类型(在Swift中为“协议”)。类型Buffer的{​​{1}}值将具有完全相同的类型,只要它们的Worker和{ {1}}类型参数相同”。因此,给定

X

Yextension String: Buffer {} extension Data: Buffer {} 将具有完全相同的类型。

这是一项强大的功能,它允许诸如异类集合之类的事情,并且可以在需要“擦除”值的原始类型并将其“隐藏”在存在类型下的更多地方使用。像所有强大的功能一样,它可能会被滥用并使代码的类型安全性降低,因此应谨慎使用。

如果您想更深入地学习,请查看Protocols with Associated Types (PATs),由于各种原因,它们不支持存在性。还有一些Generalized Existentials提案在空中飘扬,但是从Swift 5.1开始,没有什么具体的提案。实际上,由OP链接的原始Opaque Result Types提案可以解决因使用PAT而引起的一些问题,并显着缓解Swift中缺乏通用的存在性。