Tuple “upcasting” in Swift

后端 未结 2 951
后悔当初
后悔当初 2020-12-20 15:16

If I have a tuple with signature (String, Bool) I cannot cast it to (String, Any). The compiler says:

error: cannot express

2条回答
  •  轮回少年
    2020-12-20 16:04

    Tuples cannot be cast, even if the types they contain can. For example:

    let nums = (1, 5, 9)
    let doubleNums = nums as (Double, Double, Double) //fails
    

    But:

    let nums : (Double, Double, Double) = (1, 5, 9) //succeeds
    

    The workaround in your case is to cast the individual element, not the Tuple itself:

    let tuple = ("String", true)
    let anyTuple = (tuple.0, tuple.1 as Any)
    // anyTuple is (String, Any)
    

    This is one of the reasons the Swift documentation notes:

    Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple.

    I think this is an implementation limitation because Tuples are compound types like functions. Similarly, you cannot create extensions of Tuples (e.g. extension (String, Bool) { … }).


    If you're actually working with an API that returns (String, Any), try to change it to use a class or struct. But if you're powerless to improve the API, you can switch on the second element's type:

    let tuple : (String, Any) = ("string", true)
    
    switch tuple.1 {
    
    case let x as Bool:
        print("It's a Bool")
        let boolTuple = (tuple.0, tuple.1 as! Bool)
    
    case let x as Double:
        print("It's a Double")
        let doubleTuple = (tuple.0, tuple.1 as! Double)
    
    case let x as NSDateFormatter:
        print("It's an NSDateFormatter")
        let dateFormatterTuple = (tuple.0, tuple.1 as! NSDateFormatter)
    
    default:
        print("Unsupported type")
    }
    

    If the API returns Any and the tuple isn't guaranteed to be (String, Any), you're out of luck.

提交回复
热议问题