Swift - Any - 无法将MyType <int>类型的值转换为预期的元素类型MyType <protocol <>&gt;

时间:2015-12-23 22:14:49

标签: arrays swift generics compiler-errors any

我在下面列出了一个相当人为的例子来自我正在研究的更大的东西。我遇到了我认为是关于使用Any类型的Swift编译器错误。

struct Labelable <T> {
  let t: T
  let label: String
}

func allLabels(labelables: [Labelable<Any>]) -> [String] {
  return labelables.map { $0.label }
}

let labeledInt = Labelable(t: 22, label: "Steve's Age")
let labeledString = Labelable(t: "Johnson", label: "Stacy's last name")

let labels = allLabels([labeledInt, labeledString])

print(labels)

有问题:

Cannot convert value of type 'Labelable<Int>' to expected element type 'Labelable<protocol<>>'

有没有人对此问题和任何变通方法有任何见解?或许,有一种更好的方法来完成我想要做的事情?

由于

编辑:

这就是我最终要做的事情。啊。

protocol LabelableProtocol {
  var label: String { get }
}

struct Labelable <T>: LabelableProtocol {
  let t: T
  let label: String
}

func allLabels(labelables: [LabelableProtocol]) -> [String] {
  return labelables.map { $0.label }
}

let labeledInt = Labelable(t: 22, label: "Steve's Age")
let labeledString = Labelable(t: "Johnson", label: "Stacy's last name")

let labels = allLabels([labeledInt, labeledString])

print(labels)

1 个答案:

答案 0 :(得分:1)

这里的问题是Any不是类型,而是协议。您可以通过尝试通过其他协议扩展它来看到这一点(不允许其他协议的协议扩展):

protocol MyDummyProtocol {}

extension Int : MyDummyProtocol {} // OK

extension Any : MyDummyProtocol {} 
    //Error: Non-nominal type Any (aka protocol<>) cannot be extended.

因此,在调用allLabels时,您无法将IntString类型转换为Any协议。

但是,您可以在结构中专门使用Any作为通用T

let labelAny = Labelable<Any>(t: 22, label: "Steve's Age")
let labelAnyAgain = Labelable<Any>(t: "Johnson", label: "Stacy's last name")

let labels = allLabels([labelAny, labelAnyAgain]) // OK

但是,这里更有趣的是研究结构中的通用属性t。现在应该是Any,对吧?关于Any的好处是我们可以将它转变为基本的快速类型。例如,考虑:

struct Labelable <T> {
    let t: T
    let label: String
}

func allGenerics(labelables: [Labelable<Any>]) -> [Any] {
    return labelables.map { $0.t }
}

let labelAny = Labelable<Any>(t: 22, label: "Steve's Age")
let labelAnyAgain = Labelable<Any>(t: "Johnson", label: "Stacy's last name")

let labelsGeneric = allGenerics([labelAny, labelAnyAgain])

for label in labelsGeneric {
    switch label {
    case is Int: print("is int: " + "\(label)")
    case is String: print("is string: " + "\(label)")
    default: print("Default...")
    }
}
// Prints:
// is int: 22
// is string: Johnson

在这里,我们使用Any作为通用(即使它特别是Any),然后简单地让向下投射is成为我们的通用行为。

有关详细信息,请参阅Language Guide - Type Casting - Type Casting for Any and AnyObject

  

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

     

...

     

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