Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift generics error: Cannot convert value of type 'Type<T>' to expected argument type 'Type<_>'

Tags:

generics

swift

Please consider this setup:

protocol MyProcotol {
}

class MyModel: MyProcotol {
}

enum Result<T> {
    case success(value: T)
    case failure
}

class Test {
    func test<T: MyProcotol>(completion: (Result<T>) -> Void) {
        let model = MyModel()
        let result = Result.success(value: model)
        completion(result)
    }
}

Why can't I call completion(result)? I'm getting this error:

Cannot convert value of type 'Result' to expected argument type 'Result<_>'

Any workaround?

like image 469
Andrey Gordeev Avatar asked May 17 '17 08:05

Andrey Gordeev


People also ask

What is the use of Swift optional variable?

Swift optional variables make code safer if you forget to give an initial value to a variable. The swift optional variable can have a value or be nil if have no value. But in real programming, we need to get the original value that is wrapped by the optional variable.

How to change the value of a variable in Swift?

You can declare a swift variable as a variable ( var name: String = "jerry ") that value can be changed in code, a constant ( let x:Int = Int (10) ) that value can not be changed, and an optional variable ( var x:Int? ) that value can be changed and does not need to be initialized.

What is [T] in Swift placeholder type?

@Hamish From the swift docs: "The placeholder type name doesn’t say anything about what T must be, but it does say that both a and b must be of the same type T, whatever T represents". So, when we say [T], it must be an array of all the same types. I absolutely agree.

How to unwrap an optional variable that does not have value?

When you want to unwrap an optional variable that does not has a value that means the variable value is nil, if you use force unwrap in this case, you will encounter an error like below. // Declare an optional variable, the variable do not has value then it's value is nil.


2 Answers

You are using a non-generic concrete type MyModel in a generic function, that doesn't work.

You could do something like this

class Test {
    func test<T: MyProcotol>(item: T, completion: (Result<T>) -> Void) {
        let result : Result<T> = .success(value: item)
        completion(result)
    }
}
like image 158
vadian Avatar answered Sep 22 '22 10:09

vadian


You can convert your potential generic value with force cast.

Swift 4

protocol MyProcotol {}

struct MyModel: MyProcotol {
    let x: Int
}

struct TheirModel: MyProcotol {
    let y: Int
}

enum Result<T> {
    case success(value: T)
    case failure

    var value: T? {
        switch self {
            case .success(let value): return value
            case .failure: return nil
        }
    }
}

struct Test {
    enum ModelType {
        case my, their
    }

    static func get<T: MyProcotol>(type: ModelType, completion: (Result<T>) -> Void) {
        let model: Any
        switch type {
            case .my: model = MyModel(x: 42)
            case .their: model = TheirModel(y: 19)
        }

        if let value = model as? T { completion(.success(value: value)) }
        else { completion(.failure) }
    }
}

Test.get(type: .my) { (result: Result<MyModel>) in
    guard let value = result.value else { return }
    print("here is MyModel \(value) with value: \(value.x)")
}

Test.get(type: .their) { (result: Result<TheirModel>) in
    guard let value = result.value else { return }
    print("here is TheirModel \(value) with value: \(value.y)")
}

Test.get(type: .their) { (value: Result<MyModel>) in
    print("here is failure? \(value)")
}
like image 38
dimpiax Avatar answered Sep 23 '22 10:09

dimpiax