简体   繁体   English

Swift通用类初始化器

[英]Swift generic class initializer

I found a problem with designing result class in 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
    }
}

Usage should look like this 用法应如下所示

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

The problem occurs when I want to pass an error 当我想传递错误时出现问题

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

Below is real application usage: 以下是实际的应用程序用法:

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" causes compiler error: “ errorResult”导致编译器错误:

Generic parameter T could not be inferred 无法推断出通用参数T

Update: this approch works correctly: 更新:此方法正常工作:

Result<String>(error: errorFromSomewhere)

I'd like to suggest to use variant type for Result like this cause it is more compact and can be used in pattern matching naturally: 我想建议对Result使用变量类型,因为这样会更紧凑,并且可以自然地用于模式匹配:

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

Your code may become like this: 您的代码可能如下所示:

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)
                }
            })
        }
    }

} }

When you use classes instead of structs, you can define one base class (eg ErrorResult with init(error: NSError) ) and one derived Result<T> ) with init(data: T) ). 当使用类而不是结构时,可以定义一个基类(例如,带有init(error: NSError) ErrorResult ,以及带有init(data: T)一个派生的Result<T> )。

This way, you entirely side-step the generic parameter. 这样,您就完全避开了通用参数。 However, you potentially add some run-time overhead because of using a class. 但是,由于使用类,可能会增加一些运行时开销。

To answer your question directly, you could just declare errorResult as: 要直接回答您的问题,您可以将errorResult声明为:

var errorResult : Result<String>

That would fix the problem immediately. 那将立即解决问题。 However, I think the better solution is to use an enum instead of a struct as it is more appropriate (unless there is more to it than you posted). 但是,我认为更好的解决方案是使用枚举而不是结构,因为它更合适(除非它比您发布的内容多)。

enum Result<T> {
    case Data(T)
    case Error(NSError)

    var success : Bool {
        switch self {
        case .Data:
            return true
        case .Error:
            return false
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM