【问题标题】:Swift - Any - Cannot convert value of type MyType<Int> to expected element type MyType<protocol<>>Swift - Any - 无法将 MyType<Int> 类型的值转换为预期的元素类型 MyType<protocol<>>
【发布时间】:2015-12-23 22:14:48
【问题描述】:

我在下面列出了一个相当人为的例子,来自我正在研究的更大的东西。我遇到了我认为是关于使用 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)

【问题讨论】:

  • 我认为问题在于 Swift 泛型不是协变的,也不是逆变的。通用混凝土类型仅等于相同的混凝土类型。您可以通过使用通用协议而不是任何类型约束来实现您想要的。查看 mike ash mikeash.com/pyblog/… 的这篇博文
  • 这就是我最终要做的。谢谢!

标签: arrays swift generics compiler-errors any


【解决方案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 的好处是我们可以将其向下转换为基本的 swift 类型。例如,考虑:

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 可以表示任何类型的实例,包括函数类型。

..

仅当您明确需要行为时才使用 Any 和 AnyObject 他们提供的能力。最好具体一点 您希望在代码中使用的类型。

【讨论】:

  • 嗯。这让我很沮丧。 “Any 可以表示任何类型的实例,包括函数类型。”在我看来,任何可以用 Swift 表示的 thing 实际上都是 Any。 print(12 as Any) 很好。我不清楚的是我希望allLabels 工作。这就是我关心的。这是我的解决方法。我对此并不满意,但是...
猜你喜欢
  • 1970-01-01
  • 2021-10-15
  • 2017-07-10
  • 2015-11-09
  • 1970-01-01
  • 2018-05-18
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多