2015-08-16 59 views
1

有人可以向我解释为什么下面的代码似乎无法区分数值类型?按类型筛选Swift数组的奇怪行为

extension Array { 
    func filterByType<T>(type: T.Type) -> [T] { 
     var r = [T]() 
     for case let m as T in self { 
      r += [m] 
     } 
     return r 
    } 
    func filterByType2<T>(type: T.Type) -> [T] { 
     var r = [T]() 
     for m in self { 
      if m is T { 
       r += [m as! T] 
      } 
     } 
     return r 
    } 
} 

let objects = [1, "2", 3, "4", 5.1, [1, 2]] 

typealias IntArray = [Int] 

objects.filterByType(String.self) // ["2", "4"] - as expected 
objects.filterByType(IntArray.self) // [[1, 2]] - as expected 
objects.filterByType(Double.self) // [1, 3, 5.1] - ok, but surprised 1 & 3 aren't Ints 
objects.filterByType(Int.self) // [1, 3, 5] - why? 

objects.filterByType2(String.self) // ["2", "4"] - as expected 
objects.filterByType2(IntArray.self) // [[1, 2]] - as expected 
objects.filterByType2(Double.self) // [1, 3, 5.1] - ok, but surprised 1 & 3 aren't Ints 
objects.filterByType2(Int.self) // [1, 3, 5] - why? 
+1

你可以试试这个用'让对象:[任何] = ...'?我得到了您期望的结果,但我已经安装了较早的Xcode。 – dasblinkenlight

+0

@dasblinkenlight:你说得对,这也给了Xcode 7 beta 5的“预期”结果。 –

回答

3

在没有任何类型的注释,所述异源阵列

let objects = [1, "2", 3, "4", 5.1, [1, 2]] 

的类型被推断为[NSObject]。特别是,这些号码被转换为 到NSNumber对象。从NSNumberDoubleInt的(有条件的)演员总是成功并使用doubleValueintegerValue 方法。

这可以被看作具有下列简单的例子:

let n1 = NSNumber(integer: 123) 
if let x = n1 as? Double { // warning: conditional cast from 'NSNumber' to 'Double' always succeeds 
    print(x) // 123.0 
} 

let n2 = NSNumber(double: 12.8) 
if let x = n2 as? Int { // warning: conditional cast from 'NSNumber' to 'Double' always succeeds 
    print(x) // 12 
} 

参见

+0

优秀的答案。非常感谢。 – Grimxn

0

我认为有以下两行filterByTypefilterByType2被铸造IntDouble值。 String[Int]类型给出了预期的结果,因为这些不能被转换。

for case let m as T in self { 
// ... 
r += [m as! T] 

1,3,5.1可被铸造为DoubleInt

1

目的阵列被推断为NSObject类型和数量是NSNumber类型可浇铸IntDouble甚至Bool(可能意外)的。

因此,为了获得所需的行为,应明确声明你的阵列的类型为[Any]

至于改进的算法,我会建议使用flatMap

extension Array { 
    func filterByType<T>(type: T.Type) -> [T] { 
     return self.flatMap{ $0 as? T } 
    } 
}