【问题标题】:Swift generic class initializerSwift 泛型类初始化器
【发布时间】:2016-04-11 22:36:25
【问题描述】:

我发现在swift中设计结果类有问题

struct Result<T>{
    private let data: T?
    let error: NSError?
    var isSuccess: Bool {
        get {
            return data != nil
        }
    }

    init(data: T) {
        self.data = data
        self.error = nil
    }

    init(error: NSError) {
        self.data = nil
        self.error = error
    }
}

用法应该是这样的

Result(data: "something") // T as string

当我想传递错误时出现问题

Result(error: errorFromSomewhere) //T is not specified

以下是实际应用使用情况:

class ParseRegistrationProvider: RegistrationProvider {
    func register(model: RegistrationForm) -> Promise<Result<String>> {
        return Promise { accept, reject in
            let user = PFUser()
            user.username = model.nickName
            user.password = model.password
            user.email = model.emailAdreess
            user.signUpInBackgroundWithBlock({ (isSuccess, error) -> Void in
                if isSuccess {
                    accept(Result(data: "OK"))
                } else {
                    var errorResult = Result(error: error!) //causes error
                    reject(errorResult)
                }
            })
        }
    }
}

“errorResult”导致编译器错误:

无法推断通用参数 T

更新: 这个方法可以正常工作:

Result<String>(error: errorFromSomewhere)

【问题讨论】:

  • 您看到错误的上下文是什么? (根据错误消息,它似乎与此结构无关,而与使用它的上下文更相关)。
  • @nhgrif 我已经更新了问题。
  • 您还更改了编译器错误消息。当您初始化为Result&lt;String&gt;(error: error!) 时,在相同的上下文中会发生什么?reject() 函数的签名是什么?它期望什么参数类型?
  • 请注意,这不是构建Result 的好方法。在 Swift 社区中,Result 有大量的工作(请参阅 github.com/antitypical/Result 以获得非常好的一个)。如果您要构建自己的(这完全没问题;我一直这样做),您希望它是一个枚举,而不是一个结构。
  • @razor118 最好发布一个自我回答而不是在更新中进行编辑。

标签: swift


【解决方案1】:

我想建议像这样对 Result 使用变体类型,因为它更紧凑,可以自然地用于模式匹配:

enum Result<T>{
    case Data(T?)
    case Error(NSError)
    var isSuccess: Bool{
        get{
            switch self{
            case .Data(_?):
                return true
            default:
                return false
            }
          }
    } }

你的代码可能会变成这样:

class ParseRegistrationProvider: RegistrationProvider {
    func register(model: RegistrationForm) -> Promise<Result<String>> {
        return Promise { accept, reject in
            let user = PFUser()
            user.username = model.nickName
            user.password = model.password
            user.email = model.emailAdreess
            user.signUpInBackgroundWithBlock({ (isSuccess, error) -> Void in
                if isSuccess {
                    accept(Result<String>.Data("OK"))
                } else {
                    var errorResult = Result<String>(error: error!) //causes error
                    reject(errorResult)
                }
            })
        }
    }

}

【讨论】:

    【解决方案2】:

    当您使用类而不是结构时,您可以使用init(data: T) 定义一个基类(例如ErrorResultinit(error: NSError))和一个派生Result&lt;T&gt;)。

    这样,您就完全避开了泛型参数。 但是,由于使用类,您可能会增加一些运行时开销。

    【讨论】:

      【解决方案3】:

      要直接回答您的问题,您可以将 errorResult 声明为:

      var errorResult : Result<String>
      

      这将立即解决问题。 但是,我认为更好的解决方案是使用枚举而不是结构,因为它更合适(除非它比您发布的更多)。

      enum Result<T> {
          case Data(T)
          case Error(NSError)
      
          var success : Bool {
              switch self {
              case .Data:
                  return true
              case .Error:
                  return false
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-11-23
        • 2019-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-06
        • 2019-03-16
        相关资源
        最近更新 更多