一尘不染

Swift中的元组“转换”

swift

如果我有带签名的元组,(String, Bool)则无法将其强制转换为(String, Any)。编译器说:

错误:无法表示元组转换((String,Bool)’到’(String,Any)’

但这应该可行,因为Bool可以安全地Any使用它as。如果执行类似的操作,几乎会引发相同的错误:

let any: Any = ("String", true)
any as! (String, Any) // error
any as! (String, Bool) // obviously succeeds

错误:

无法将类型’(Swift.String,Swift.Bool)’的值强制转换为’(protocol <>,protocol <>))

那么,有什么变通办法,尤其是对于第二种情况?因为您甚至无法转换Any(Any, Any)可以分别转换元素的任何元组。


阅读 254

收藏
2020-07-07

共1个答案

一尘不染

即使元组可以包含类型,也不能强制转换。例如:

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

但:

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

您的解决方法是强制转换单个元素,而不是元组本身:

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

这是Swift文档指出的原因之一:

元组对于相关值的临时组很有用。它们不适合创建复杂的数据结构。如果您的数据结构可能会在临时范围之外继续存在,则将其建模为类或结构,而不是元组。

我认为这是一个实现限制,因为元组是像函数一样的 复合类型 。同样,您不能创建元组的扩展名(例如extension (String, Bool) { … })。


如果您实际上使用的是会返回的API (String, Any),请尝试将其更改为使用类或结构。但是,如果您无力改善API,则可以switch使用第二个元素的类型:

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

如果API返回Any并且不能保证元组为(String, Any),那么您就不走运了。

2020-07-07