【问题标题】:How do I define extension for Dictionary of specific type?如何为特定类型的字典定义扩展名?
【发布时间】:2018-10-05 07:37:11
【问题描述】:

我创建了typealias:

typealias Multilang = [String: Any]

现在我想用属性localized 扩展那个字典。有可能吗?

我需要如何使用它?

let dictionary: Multilang = ["en": "b", "pl": "d"]()
let value = dictionary.localized

我尝试这样做:

extension Dictionary where Dictionary: Multilang {
    var localized: String {
        print("self: \(self)")
        return "hello"
   }
}

但它不起作用。为什么?

类型 'Dictionary(Key, Value)' 受限于非协议、非类类型 'Multilang'(又名'Dictionary(String, Any)')

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    你可以这样写一个扩展:

    extension Dictionary where Key == String, Value == Any {
        var localized: String {
            print("self: \(self)")
            return "hello"
        }
    }
    

    或:

    extension Dictionary where Dictionary == Multilang
    

    【讨论】:

    • 但这种方式将扩展为每个[String: Any] 类型的字典,即使对于那些未定义为Multilang 的字典。
    • 不如试试这样的:extension Dictionary where Dictionary == Multilang
    • @BartłomiejSemańczyk 这不是类型别名的工作方式。编译器将所有类型别名交换为它们在编译时 表示的实际类型,因此类型别名实际上不会创建新类型,并且类型系统不了解类型别名。所以你想要做的事情是不可能的。
    【解决方案2】:

    (很遗憾)不能以这种方式使用typealias,因为它不会创建新类型。例如,您可以拥有typealias Foo = [String: Any]typealias Bar = [String: Any],但FooBar 仍然是同一类型。

    所以要么你必须扩展所有[String: Any] 字典,要么你需要创建一个包装器类型(你也不能继承Dictionary,因为它是一个struct)。例如:

    struct Multilang<Element> {
        var dictionary: [String: Element]
        var localized: Element? {
            return dictionary[currentLanguage]
        }
    }
    

    缺点是您需要通过multilang.foo 语法定义要使用的所有包装器方法和属性,但如果只有multilang.localized 就足够了,您可以通过multilang.dictionary.foo 完成所有其余操作。

    您还可以实现ExpressibleByDictionaryLiteral 来轻松创建这些对象:

    extension Multilang: ExpressibleByDictionaryLiteral {
        init(dictionaryLiteral elements: (String, Element)...) {
            dictionary = .init(elements) { $1 }
        }
    }
    
    let multilang: Multilang = [ "en": "English", "pl": "Polish" ]
    

    【讨论】:

      【解决方案3】:

      对于 Swift 3 及更高版本,您可以尝试此方法来扩展 [String: Any] 类型的字典。

      extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
          // Your extension code
          var localized: String {
          print("self: \(self)")
          return "hello"
      }
      

      ExpressibleByStringLiteralStringStaticString 类型遵循的协议。

      你不能只将它应用于类型别名,因为Multilang 只是[String:Any] 的一个标签,所以即使你可以扩展它,它仍然会扩展这种类型的所有字典。

      【讨论】:

      • 好的,但我如何only 使用Multilang 类型?不是[String: Any]
      • @BartłomiejSemańczyk 我不认为你可以,因为Multilang 只是[String:Any] 的标签,所以即使你可以扩展它,它也会扩展这种类型的所有字典。
      • @BartłomiejSemańczyk 请参阅this answer 了解更多信息。
      猜你喜欢
      • 1970-01-01
      • 2020-08-31
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      相关资源
      最近更新 更多