Подтвердить что ты не робот

Расширьте словарь, где Key имеет тип String

Я хочу расширить метод словаря, но только если ключ имеет тип String.

Я пытаюсь сделать это:

extension Dictionary where Key: String {
    mutating func lowercaseKeys() {
        for key in self.keys {
            self[key.lowercase] = self.removeValueForKey(key)
        }
    }
}

И получите ошибку:

Введите "Ключ", ограниченный не-протокольным типом "String"

Основываясь на этом сообщении об ошибке, я могу сказать, что я могу делать такую ​​фильтрацию только с протоколами... Есть ли способ обходить это?

4b9b3361

Ответ 1

Я считаю, что ближайший протокол, отвечающий вашим потребностям, StringLiteralConvertible, который с несколькими дополнительными строками позволит вам выполнить этот

extension Dictionary where Key: StringLiteralConvertible {
    mutating func setAllKeysLowercase() {
        for key in self.keys {
            if let lowercaseKey = String(key).lowercaseString as? Key {
                self[lowercaseKey] = self.removeValueForKey(key)
            }
        }
    }
}

var stringKeyDictionary = [ "Hello" : NSObject(), "World" : NSObject() ]
stringKeyDictionary.setAllKeysLowercase()
print( stringKeyDictionary )

// Prints: ["hello": <NSObject: 0x1007033c0>, "world": <NSObject: 0x1007033d0>]

var numberKeyDictionary = [ 0 : NSObject(), 1: NSObject() ]
numberKeyDictionary.setAllKeysLowercase() //< Won't compile, keys are not strings

Ответ 2

Я обновил это для Swift 4.

extension Dictionary where Key: StringProtocol {
    mutating func setAllKeysLowercase() {
        for key in self.keys {
            if let lowercaseKey = key.lowercased() as? Key {
                self[lowercaseKey] = self.removeValue(forKey: key)
            }
        }
    }
}

var stringKeyDictionary = [ "Hello" : 123, "World" : 456 ]
stringKeyDictionary.setAllKeysLowercase()
print( stringKeyDictionary )

Отпечатки: ["hello": 123, "world": 456]

var numberKeyDictionary = [ 0 : 123, 1: 456 ]
numberKeyDictionary.setAllKeysLowercase()

дает ошибку: error: cannot use mutating member on immutable value: 'numberKeyDictionary' is immutable

Так как StringLiteralConvertible устарел, я подумал, что лучше использовать StringProtocol вместо эквивалента Swift4 ExpressibleByStringLiteral. Использование ExpressibleByStringLiteral означает, что ключ не является строкой, поэтому не может использовать методы String, такие как lowercased.