为什么当在Array中放置多个类型项时,Swift不会对Any进行类型推断

c41*_*1ux 7 arrays types type-inference swift anyobject

有两种情况让我在使用Xcode 7.1开发swift 2.2时感到困惑,请看下面的例子,谢谢

首先,当导入Foundation时,我声明了一个testArray,它包含两个项目,一个Integer类型1和一个String类型"hello",我的问题是为什么Swift类型推断testArray到Array(NSObject)而不是Array(Any)

import Foundation
let testArray = [1, "hello"] 
print(testArray.dynamicType) //testArray is Array<NSObject>
Run Code Online (Sandbox Code Playgroud)

其次,当我删除import Foundation时,下面的代码无法编译,错误信息是"表达式的类型没有更多内容",我的问题是为什么Swift在这种情况下没有对Array(Any)进行类型推断,谢谢求助

let testArray2 = [2, "world"]
print(testArray2) 
//can't compile, error message = "Type of expression is ambiguous without more content"
Run Code Online (Sandbox Code Playgroud)

Ham*_*ish 9

/// The protocol to which all types implicitly conform.
public typealias Any = protocol<>
Run Code Online (Sandbox Code Playgroud)

Any只是一个所有类型都隐式符合的协议 - 它本身不是具体类型.Swift无法推断出非具体类型的数组,这就是为什么它无法推断Any,但是成功NSObject(Int可以桥接NSNumber,String可以桥接到NSString- 并且它们都继承自NSObject,这是具体类型).

例如,考虑一下:

protocol Foo {}
struct Bar:Foo {}
struct Baz:Foo {}

let arr = [Bar(), Baz()] // error: Type of expression is ambiguous without more context
Run Code Online (Sandbox Code Playgroud)

因为Foo是非具体类型,Swift无法推断出它的数组.您必须明确告诉编译器您希望其类型是什么:

let arr:[Foo] = [Bar(), Baz()]
Run Code Online (Sandbox Code Playgroud)

您也将获得相同的行为AnyObject(因为它是所有隐式符合的协议- 但仍然不是具体类型):

class Qux {}
class Fox {}

let a = [Qux(), Fox()] // error: Type of expression is ambiguous without more context

let a1:[AnyObject] = [Qux(), Fox()] // no error
Run Code Online (Sandbox Code Playgroud)

为什么 Swift无法推断出非具体类型的数组很可能是由于语言中非具体类型的现有限制 - 目前大多数非平凡操作都需要具体类型.请参阅这个很棒的问答例子.

但说实话,你真的应该考虑更多关于你是否真的需要一系列的Any.我想不出有一个数组的实际应用Any,因为因为一切都隐含地符合元素,所以必须保证它们什么都不做(你不能在可能是任何东西的东西上调用特定的方法).当然你可以打字,但是重新开始你扔掉的类型安全有什么意义呢?

您应该始终尽可能地具体类型.您可以为您的值构建一个包装器 - 这可能是一个简单struct的包装几个属性,或者是一个类型擦除,以便在伪具体类型中包装非具体类型.至少,您应该考虑创建自己的数组元素符合的协议.

  • 最后两段提出了最重要的观点.老实说,"NSObject"(或者"AnyObject"在这里不起作用,但我看到它一直使用)并不比"Any"更具体. (2认同)