Swift枚举中通用关联值的确切限制是什么?

时间:2014-12-02 19:37:12

标签: generics swift enums

我试图了解Swift中具有通用关联值的枚举的确切限制。

您可能认为它们受支持,因为Optional就是这种类型。以下是Swift标准库中定义Optional的代码:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)
// ...
}

似乎案件成员Some具有变量类型T的关联值,对吗?

但是,书Functional Programming in Swift(第87页)中提到,不支持此类型:

  

我们想要定义一个通用的新枚举   与成功相关的结果:

enum Result<T> {
    case Success(T)
    case Failure(NSError) 
} 
     

不幸的是,当前的Swift编译器不支持通用关联值。

事实上,如果您将该代码段输入编译器,则会出现错误(error: unimplemented IR generation feature non-fixed multi-payload enum layout)。

那么这里发生了什么?它只是一般不支持,但作为特例支持Optional吗?有没有办法看看Optional如何获得这种特殊支持?或者,如果其他标准库类型也获得特殊支持?

2 个答案:

答案 0 :(得分:19)

在Swift 2中(作为Xcode 7的一部分),对关联值没有限制。所以,请随意跳舞,比如:

enum YouCanGoWith<T, U> {
    case This(T)
    case That(U)
    case Us
}

现在,如果您正在寻找成功或错误类型的枚举,您可能想停下来思考为什么......因为Swift 2还带来了一个新的错误处理模型。所以你不需要这样的类型作为你的函数的返回值 - 你可以这样声明:

func walkWith(rhythm: Bool) throws -> Place { /* ... */ }

...如果你的函数成功,调用者总是得到一个(非可选的)Place用于walken。并且 - 与使用结果分开 - 调用者决定如何处理,吞下或传播错误。

有关详细信息,请参阅 Swift编程语言中的Error Handling。仔细观察 - 语法看起来有点像你在其他语言中看到的异常模型,但Swift错误是一种完全不同的动物。

(当然,throws模型特定于同步调用。如果您正在声明异步进程的回调,其中回调闭包接收成功异步工作或错误的结果 - 成功 - or-Error类型仍然完全合适。)

答案 1 :(得分:6)

这个答案在Swift 2中已经过时了。请参阅rickster对Swift 2更新的回答。

您的评论是正确的。如果其中任何一个具有未知大小,则您不能拥有多个具有关联数据的案例。值类型可以是任何大小(因为它们被复制)。引用类型(如对象)具有已知大小,因为它们存储指针。

典型的解决方案是创建一个额外的包装类来保存泛型类型,就像FP书一样。按惯例,每个人都称它为Box。有理由希望Swift团队将来能够解决这个问题。如你所知,他们称之为&#34;未实现&#34;不支持#34;

Box的典型实现:

final public class Box<T> {
  public let unbox: T
  public init(_ value: T) { self.unbox = value }
}