Andrey Gordeev
Andrey Gordeev

Reputation: 32529

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

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?

Upvotes: 11

Views: 14919

Answers (2)

dimpiax
dimpiax

Reputation: 12687

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

Upvotes: 3

vadian
vadian

Reputation: 285200

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

Upvotes: 10

Related Questions