【问题标题】:Cast SomeType<Protocol> to SomeType<ProtocolImpl> in Swift在 Swift 中将 SomeType<Protocol> 转换为 SomeType<ProtocolImpl>
【发布时间】:2020-02-26 20:37:29
【问题描述】:

我目前正在 Swift 中使用泛型进行试验,但在将某些类型(例如 SomeType&lt;Protocol&gt; 转换为 SomeType&lt;ProtocolImpl&gt;)时遇到了一些问题。所以基本上我有一些类型,它接受一个作为协议处理的泛型参数,稍后将其转换为更具体的类型。我的问题是,如果这不可能吗?

/// 'dict' is of type [String: SomeType<Protocol>]
if let element = dict["str"], // 'element' here is of type SomeType<Protocol>
   let castedElement = element as? SomeType<ProtocolImpl> { // This is always false
    return castedElement // Here I want to return castedElement with type SomeType<ProtocolImpl>
}

有什么办法可以让这个演员工作?我已经在为我的问题寻找另一种解决方案,但我仍然对是否有办法以某种方式完成这项工作感兴趣。

编辑:因为@jtbandes 想要一个可以粘贴到某处的示例,所以在这里:

class SomeType<T> {
    let value: T

    init(value: T) {
        self.value = value
    }
}

protocol Protocol {}

class ProtocolImpl: Protocol {}

var dict: [String: SomeType<Protocol>] = ["str": SomeType(value: ProtocolImpl())]

if let element = dict["str"],
   let castedElement = element as? SomeType<ProtocolImpl> {
    print(castedElement.value) // I want to get here
}

【问题讨论】:

  • 您编写它的方式是不可能的,但如果您edit 您的问题包括minimal reproducible example,那么也许有人可以就不同的解决方案为您提供建议。
  • 您不能将dict[String:type] 转换为type。它是一个包含您的类型实例的字典,但它不是您的类型的实例,无论您如何抽象。
  • @Putz1103 代码中没有任何地方从字典转换为其他类型,请再次仔细阅读。 dict["str"] 的类型为 SomeType&lt;Protocol&gt;
  • 为什么不检查let castedElement = element.value as? ProtocolImpl。这应该可以正常工作。
  • @Putz1103 虽然这可以编译,但这不是我的目标。我想要从数组中引用 SomeType 对象,而不是 ProtocolImpl 对象。

标签: swift generics casting


【解决方案1】:

长话短说,Swift 中的泛型不是协变的,这意味着SomeType&lt; ProtocolImpl&gt; 是不可转换的SomeType&lt;Protocol&gt;,即使ProtocolImpl 符合Protocol。因此,您的问题的直接答案是:这在 Swift 中目前是不可能的。

但是,您可能会问自己,为什么首先需要沮丧。当您将实例存储在容器中时,多态行为可能更适合。您可以将需要访问的功能声明为协议的一部分,并且通过协议接口进行访问。这样你就不需要知道哪个是底层的具体实现,这是使用协议的主要原因之一。

【讨论】:

  • 非常感谢,我只是想知道是否有可能从字典中获得铸造参考。这个问题是在工作中出现的,因此我很想知道这是否可能。在大计划中,我们已经通过选择另一种数据结构来避免这些转换问题,但我仍然很感兴趣,因为我也想了解 Swift。
【解决方案2】:

我很难从这个问题中说出你想要达到的目标。不过,也许以下内容会对您有所帮助。

class SomeType<T>: Protocol { // Maybe SomeType IS your ProtoImpl?
    let value: T

    init(value: T) {
        self.value = value
    }
}

protocol Protocol {}

//class ProtocolImpl: Protocol {}

//var dict: [String: SomeType<Protocol>] = ["str": SomeType(value: ProtocolImpl())]
var dict: [String: Protocol] = ["str1": SomeType<String>(value: "Some Type"),
                                "str2": SomeType<Int>(value: 1)
                            ]

if let castedElement = dict["str1"] as? SomeType<String> {
    print(castedElement.value) // --> "Some Type"
}

if let castedElement = dict["str2"] as? SomeType<Int> {
    print(castedElement.value) // --> "1"
}

【讨论】:

  • 我应该更清楚地表明我的问题更具理论性,而不是由于选择了另一种数据结构而无法解决的问题。实际问题涉及 RxSwift BehaviorRelays。我只是想给出一个非常简单的问题场景。感谢您花时间回答我的问题,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多