How to use a generic type as the function's return type?

protocol TestReturnTypeProtocol {
    associatedtype T
    func test(_ type: T)
}

protocol Testable {}

extension Int: Testable { }
extension String: Testable { }

class AnyTestReturnType<Type>: TestReturnTypeProtocol where Type: Testable {
    init<P: TestReturnTypeProtocol>(_ p: P) where P.T == Type { }
    func test(_ type: Type) { }
}

class IntReturnClass: TestReturnTypeProtocol {
    func test(_ type: Int) { }
}
class StringReturnClass: TestReturnTypeProtocol {
    func test(_ type: String) { }
}


func tesfFunction<T: Testable>(isInt: Bool) -> AnyTestReturnType<T> {
    if isInt {
        let intRet = AnyTestReturnType(IntReturnClass())
        return intRet
    } else {
        let strRet = AnyTestReturnType<String>(StringReturnClass())
        return strRet
    }
}

I can use the as! T to solve this question, It will complain Cast from 'AnyTestReturnType <Int>' to unrelated type 'AnyTestReturnType <T>' always fails

When using genetics, the generic types are chosen by the call site. That is, the function is not free to return any type that conform to the constraints, but rather the caller is free to request any return type that conform to the constraints.

If your goal is just to hide the returned type, you can use an opaque return type instead of generics. However, you’ll need to wrap the returned value in an enum because every returned value must have the same type when you use an opaque return type.

protocol Testable {
    func test()
}

class Int: Testable {
    func test() { }
}

class String: Testable {
    func test() { }
}

func testFunction(isInt: Bool) -> some Testable {
    enum OpaqueEnum: Testable {
        case int(Int)
        case string(String)

        func test() {
            switch self {
            case .int(let x):
                x.test()
            case .string(let x):
                x.test()
            }
        }
    }
    if isInt {
        let intRet = OpaqueEnum.int(Int())
        return intRet
    } else {
        let strRet = OpaqueEnum.string(String())
        return strRet
    }
}
Terms of Service

Privacy Policy

Cookie Policy