gpt4 book ai didi

swift - 如何将此效用函数转换为扩展函数?

转载 作者:搜寻专家 更新时间:2023-11-01 06:15:32 25 4
gpt4 key购买 nike

我在 Swift 4 中写了这个效用函数:

func insert<Key, Element>(_ value: Element, into dictionary: inout [Key : Set<Element>], at key: Key) {
if let _ = dictionary[key] {
dictionary[key]?.insert(value)
}
else {
var set = Set<Element>()
set.insert(value)
dictionary[key] = set
}
}

这是这样使用的:

insert("foo", into: &myDictionary, at: "bar")

...但我想这样使用它:

myDictionary.insert("foo", at: "bar")

我试过这样声明:

extension Dictionary where Value == Set<AnyHashable> {
mutating func insert(_ value: Value.Element, at key: Key) { // Error here
if let _ = self[key] {
self[key]?.insert(value)
} else {
var set = Set<Value.Element>() // Error here
set.insert(value)
self[key] = set
}
}
}

...但我收到以下错误:

/path/to/Sequence Extensions.swift:2:41: error: 'Element' is not a member type of 'Dictionary.Value'
mutating func insert(_ value: Value.Element, at key: Key) {
~~~~~ ^
Swift.Set:608:22: note: did you mean 'Element'?
public typealias Element = Element
^
Swift._IndexableBase:3:22: note: did you mean '_Element'?
public typealias _Element = Self.Element

/path/to/Sequence Extensions.swift:6:23: error: type 'Value.Element' does not conform to protocol 'Hashable'
var set = Set<Value.Element>()
^

最佳答案

不幸的是,Swift 目前不支持 parameterised extensions (在扩展声明中引入类型变量的能力),所以你目前不能直接表达“对某些 Set<T> 有约束的扩展”的概念。但是,它是泛型声明的一部分,因此希望它能进入该语言的 future 版本。

即使您的扩展名为 Value限于 Set<AnyHashable>编译,它不会非常有用。您需要先将所需字典转换为临时字典 [Key: Set<AnyHashable>] ,然后对其调用 mutating 方法,然后将其转换回其原始类型(使用 as! )。

这是因为扩展程序位于 Dictionary 上异质Set值。扩展方法插入任意是完全合法的Hashable元素到字典的值之一。但这不是你想表达的。

在简单的情况下,我认为首先不需要扩展。你可以说:

var dict = [String: Set<String>]()
dict["key", default: []].insert("someValue")

使用 Dictionary的下标重载采用默认值,如 SE-0165 中介绍的那样.

如果您仍然想要扩展,我建议您简单地使其更通用。例如,而不是约束 ValueSet ;将其约束到协议(protocol) SetAlgebra (Set 符合)。

它表示可以执行类集合操作的类型,也派生自 ExpressibleByArrayLiteral这意味着您可以使用上面的确切语法来实现您的方法:

extension Dictionary where Value : SetAlgebra {

mutating func insert(_ value: Value.Element, at key: Key) {
self[key, default: []].insert(value)
}
}

虽然这里要考虑的另一件事是 Swift 集合类型的写时复制行为,例如 Set .在上述方法中,将查询字典中的给定键,返回该键的现有集合或新的空集合。你的value然后将被插入到这个临时集合中,并且它将被重新插入到字典中。

这里使用临时表示如果集合已经在字典中,value不会就地插入其中,将首先复制集合的缓冲区以保留值语义;这可能是一个性能问题(这在 this Q&Athis Q&A 中有更详细的探讨)。

尽管如此,我目前正在为 Dictionary 修复此问题的 subscript(_:default:) in this pull request ,这样集合就可以发生变异。

虽然在修复之前,解决方案是在变异之前先从字典中删除集合:

extension Dictionary where Value : SetAlgebra {

mutating func insert(_ value: Value.Element, at key: Key) {
var set = removeValue(forKey: key) ?? []
set.insert(value)
self[key] = set
}
}

在这种情况下,使用扩展是完全合理的。

值得注意的是,这里使用协议(protocol)约束是解决没有参数化扩展问题的一般解决方案(或某些情况下的解决方法)。它允许您将所需的占位符实现为该协议(protocol)的关联类型。参见 this Q&A有关如何创建自己的协议(protocol)来实现该目的的示例。

关于swift - 如何将此效用函数转换为扩展函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45968332/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com