2015-10-16 2 views
12

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

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

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

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

Type 'Key' constrained to non-protocol type 'String'

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

ответ

18

Я считаю, что самый близкий протокол, который отвечает вашим потребностям 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 
+5

StringLiteralConvertible устарел от Swift 3. Вместо этого используйте ExpressibleByStringLiteral. –

+0

Замечательно, спасибо @MacBellingrath! –

0

Я обновил это для 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.