简体   繁体   中英

Swift generics with default value

I'm trying to implement some single solution for each callbacks in application. So I want any callback use the same class, or at least family of classes.

  • Every callback can be successful or not.
  • If it is successful, it can contain some result of operation.
  • If it is not, it can contain information about what it is failed.

The common callbacks usage looks like this:

func foo(callback: ((success: Bool, result: Result?, error: Error?) -> Void)?) { }

Or:

func foo(success: ((result: Result) -> Void)?, failure: ((error: Error) -> Void)?) { }

I don't like any of them. I want to have single elegant solution for each callback. I found something similar in Alamofire library.

    enum CallbackResult<T, V> {
        case success(value: T?)
        case failure(error: V?)

        var isSuccess: Bool {

            switch self {
            case .success: return true
            case .failure: return false
            }
        }
    }

    func foo(callback: ((result: CallbackResult<Any, AnyObject>) -> Void)?) {
         callback?(result: .success(value: nil))
    }

This solution it nice. But like in my example, not always we need to pass any value or error as a parameter. Anyway, compiler always need to know what type generic parameters should be of. So even if I don't meter what type value is, I always should put there at least Any or AnyObject . It is overcomplicated.

I've tried to change it with class solution:

    class CallbackResult<T, V> {

        let isSuccess: Bool

        let value: T?

        let error: V?

        fileprivate init(success: Bool, value: T? = nil, error: V? = nil) {

            self.isSuccess  = success
            self.value      = value
            self.error      = error
        }

        static func success(value: T? = nil) -> CallbackResult {
            return CallbackResult(success: true, value: value)
        }

        static func failure(error: V? = nil) -> CallbackResult {
            return CallbackResult(success: false, error: error)
        }
    }

    func foo(callback: ((result: CallbackResult<Any, AnyObject>) -> Void)?) {
         callback?(result: CallbackResult.success(value: nil))
    }

It has the same functionality. But even in this way it didn't solve my problem. You can't just write like this:

CallbackResult<_, Error>

It will not work.

Maybe somebody know solution to my problem? Some way to put default value maybe^ not to write Any each time? Or for now there is only ugly way of using that approach?

Swift 3 added generic type aliases . These might help you avoid typing all types each time.

Example:

typealias AnyResult<E> = CallbackResult<Any, E>
typealias AnyCallback<E> = (AnyResult<E>) -> ()

func foo(callback: AnyCallback<String>?) {
    callback?(.failure(error: "Ouch!"))
}

foo() { result in
    if result.isSuccess {
        // ...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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