使用Any类型是一个很好的解决方案时是否有任何具体的例子?

时间:2016-05-18 12:36:02

标签: swift types casting

我们都知道swift有一个强大的类型系统,因此我倾向于使用这个系统对我有利:)

以下是Apple对使用Any类型的看法:

  

为Any和AnyObject输入类型

     

Swift提供了两种特殊类型的别名,用于处理非特定的别名   类型:

     

AnyObject可以表示任何类类型的实例。任何可以   表示任何类型的实例,包括函数类型。   注

     

仅当您明确需要行为时才使用Any和AnyObject   他们提供的能力。具体而言总是更好   您期望在代码中使用的类型。

我不知道它是不是我,但我认为代码在使用时会开始闻到(这可能是我缺乏使用它们的经验) - 我知道AnyObject是必需的/有用的与Objective-C交互,因此我认为AnyObject的使用具有实用性。

所以我想知道具体的例子代表了Any类型的好用。

例如,它可用于将未知内容传递给POST请求构造函数方法,该方法可以安全地使用可选链接来检查未知内容。

来自Swift Programming Language (Swift 2.2)

的Apple示例
  

任何

     

以下是使用Any处理不同类型混合的示例,   包括函数类型和非类类型。该示例创建了一个   数组调用的东西,可以存储Any类型的值:

var things = [Any]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })

2 个答案:

答案 0 :(得分:2)

如果您使用的是纯Swift(没有遗留的Objective-C内容)并且您想要一个可以放置Int(s),Bool(s)和String的数组(s)然后你需要一个Any数组。

let values: [Any] = [1, true, "I'm not a pointer!"]

enter image description here

但是,等等我还可以使用AnyObject数组吗?

不。 Swift中的实际IntBoolStringstruct(s)。

他们为什么编译这段代码?

enter image description here

上面的代码编译是因为import Foundation确实启用了到Objective-C的桥接器。这意味着编译器允许Swift IntBoolString被视为对象,以保持与Objective-C的兼容性。

但是一旦删除import Foundation代码停止编译。

enter image description here

答案 1 :(得分:2)

我应该何时使用[Any]

Any是一种抽象类型,所有其他类型都隐式符合。因为它可能是任何 - 必须保证没有

由于这个原因,将变量键入Any是荒谬的。如果我定义这个:

let itCouldBeAnything : Any = "Actually it's a string"

它现在无法做任何事情(没有类型转换):

enter image description here

在定义某些内容时,您应始终使用最具描述性的类型,并且由于Any的抽象性质,始终是一种更具描述性的类型 - 在这种情况下,String应该已被使用。

现在让我们考虑数组。正如您所说,Apple演示您可以使用Any数组来混合不同类型。

var things = [Any]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))

大。但是这个数组实际上代表是什么?它只是垃圾的集合 - 相当于我汽车后座的编程。

如果我们尝试用其中一个元素做某事......

enter image description here

我们做不到。它可能是任何 - 所以我们不能对它做任何事情。当然,我们可以使用switchif语句键入转换元素来处理不同的可能性 - 但是我们所做的就是将数组拆分为不同的类型。那么使用[Any]开始时有什么意义呢?

数组应始终表示相关数据的集合。如果元素没有任何共同点,那么阵列就没有意义了。如果阵列可以存储的不同类型具有通用功能,那么您应该使用以下常用功能定义协议:

protocol ACommonProtocol {
    // define common functionality
}

然后我们可以使数组可以存储的类型符合它:

extension Int : ACommonProtocol {}
extension Double : ACommonProtocol {}
extension String : ACommonProtocol {}
extension Movie : ACommonProtocol {}

现在我们的数组可以是[ACommonProtocol]类型。这是Any重要改进,我们缩小了元素可以降低到4的具体类型 - 现在我们可以使用我们在协议中定义的任何常用功能没有类型转换的元素。我们的元素现在也显式相关,这实际上赋予了数组一些含义(假设协议代表一个有意义的概念)。

如果阵列可以存储的不同类型不要具有任何通用功能,或者不能符合协议(例如元组和函数),但仍然以某种有意义的方式相关 - 然后表达这种关系的另一种方式是使用enum和相关值:

// obviously this enum (and possibly its cases) should have a far better names
enum IntDoubleStringOrMovie { 
    case int(Int)
    case double(Double)
    case string(String)
    case movie(Movie)
}

现在我们的数组可以是[IntDoubleStringOrMovie]类型 - 它的另一个好处是允许我们使用详尽的switch来确定元素类型:

for element in array {
    switch element {
    case let .int(int):
        print(int)
    case let .double(double):
        print(double)
    case let .string(string):
        print(string)
    case let .movie(movie):
        print(movie)
    }
}

因此,您永远不必在Swift中使用[Any]。如果您发现自己处于使用[Any]的情况,您应该重新考虑您的数据结构。是否涉及将数组拆分为子数组,将元素符合通用协议(如果它们具有共同功能),使用具有关联值的枚举(如果它们没有共同功能)或使用不同的集合类型,则是完全取决于你。

但是与Objective-C接口呢?

Any有时需要与Objective-C的劣质类型系统进行桥接 - 因此您可能会发现自己使用带有Objective-C API的[Any],这是可以接受的(尽管the bridging of Objective-C's lightweight generics对Swift来说,它应该是不常见的。)

我唯一要说的是,一旦你回到你的Swift逻辑中,你应该总是通过类型转换将[Any]转换回有意义的数组类型,或者将其解压缩到更合适的数据结构中。你不应该因为Objective-C在这方面缺乏而牺牲Swift中的类型安全性。

但是[AnyObject]呢?

AnyObject与纯粹的Swift中的Any一样模糊。它唯一保证的是它是一个类。但是,从Swift 3开始,anything can be bridged to Objective-C被装在_SwiftValue中。出于这个原因,[AnyObject][Any]一样(如果不是更多)有问题。