简体   繁体   中英

Swift Protocols with Associated Type and Generics calling wrong function

I have tried to keep my question very simple. I have been struggling whole day to make it work but no luck. I have two protocols. Decodable and Requestable.

protocol Decodable { }
struct D: Decodable { }

protocol Requestable {
    associatedtype Model
}

extension Requestable {
    func returnValue() {
        Utils.doSomething(Model)
    }
}

And a class Utils

class Utils {
    static func doSomething<T>(param: T) {
        print("Default")
    }

    static func doSomething<T: Decodable>(param: T) {
        print("Decodable")
    }

    static func doSomething<T: Decodable>(param: [T]) {
        print("Decodable Array")
    }
}

I create a struct R implementing Requestable and give the type alias Model to String

struct R: Requestable {
    typealias Model = String
}

When i run the R().returnValue() function, It prints Default . As Expected.

I create a struct R2 implementing Requestable and give the type alias Model to D which is implementing Decodable

struct R2: Requestable {
    typealias Model = D
}

When i run the R2().returnValue() function, It prints Default . but i was expecting it would print Decodable because the Model D conforms to Decodable .

I create a struct R3 implementing Requestable and give the type alias Model to [D] where the element of array is implementing Decodable

struct R3: Requestable {
    typealias Model = [D]
}

When i run the R3().returnValue() function, It prints Default . but i was expecting it would print Decodable Array because the Model D conforms to Decodable .

Any kind of help appreciated.

UPDATE

Using AnyRequestable and checking in runtime will not work in this case because in real code the Generic is the return value and could not be checked dynamically.

In real code functions signatures are like

public static func ResponseSerializer<M>() -> ResponseSerializer<M, NSError> {}
public static func ResponseSerializer<M: Decodable>() -> ResponseSerializer<M, NSError> {}
public static func ResponseSerializer<M: Decodable>() -> ResponseSerializer<[M], NSError> {}

This is the expected result. You forgot to declare the Decodable conformance for your Model associated type. This should fix it:

protocol Requestable {
    associatedtype Model: Decodable
}

Edit: Reading your comments, I now understand your problem. The thing is, what you're asking of requires the runtime, there is no way to statically achieve it:

class Utils {
    static func doSomething<T>(param: T) {
        if let param = param as? Decodable {
            print("Decodable")
        } else {
            print("Default")
        }
    }
}

Think about it; when you are compiling your code, in the scope of returnValue , the compiler only knows that Model is an associated type and nothing else. Either you explicitly declare the conformance Decodable , or the compiler assumes the default case, which is just <T> .

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