Swift:如何解决下标模糊问题。命名下标?

3

我已经实现了一个有序字典,它有两个下标。第一个下标是索引(始终为类型 Int),而第二个下标是可变类型的关键字 keyType

这一切都很好,直到 keyTypeInt,因为此时子脚本显然是模糊的。

'subscript' 的使用不明确

为了解决歧义,我尝试简单地添加一个名称标签 key: 给值,就像普通函数参数一样,但这导致 key: keyType 被视为我的参数类型,从而导致以下错误:

无法用 '(key: Int)' 类型的索引对 'OrderedDictionary' 的值进行下标操作

对我来说,这些错误信息非常清楚,但我不知道如何解决这种模糊性。目前我正在使用函数 insert(for:value:)

这里是 OrderedDictionary 类:

import Foundation

struct OrderedDictionary<keyType: Hashable, valueType>: Sequence {
    typealias Element = (keyType, valueType)

    let comparator: ((Element, Element) -> (Bool))?
    var keys = [keyType]()
    var values = [keyType:valueType]()
    var count: Int {
        get {
            return keys.count
        }
    }

    public struct Iterator: IteratorProtocol {
        let parent: OrderedDictionary
        var position: Int = 0

        init(parent: OrderedDictionary) {
            self.parent = parent
        }

        mutating func next() -> (keyType, valueType)? {
            if position == parent.keys.count {
                return nil
            }
            let entry = parent.getEntry(at: position)
            position += 1
            return entry
        }
    }

    init() {
        comparator = nil
    }

    init(comparator:  ((Element, Element) -> (Bool))?) {
        self.comparator = comparator
    }

    subscript(index: Int) -> valueType? {
        get {
            return self.values[self.keys[index]]
        }
        set(newValue) {
            let key = self.keys[index]
            if newValue == nil {
                self.keys.remove(at: index)
                self.values.removeValue(forKey: key)
            } else {
                self.values[key] = newValue
            }
        }
    }

    subscript(key: keyType) -> valueType? {
        get {
            return self.values[key]
        }
        set(newValue) {
            if newValue == nil {
                for i in (0..<self.keys.count) {
                    if self.keys[i] == key {
                        self.keys.remove(at: i)
                        break
                    }
                }
                self.values.removeValue(forKey: key)
            } else {
                insert(for: key, value: newValue!)
            }
        }
    }

    mutating func insert(for key: keyType, value: valueType) {
        let oldValue = self.values.updateValue(value, forKey: key)
        if oldValue == nil {
            if comparator != nil {
                for i in (0..<self.keys.count) {
                    if comparator!((key, value), getEntry(at: i)) {
                        self.keys.insert(key, at: i)
                        return
                    }
                }
            }
            //First key, largest key or insertion order
            self.keys.append(key)
        }
    }

    func getEntry(at index: Int) -> Element {
        let key = self.keys[index]
        return (key, self.values[key]!)
    }

    func makeIterator() -> OrderedDictionary<keyType, valueType>.Iterator {
        return Iterator(parent: self)
    }

    mutating func removeAll() {
        self.keys.removeAll()
        self.values.removeAll()
    }
}

以下是一些 Swift 的示例:

//Note: Index type 'Int' same as key type 'Int'
var dict = OrderedDictionary<Int, String>()

// Ambiguous
dict[0] = "Hello"

// Named (not valid)
dict[key: 10] = "World"

// Workaround
dict.insert(for: 20, value: "!")

我该如何解决这种二义性?在Swift中是否有可能实现这一点?

可能是Swift带参数标签的下标的重复问题。 - pkamb
1个回答

6
与 Swift 中的所有其他函数不同,下标参数名称默认情况下不是外部化的。 (我认为这种不一致性是语言中的错误。)
因此,在您拥有以下代码时:
subscript(key:

...you need to say

subscript(key key:

为了将 key 标签暴露给调用者。


实际上,听起来您需要的是三个下标:

subscript(index: Int)
subscript(key: keyType)
subscript(key key: keyType)

这样,您只需在调用中使用key,以防止出现歧义。

1
实际上,由于您可能更多地通过键访问而不是索引访问,因此您可能希望将“index”公开为标签。或者您可以同时公开两者。 - matt
是的,如果存在歧义,有可选标签会很好,但这个也可以。 - Minding
嗯,我不认为你的另一种解决方案(使用方法而不是下标)很糟糕。下标很方便,但它们只是一种便利。例如,Swift Dictionary 的下标不能让您做任何通过调用方法不能实现的事情。我们太习惯了使用下标,以至于忘记方法的存在。 - matt
哦,顺便说一下,当然,你可以有可选标签,只需添加另一个下标即可。我会将其添加到我的答案中。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接