【问题标题】:Can one extend a Swift Dictionary by a struct?可以通过结构扩展 Swift 字典吗?
【发布时间】:2016-11-23 14:07:51
【问题描述】:

我已经尝试过extension of Dictionary where <String, AnyObject> 中的解决方案,但它不会为我编译。

我只是想将字典扩展限制为struct 类型。有没有办法做到这一点?

import Cocoa

struct Foo: Hashable {
    let bar: String

    static let predefinedFoo = Foo(bar: "something")

    var hashValue: Int { return bar.hashValue }

    public static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}


struct Baz {
    let isSpecial: Bool
}


extension Dictionary where Key: Foo, Value: Baz { // Note that the == syntax does not compile, either
    var hasSpecialPredefined: Bool {
        return self[.predefinedFoo]?.isSpecial ?? false
    }
}

let test: [Foo: Baz] = [.predefinedFoo: Baz(isSpecial: true)]

test.hasSpecialPredefined

使用上面的代码,我得到两个编译错误:

error: type 'Key' constrained to non-protocol type 'Foo'
error: type 'Value' constrained to non-protocol type 'Baz'
error: '[Foo : Baz]' is not convertible to '<<error type>>'
    test.hasSpecialPredefined
    ^~~~

是否可以通过结构来限制扩展?如果不能,为什么不呢?这似乎完全合理。


请注意,这里的FooBar 不在我的控制范围内。它们代表在外部模块中定义的结构,我要扩展的字典也来自这个模块。答案应该假定Foo始终struct,并且该结构将always 是字典的键类型。

【问题讨论】:

  • 一种方法是简单地创建一个包装器类型,例如 Rob 对this question 的回答。另一种选择是创建一个“虚拟”协议,例如this Q&A

标签: swift generics struct swift-extensions


【解决方案1】:

试试我的版本

1。代码(带结构)

import Foundation

struct Foo: Hashable {
    let bar: String

    static let predefinedFoo = Foo(bar: "something")

    var hashValue: Int { return bar.hashValue }

    static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}

struct Baz {
    let isSpecial: Bool
    init(isSpecial: Bool) {
        self.isSpecial = isSpecial
    }
}

extension Dictionary where Key: Any, Value: Any {
    var hasSpecialPredefined: Bool {
        for key in keys {
            if let _key = key as? Foo, _key == .predefinedFoo, let value = self[key] as? Baz {
                return value.isSpecial
            }
        }
        return false
    }
}

let foo1 = Foo(bar: "ddddd")
var test: [Foo: Baz] = [foo1: Baz(isSpecial: true)]
print("\(test), hasSpecialPredefined: \(test.hasSpecialPredefined)")
test[.predefinedFoo] =  Baz(isSpecial: true)
print("\(test), hasSpecialPredefined: \(test.hasSpecialPredefined)")

结果

2。代码(带类)

import Foundation

class Foo: Hashable {
    let bar: String

    init(bar:String) {
        self.bar = bar
    }

    static let predefinedFoo = Foo(bar: "something")

    var hashValue: Int { return bar.hashValue }

    public static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}

class Baz: AnyObject {
    let isSpecial: Bool
    init(isSpecial: Bool) {
        self.isSpecial = isSpecial
    }
}

extension Dictionary where Key: Foo, Value: Baz {
    var hasSpecialPredefined: Bool {
        for key in keys {
            if key == .predefinedFoo {
                return self[key]?.isSpecial ?? false
            }
        }
        return false
    }
}

let foo1 = Foo(bar: "ddddd")
var test: [Foo: Baz] = [foo1: Baz(isSpecial: true)]
print ("hasSpecialPredefined: \(test.hasSpecialPredefined)")
test[.predefinedFoo] =  Baz(isSpecial: true)
print ("hasSpecialPredefined: \(test.hasSpecialPredefined)")

【讨论】:

  • 对不起,我应该清楚的。我需要 FooBaz 成为结构。它们代表存在于我无法更改的外部模块中的结构。字典也来自这个模块。
  • 这当然可以正确编译和运行,是的。但是,让每个字典的自动完成中弹出该 var 并不好。我会考虑这个答案,但我可能不会在实践中使用它。
  • Swift 语言有限制。我在回复中留下了两个例子。要么您使用类,然后 hasSpecialPredefined 属性将仅对字典 [Foo: Baz] 可用,或者您可以使用结构并且 hasSpetialPredefined 将可用于所有字典。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多