Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 获取未知类型数组的元素和计数_Swift_Swift2.2 - Fatal编程技术网

Swift 获取未知类型数组的元素和计数

Swift 获取未知类型数组的元素和计数,swift,swift2.2,Swift,Swift2.2,假设我们有一个数组,分配给类型为Any let something: Any = ["one", "two", "three"] 让我们也假设我们不知道它是一个数组还是完全其他的东西。我们也不知道我们要处理的是什么类型的数组.Element 现在我们想知道它是否是一个数组 let isArray = something is Array // compiler error let isArray = (something as? [Any?] != nil) // does not work

假设我们有一个数组,分配给类型为
Any

let something: Any = ["one", "two", "three"]
让我们也假设我们不知道它是一个数组还是完全其他的东西。我们也不知道我们要处理的是什么类型的
数组.Element

现在我们想知道它是否是一个数组

let isArray = something is Array // compiler error
let isArray = (something as? [Any?] != nil) // does not work (array is [String] and not [Any?])
是否有任何优雅的解决方案可以从swift类型系统中获取以下信息:

  • 给定的对象是数组吗
  • 数组的计数是多少
  • 给我数组的元素

  • (桥接到NSArray对我来说不是一个解决方案,因为我的数组也可以是[Any?]类型,并且包含零值)

    我提出的唯一解决方案是以下解决方案,但我不知道它是否是最优雅的:)


    我喜欢@stefreak的问题和他的解决方案。记住@dfri关于Swift运行时内省的出色回答,我们可以在一定程度上简化和推广@stefreak的“类型标记”方法:

    protocol AnySequenceType {
        var anyElements: [Any?] { get }
    }
    
    extension AnySequenceType where Self : SequenceType {
        var anyElements: [Any?] {
            return map{
                $0 is NilLiteralConvertible ? Mirror(reflecting: $0).children.first?.value : $0
            }
        }
    }
    
    extension Array : AnySequenceType {}
    extension Set   : AnySequenceType {}
    //    ... Dictionary, etc.
    
    使用:

    关于允许协议扩展的可能性,请参见:

    extension<T> Sequence where Element == T?
    

    无论如何,所有这些让我明白的是,一旦你丢失了类型信息,就再也回不去了。即使您在
    Mirror
    上进行反思,您仍然会得到一个
    dynamicType
    ,您必须切换到一个期望的类型,以便可以强制转换值并将其作为一种类型使用。。。所有这些都是在运行时进行的,所有这些都永远不在编译时检查和健全性范围内。

    这对我来说非常有用:

    // Generate fake data of random stuff
    let array: [Any?] = ["one", "two", "three", nil, 1]
    // Cast to Any to simulate unknown object received
    let something: Any = array as Any
    
    // Use if let to see if we can cast that object into an array
    if let newArray = something as? [Any?] {
        // You now know that newArray is your received object cast as an
        // array and can get the count or the elements
    } else {
        // Your object is not an array, handle however you need.
    }
    

    我发现对
    AnyObject
    进行强制转换适用于对象数组。仍在研究值类型的解决方案

    let something: Any = ["one", "two", "three"]
    
    if let aThing = something as? [Any] {
        print(aThing.dynamicType) // doesn't enter
    }
    
    if let aThing = something as? AnyObject {
        if let theThing = aThing as? [AnyObject] {
            print(theThing.dynamicType) // Array<AnyObject>
        }
    }
    
    Any=[“一”、“二”、“三”]
    如果让aThing=某物作为?[任何]{
    打印(aThing.dynamicType)//不输入
    }
    如果让aThing=某物作为?任何对象{
    如果让thing=aThing为?[任何对象]{
    打印(theThing.dynamicType)//数组
    }
    }
    
    作为@milos和OP:s协议一致性检查的替代方法,我将添加一个方法,使用
    某物的运行时内省(
    foo
    bar
    ,在下面的示例中)

    用法示例:

    /* example usage */
    let foo: Any = ["one", 2, "three"]
    let bar: [Any?] = ["one", 2, "three", nil, "five"]
    
    if let foobar = getAsCleanArray(foo) {
        print("Count: \(foobar.count)\n--------")
        foobar.forEach { print($0) }
    } /* Count: 3
         --------
         one
         2
         three      */
    
    if let foobar = getAsCleanArray(bar) {
        print("Count: \(foobar.count)\n-------------")
        foobar.forEach { print($0) }
    } /* Count: 5
         -------------
         Optional("one")
         Optional(2)
         Optional("three")
         nil
         Optional("five")  */
    

    关键是,在运行时,它可以是任何东西的数组。我们如何才能转换
    某物
    ,所以我们实际上有了变量
    数组
    ?如果你已经知道它是一个数组,为什么不这样分配它呢
    让某物:[Any?]=[…]
    ?@EmilioPelaez实际上我从其他地方得到数组(作为另一个
    [Any]
    数组的元素之一),所以上面的任务是一个简化,所以更容易解释这个问题。扩展数组:P{};something is P
    您还可以使用类型内省来查看
    something
    是否具有集合显示样式,例如,如果让disp=Mirror(反射:something)。displaystyle其中disp==.collection{//is array},但是我相信上面的@milos协议一致性检查是理想的。我个人认为这不是一个问题,因为
    AnyArray
    协议不应该被随机结构和类类型所遵循:它应该只存在(我们应该能够让声明它的开发人员承担这么多责任)作为
    阵列
    的类型测试协议。因此,将上面的
    Dummy
    AnyArray
    一致,imho,实际上并没有涵盖我们可能遇到的实际情况(即使有点偏离“逻辑错误安全”并将其交给开发人员……)。非常感谢!)问题/区别到底是什么?另外,您非常好的三行解决方案只解决了我问题的第一部分(给定对象是数组吗),而不是第二部分。和3.@stefreak我相信milos在这里指出的是,当我们仅创建此协议用于检查某个对象是否是数组时,可以对某些结构/类/etc类型使用协议
    AnyProtocol
    (符合它)。如果有人像这样使用
    AnyArray
    ,它会在其他地方破坏我们的类型控制。因此,它确实描述了一个可能的问题,但是一个开发人员在逻辑错误中出错的问题。只要你在运行一个人的项目,你就很可能很安全,因为你知道自己永远不会让随机类型符合
    AnyArray
    。是的,很好地说@dfri。但我也是+1 stefreak的解决方案。Q和A都很好。@milos在你的最后一部分:只有在你的类型完全正确的情况下,条件转换才有效。因此,如果您将
    让maybies:Any=[1,nil]写为[Int?]
    并且
    让things:Any=[1,2]写为[Int]
    它将停止工作,因为您已经显式地将
    数组
    声明为数组(可选的
    Any
    :s)。OP描述的问题是,我们只知道
    某物
    可以通过类型
    任何
    捕获(即,可以是任何东西),并且
    某物
    不一定是数组。如果我们可以首先将
    某物
    声明为数组,那么这里就不会有任何问题。嗯,如果您将第一行替换为
    let array:[字符串?]=[“一”,“二”,“三”,零]
    @dfri我确实将
    数组
    声明为数组,因为
    let something:any=[…]
    不编译,正如你在答案中所看到的,
    数组
    只被用来强制转换为
    任何
    对象。@EmilioPelaez
    让一些东西:Any=[“一”、“二”、“三”]
    用Xcode 7.3/Swift 2.2为我编译。@JAL Try
    让数组:[Any?]=[“一”、“二”、“三”,nil,1]
    ,我试图模拟比“三个字符串”更随机的数据,但当某个东西是一个可选的数组时,它似乎不再起作用:(
    让某个东西:Any=[“一”、“二”、“三”,nil]作为[String?]
    @stefreak,这是因为
    Any
    optional
    更“可选”。
    things as? AnyObject as? [AnyObject] // [1, 2]
    
    // ... which at present (Swift 2.2) passes through `NSArray`, i.e. as if we:
    
    import Foundation
    things as? NSArray  // [1, 2]
    
    // ... which is also why this fails for `mabyies`
    maybies as? NSArray // nil
    
    // Generate fake data of random stuff
    let array: [Any?] = ["one", "two", "three", nil, 1]
    // Cast to Any to simulate unknown object received
    let something: Any = array as Any
    
    // Use if let to see if we can cast that object into an array
    if let newArray = something as? [Any?] {
        // You now know that newArray is your received object cast as an
        // array and can get the count or the elements
    } else {
        // Your object is not an array, handle however you need.
    }
    
    let something: Any = ["one", "two", "three"]
    
    if let aThing = something as? [Any] {
        print(aThing.dynamicType) // doesn't enter
    }
    
    if let aThing = something as? AnyObject {
        if let theThing = aThing as? [AnyObject] {
            print(theThing.dynamicType) // Array<AnyObject>
        }
    }
    
    /* returns an array if argument is an array, otherwise, nil */
    func getAsCleanArray(something: Any) -> [Any]? {
        let mirr = Mirror(reflecting: something)
        var somethingAsArray : [Any] = []
        guard let disp = mirr.displayStyle where disp == .Collection else {
            return nil // not array
        }
    
        /* OK, is array: add element into a mutable that
         the compiler actually treats as an array */
        for (_, val) in Mirror(reflecting: something).children {
            somethingAsArray.append(val)
        }
    
        return somethingAsArray
    }
    
    /* example usage */
    let foo: Any = ["one", 2, "three"]
    let bar: [Any?] = ["one", 2, "three", nil, "five"]
    
    if let foobar = getAsCleanArray(foo) {
        print("Count: \(foobar.count)\n--------")
        foobar.forEach { print($0) }
    } /* Count: 3
         --------
         one
         2
         three      */
    
    if let foobar = getAsCleanArray(bar) {
        print("Count: \(foobar.count)\n-------------")
        foobar.forEach { print($0) }
    } /* Count: 5
         -------------
         Optional("one")
         Optional(2)
         Optional("three")
         nil
         Optional("five")  */