简体   繁体   中英

Why does Int enum as dictionary key, produce different json string than Int as dictionary key?

I try to convert a dictionary, with Int enum

enum TypeE: Int, Codable
{
    case note = 1
    case tab
}

let encoder = JSONEncoder()

let dictionary0 = [TypeE.note:"VALUE0", TypeE.tab:"VALUE1"]
var data = try encoder.encode(dictionary0)
var string = String(data: data, encoding: .utf8)!
// [1,"VALUE0",2,"VALUE1"]
print(string)

The produced json string output is

[1,"VALUE0",2,"VALUE1"]

It looks strange to me. As, the produced json string represents an array.


If I tested with

let encoder = JSONEncoder()

let dictionary1 = [1:"VALUE0", 2:"VALUE1"]
var data = try encoder.encode(dictionary1)
var string = String(data: data, encoding: .utf8)!
// {"1":"VALUE0","2":"VALUE1"}
print(string)

The produced json string output is

{"1":"VALUE0","2":"VALUE1"}

It seems like if I use Int enum as dictionary key, the produced json string will become representation of array?

Is there any mistake in my code, or my expectation is incorrect?

The source code of Codable provides explanation for this behavior. If the key isn't a String or an Int , the resulting type is an Array :

  public func encode(to encoder: Encoder) throws {
    if Key.self == String.self {
      // Since the keys are already Strings, we can use them as keys directly.
      ...
    } else if Key.self == Int.self {
      // Since the keys are already Ints, we can use them as keys directly.
      ...
    } else {
      // Keys are Encodable but not Strings or Ints, so we cannot arbitrarily
      // convert to keys. We can encode as an array of alternating key-value
      // pairs, though.
      var container = encoder.unkeyedContainer()
      for (key, value) in self {
        try container.encode(key)
        try container.encode(value)
      }
    }
  }

I made an extension for your case may be useful:

extension Dictionary where Key == TypeE.RawValue, Value == String {
    
    init(dictionaryLiteral elements: (TypeE, String)...) {
        var headers: [TypeE.RawValue: String] = [:]
        for pair in elements {
            headers[pair.0.rawValue] = pair.1
        }
        
        self = headers
    }
    
    subscript(typeE t: TypeE) -> Value? {
        get {
            return self[t.rawValue]
        }
        set {
            self[t.rawValue] = newValue
        }
    }
}

usage:

var dic2 = Dictionary<TypeE.RawValue, String>.init(dictionaryLiteral: (TypeE.note,"Str"), (TypeE.tab,"Str2"))

add new key/Value:

dic2[typeE: TypeE.thirdCase] = "Str3"

O/P: 在此处输入图像描述

and get specific key:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM