如何检测该参数是两个任意类型的元组?

Ras*_*sto 5 types casting tuples type-conversion swift

我实际上正在做的事情更复杂,但归根结底是能够实现函数来检测某事物是一个元组,无论其元素的类型是什么。

这是我的方法,不起作用(请参阅最后一行的评论):

func isTuple(b: Any) -> Bool {
    return b is (Any, Any)
}

let myString = "aa"
let myDouble = 1.2
isTuple((myString, myDouble)) //returns false
Run Code Online (Sandbox Code Playgroud)

为什么不起作用?不应该Any也充当元组中的“通配符”吗?这是一个已知的 Swift 错误吗(如果不是,我应该将其视为一个错误并报告)吗?还有其他方法可以使isTupple方法发挥作用吗?


编辑

@NateCook 的答案完全回答了原来的问题,但它是否并不能帮助我做我想做的事情。就是这个:

我不仅需要确定某个东西是一个元组,而且还需要将其分解为两个值,而不知道这些值的确切类型。

这是代码:

func processIfTuple(b: Any) {
    if reflect(b).disposition == MirrorDisposition.Tuple {
        let (first, second) = b as (Any, Any) //error when casting
        process(first)
        process(second)
    }
}

func process(value: Any) {
    ...
}

processIfTuple(("aa", 1.2))
Run Code Online (Sandbox Code Playgroud)

由于测试不起作用的类似原因,这b is (Any, Any)不起作用。这次尝试投射时出现错误。这个问题能解决吗?如果不是,是否应该将其视为语言错误或缺少功能并报告?它肯定会导致大量代码重复,因为我需要测试元组的所有可能的类型对。

Nat*_*ook 2

您可以使用 Swift 的婴儿内省方法来实现这一点:

func isTuple(b: Any) -> Bool {
    return reflect(b).disposition == MirrorDisposition.Tuple
}
Run Code Online (Sandbox Code Playgroud)

请注意,这reflect很大程度上没有记录,可能仅作为对游乐场/调试器的支持,但据我所知,这是执行此操作的唯一方法。


为了实现这一点,您需要深入研究reflect()给您带来的东西,这是一个符合 的结构MirrorType,我将其称为反射,因为缺乏更好的术语。您可以为元组的反射添加下标以获取元组成员的反射,然后将值返回为Any。此时,您可以使用可选绑定来安全地重新发现底层类型:

func process(value: Any) {
    println("Any \(value)")
}

func process(value: String) {
    println("String \(value)")
}

func processTuple(b: Any) -> Bool {
    let isTuple = reflect(b).disposition == MirrorDisposition.Tuple

    let r = reflect(b)
    for i in 0..<r.count {
        println(r[i].0)         // string holding tuple part name: ".0", ".1", etc
        println(r[i].1.value)   // the value of that tuple part: "aa", 1.2

        process(r[i].1.value)   // calls process(Any)
        if let val = r[i].1.value as? String {
            process(val)        // calls process(String)
        }
    }

    return isTuple
}

let myString = "aa"
let myDouble = 1.2
processTuple((myString, myDouble)) //returns false
Run Code Online (Sandbox Code Playgroud)

输出:

.0
aa
Any aa
String aa
.1
1.2
Any 1.2
Run Code Online (Sandbox Code Playgroud)