【问题标题】:How to tell if a variable is an array如何判断变量是否为数组
【发布时间】:2014-10-07 00:40:29
【问题描述】:

我有一个接受 Any 的 Swift 函数,我希望它能够接受字符串数组、整数数组、混合数组或数组数组等。它也可以只接受字符串或不在数组中的 Int 等。

所以我有这个:

    private func parse(parameter: Any) {
        if parameter is Int {
            // Int
        } else if (parameter is Float) || (parameter is Double) {
            // Double
        } else if parameter is String {
            // String
        } else if parameter is Bool {
            // Bool
        } else if let array = parameter as? [Any] {
            // Should catch all Arrays
        } else {
            assert(false, "Unsupported type") // [String] ends up here
        }
    }

但如果我调用parse(["Strings"]),则会引发断言。如何捕获所有类型的数组?

编辑 - 我想要完成的工作有些混乱。我基本上需要根据类型返回一个String,所以Int->“”和String->“”,所以一个数组会递归调用返回“...”

这篇文章被标记为重复,但另一个问题是关于 Javascript,而不是 Swift。

【问题讨论】:

  • user3352495 false,对 [Any] 的检查仍然无法按预期工作(Swift 5)

标签: arrays swift


【解决方案1】:

我终于找到了办法,那就是使用NSArray进行强制转换。

private func parse(x: Any) {
    if let o = x as? [Any] {
        println("[Any]")
    }
    if let o = x as? [AnyObject] {
        println("[AnyObject]")
    }
    if let o = x as? NSArray {
        println("NSArray")
    }
}

let a: [Any] = ["bar"]
let b: [AnyObject] = ["bar"]
let c = ["foo", 3.14]

parse(a) // ==> [Any]
parse(b) // ==> [AnyObject], and also NSArray
parse(c) // ==> NSArray

看起来包含Any 值的数组内部表示为NSArray。 (但它应该能够将c 转换为[Any]...吗?我怀疑这是一个错误。)

【讨论】:

  • 给我一点时间在我的实现中尝试这个想法!
  • 砰!这样可行!我将继续尝试简化,以便为雷达提供一个很好的示例,但同时我会使用它。
  • Swift 5 看起来它不再工作了..“错误:无法将类型 'String' 的值转换为预期的元素类型 'AnyObject'” for line let b: [AnyObject] = [ “酒吧”]
【解决方案2】:

在 Swift 中理解类型和类型相关问题的关键是条条道路通向协议。

这个问题的挑战在于检测任何类型的数组,而不仅仅是一种具体的类型。 OP 的示例失败了,因为 [Any] 不是 [String] 的基类或通用模式,也就是说,(据我所知),在 Swift [T] is not covariant on T 中。除此之外,您无法检查 SequenceType 或 CollectionType,因为它们具有关联的类型 (Generator.Element)。

因此,惯用的解决方案是使用 marker 协议来指示您希望哪些类型符合您的标准。如下图所示,您可以通过创建一个空协议并将其与感兴趣的类型相关联来实现这一点。

import Foundation


protocol NestedType {}
extension Array: NestedType {}
extension Set: NestedType {}
extension Dictionary: NestedType {}
extension NSSet: NestedType {}

protocol AnyTypeOfArray {}
extension Array: AnyTypeOfArray {}
extension NSArray: AnyTypeOfArray {}

protocol AnyTypeOfDictionary {}
extension Dictionary: AnyTypeOfDictionary {}


func printType(v:Any) {
    if v is NestedType {
        print("Detected a nested type")
    }

    if v is AnyTypeOfArray {
        print("\t which is an array")
    }

    else if v is AnyTypeOfDictionary {
        print("\t which is a dictionary")
    }
}


printType([String:Int]())
printType([Int]())
printType(NSArray())

其输出为:

Detected a nested type
     which is a dictionary
Detected a nested type
     which is an array
Detected a nested type
     which is an array

【讨论】:

  • 这是正确答案。还有最“迅速”的?
【解决方案3】:

您可以这样做的一种方法是将函数分成两个单独的实现(具有相同的名称),一个采用Array,另一个用于其他所有实现。您还需要使它们成为通用函数,而不是使用 Any 类型。通过这种设置,Swift 可以使用类型推断来找出要调用的最佳函数。

我会像这样实现它(我只是 printlning 类型以显示事情的结局):

func parse<T>(parameter: T) {
    if parameter is Int {
        println("Int")
    } else if (parameter is Float) || (parameter is Double) {
        println("Double")
    } else if parameter is String {
        println("String")
    } else if parameter is Bool {
        println("Bool")
    } else {
        assert(false, "Unsupported type")
    }
}

func parse<T>(parameter: Array<T>) {
    println("Array")
    for element in parameter {
        // Recursively parsing...
        parse(element)
    }
}

然后这样称呼它:

parse(1)  // Int
parse(0.1) // Double
parse("asdf") // String
parse(true) // Bool
parse(["asdf", "asdf"]) // Array -> String String

输出:

Int
Double
String
Bool
Array
String
String

【讨论】:

  • 按原样运行代码可以完美运行。但是,在我的代码上下文中运行它会破坏它。我正在从 [Any] 类型的数组中解压缩参数并在每个元素上调用 parse()。无论元素是什么,都会调用第一个函数,而不是第二个。
  • 这失败了:parseAny([["a", "b", "c"]]) func parseAny(values: [Any]) { for value in values { parse(value) } }
  • 同样如此,只是将 parseAny([Any]) 更改为 parseAny(Array)
  • 嗯,是的,你是对的......我不知道为什么,但我会考虑一下,看看我能不能想出点什么。
  • 我唯一能想到的另一件事是某种包装结构。
【解决方案4】:

您可以使用 _stdlib_getTypeName 返回给定值的错位类型名称。

例如:

    var myString = "String"
    var myInteger = 10
    var myArray = [10,22]
    var myDictionary = ["one": 1, "two": 2, "three": 3]
    println("\(_stdlib_getTypeName(myString))")
    println("\(_stdlib_getTypeName(myInteger))")
    println("\(_stdlib_getTypeName(myArray))")
    println("\(_stdlib_getTypeName(myDictionary))")

结果将是:

_TtSS // for String
_TtSi // for integer
_TtSa // for array
_TtVSs10Dictionary // for dictionary

【讨论】:

  • 这在技术上会让我知道我何时获得了数组,但不会让我在不尝试强制转换的情况下将其视为数组。问题是,使用parameter as [Any] 强制向下转换会导致运行时崩溃。此外,这是超级hacky。
猜你喜欢
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 2011-08-17
  • 2014-12-27
相关资源
最近更新 更多