Swift Generic Type conversion?

时间:2016-02-12 20:51:05

标签: swift generics

I am new to Swift, and I am trying to mess around with the generics a bit, but I am getting strange build errors that I don't understand. Here is the example code:

{ 
        "_id" : ObjectId("569d62673b020a47f0401325"), 

        "descriptors" : [
            {
                "id" : 123, 
                "name" : "Version", 
                "value" : "Latest based on new infor", 
                "parent" : null
            }, 
            {
                "id" : 345, 
                "name" : "Eligibility Criteria", 
                "value" : "Really qualified ", 
                "parent" : null
            }
        ],      
    }

    { 
        "_id" : ObjectId("569dac2e4e6247c01bbac47f"), 

        "descriptors" : [
            {
                "id" : 3221, 
                "name" : "Version", 
                "value" : "Latest new info", 
                "parent" : null
            }, 
            {
                "id" : 345, 
                "name" : "Eligibility Criteria", 
                "value" : "Different Value", 
                "parent" : null
            }
        ], 
    }

    { 
        "_id" : ObjectId("56bce4df7aae8369d8fc705d"), 
        "descriptors" : [
            {
                "id" : 3221, 
                "name" : "Version", 
                "value" : "Latest based on new infor", 
                "parent" : null
            }, 
            {
                "id" : 345.0, 
                "name" : "Eligibility Criteria", 
                "value" : "Really qualified", 
                "parent" : null
            }
        ], 

    }

OK, that seems odd since CGargabe is a CJunk... Let's try something a little more basic:

class CJunk
{
    var HowMuch:Int = 0
}

class CGarbage : CJunk
{

}

// This will not compile because:
// Cannot convert return expression of type 'CGarbage' to return type 'T'
func MakeGarbage<T:CJunk>(input:CJunk) -> T
{
    let x: CGarbage = CGarbage()
    x.HowMuch = input.HowMuch * 2;
    return x;
}

EDIT: The problem is that in each case I am erroneously trying to upcast. This actually has nothing to do with generics, and more with OOP fundamentals. The other problem is that I misinterpreted the error message. Ooops.

1 个答案:

答案 0 :(得分:1)

What MartinR already mentioned a bit more clearly stated:

ant.genkey(alias:$keyAlias, keystore:$keystoreLocation, storepass:$storePass, dname:'$dName) means that <T:CJunk> is one very specific subclass of T. Since you try to return CJunk or CGarbage there is no guarantee whatsoever that that returned class actually matches the specific CJunk - it may not be convertable.

Your example is so simply that generics is simply overkill and the easy solution is to drop them altogether since your function returns the same type all the time any way:

T

We will be happy to help with more complex generics problems - this one is so basic that it simply does not make any sense at all to use generics at all.

If you think about your generic Method the compiler has to somehow infer the type func MakeGarbage(input:CJunk) -> CGarbage { let x: CGarbage = CGarbage() x.HowMuch = input.HowMuch * 2; return x; } or you have to specify the type. The compiler cannot infer it in the first place, if you would get over the initial compiler error. Therefore you as the developer would have to provide the type of T explicitly. When you do that and specify that T has to actually be T then it is easy to see why the compiler complains in the first place, because now your method will return a YourSecondSubclass which is clearly not convertable to CGarbage. I hope that explains it a bit!?

Consider the following

YourSecondSubclass

The compiler no goes ahead and infers class CJunk { var HowMuch:Int = 0 } class CGarbage : CJunk { } class MoreGarbage : CJunk { } func MakeGarbage<T:CJunk>(input:CJunk) -> T { let x: CGarbage = CGarbage() x.HowMuch = input.HowMuch * 2; return x; } var more : MoreGarbage = MakeGarbage(CJunk()) to be T since that is the expected return type, no unfortunately the actual returned type MoreGarbage has nothing to do with CGarbage.

This argument works for both cases exactly the same: the compiler infers the type of MoreGarbage from the caller and there is no guarantee that the you can convert T to CJunk.