Swift@autoclosure破坏了v1.2中枚举用例的兼容性



我刚刚将Xcode更新到6.3,过去在Xcode 6.2中编译的Swift代码现在不编译了。

import Foundation
public enum Result<T> {
    case Success(@autoclosure() -> T)
    case Failure(NSError)
    case Cancelled
    public init(_ value: T) {
        self = .Success(value)
    }
    public init(_ error: NSError) {
        self = .Failure(error)
    }
    public init() {
        self = .Cancelled
    }
    public var failed: Bool {
        switch self {
        case .Failure(let error):
            return true
        default:
            return false
        }
    }
    public var error: NSError? {
        switch self {
        case .Failure(let error):
            return error
        default:
            return nil
        }
    }
    public var value: T? {
        switch self {
        case .Success(let value):
            return value()
        default:
            return nil
        }
    }
}

此行:case Success(@autoclosure() -> T)

产生错误:'autoclosure' attribute is only allowed on parameters, not on enum cases

仅仅移除@autoclosure并不能解决问题。

正确。它已被删除,明确是为了防止出现您提供的情况。自动闭包不打算以这种方式使用,Swift团队故意取消了这样做的能力。在Result类型中,这是危险的,因为每次访问闭包时都会重新评估它。如果关闭有副作用,这可能会产生非常令人惊讶的影响。即使这不是小事,它也会对性能产生令人惊讶的影响。

这里正确的工具是Box。请参阅Rob Rix的Result以获得此类型的良好实现。

我想我已经找到了解决方案。您只需要更改原始实现中的2行即可使其工作:

case Success(() -> T)

public init(@autoclosure(escaping) _ value: () -> T) {

对于那些只想要一个简单的解决方案而不需要导入外部框架的人:

public enum Result<T> {
  case Success(Box<T>)
  case Failure(String)
  public init(_ value: T) {
      self = .Success(Box(value))
  }
  public init(_ error: String) {
      self = .Failure(error)
  }
}
// Due to current swift limitations, we have to include this Box in Result.
final public class Box<T> {
    public let unbox: T
    public init(_ value: T) { self.unbox = value }
}
public func success<T>(value: T) -> Result<T> {
    return .Success(Box(value))
}
public func failure<T>(error: String) -> Result<T> {
    return .Failure(error)
}

最新更新