2016-05-04 35 views
7

有两种情况让我混淆使用的Xcode 7.1,请参见下面的例子中发展迅速的2.2时,由于为什么在阵列

首先,当进口将多个类型的项目时,斯威夫特没有类型推断的任何基金会,我宣布它包含两个项目,一个Integer型和String类型的“hello”的testArray,我的问题是,为什么斯威夫特类型推断testArray到阵列(NSObject的),而不是阵列(任何)

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

二,当我删除导入基础,下面的代码不能编译,错误信息是“表达式的类型是不明确的,没有更多的内容”,我的问题是什么原因斯威夫特没有类型推断在这种情况下阵列(任何),用于帮助

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

回答

9
/// The protocol to which all types implicitly conform. 
public typealias Any = protocol<> 

Any阵列仅仅是所有类型的隐含遵循的协议 - 它不是一个具体的类型本身。斯威夫特无法推断非混凝土类型的数组,这就是为什么它不能推断Any,但NSObject成功(Int可桥接至NSNumberString可桥接至NSString - 他们都来自NSObject继承,这是一个具体的类型)。

例如,考虑这样的:

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

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

由于Foo是一个非混凝土类型,夫特不能推断它的一个数组。你必须明确地告诉你,你的类型是什么编译器:

let arr:[Foo] = [Bar(), Baz()] 

您还将获得与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 

为什么斯威夫特无法推断非混凝土类型的数组是最有可能是由于非混凝土类型语言的现有限制 - 目前具体的类型所需要的最非平凡的操作。 See this great Q&A for an example

但说实话,你真的应该更多地考虑你是否实际上需要一个Any数组。我想不出有一个具有Any数组的实际应用程序,因为一切都隐含地符合元素,它们必须保证什么都不做(你不能在任何可能的东西上调用特定的方法)。当然你可以打字,但是回到最初丢弃的类型安全有什么意义?

你应该总是尽可能的类型。你可以为你的值创建一个包装器 - 这可以是一个简单的struct来包装几个属性,或者是一个type erasure,以便将伪具体类型中的非具体类型包装起来。至少,你应该考虑创建你自己的协议,你的数组元素符合。

+2

最后两段提到了这里最重要的一点。说实话,'NSObject'(或者'AnyObject'不会在这里工作,但我总是看到它被使用)并不比'Any'更具体。 – nhgrif

+0

@ originaluser2你的解释真的很有帮助,非常感谢 – c41ux

+0

@ c41ux乐于帮助:) – Hamish

3

感谢因为它不会自动识别Any

阵列它会工作,如果你把它定义为

let testArray2 :[Any] = [2, "world"] 

Foundation的库进口NS API,其中自动转换所述2NSNumber"world"NSString,将其转换自然而然LY到NSObject

+2

1.回答:有趣的是,他问为什么,你只说,因为它是如此。 2.答案:如果你使用'import Foundation','2'是'Int',''world''是'String'。只是因为没有可以找到的本地Swift类型(谁知道它为什么不识别'[Any]'),它需要'[NSObject]'。 – Binarian

+2

@iGodric,嘿,你错了。看看他的错误:'表达式的类型是不明确的,没有更多的内容',它不能自动识别它,因为那是编译器的工作原理。 2.“NSObject”数组必须包含“NSObject”。如果您将执行'import Foundation'并执行下一个代码print(testArray [0] .dynamicType) print(testArray [1] .dynamicType),则输出将是NSNumber(而非Int)的__NSCFNumber和'_NSContiguousString'是'NSString'而不是String。感谢“Funny”评论。 –

+1

对1.是的,但解释说“这是编译器如何工作”是没有解释。 2.你说的是正确的,但你在我的评论中做出了假设,我没有这么说。是的,在这种情况下,当导入基金会和创建一个多种类型'2'的数组是'NSNumber'和''world''是'NSString'时,只是因为推断的类型是'[AnyObject]'。但是导入'Foundation'本身不会自动将'2'转换为'NSNumber',这正是我想说的。你的回答可能会引起误解。我的第一个评论可能听起来很苛刻。 – Binarian