Swift:从值数组批量分配struct成员

时间:2017-08-19 20:15:42

标签: swift

我正在从快速数据块中读取设置,并希望将其填充到结构中以便于访问和键入正确性。是否有一种简洁的方法将值赋给结构成员?例如使用下标自我?

let settings : [UInt] = [5, 5, 121, 700, 108, 1452, 6655, 10]

struct Header {
    var version             : UInt8?
    var options             : UInt8?
    var records             : UInt16?
    var timeout             : UInt16?
    var left                : UInt16?
    var right               : UInt16?
    var middle              : UInt16?
    var speed               : UInt8?

    init(values: [UInt]) {
        let m = Mirror(reflecting: self)
        var labels : [String] = []
        for (n, _) in m.children {
            labels.append(n!)
        }

        for (h, v) in zip(labels, values) {
            print("\(h) -> \(v)")
            self[h] = v     //error: type 'Header' has no subscript members
        }
    }
}

let h = Header(values: settings)

跟进
感谢ColGraff的解决方案。

在我的情况下,数据来自多个地方,以数组的形式出现。以下将有所帮助

let settings : [UInt] = [5, 5, 121]
let labels : [Header.Keys] = [.version, .options, .records]
var data : [Header.Keys : UInt] = [:]
zip(labels, settings).forEach { data[$0] = $1 }

2 个答案:

答案 0 :(得分:3)

广泛接受的做某事的方式是:

struct Header {
  let version : UInt
  let options : UInt
  let records : UInt
}

// adds marshaling from a `Dictionary`
extension Header {
  enum Keys: String { case version, options, records}

  init?(settings: [Keys:UInt]) {
    guard let version = settings[.version] else { return nil }
    guard let options = settings[.options] else { return nil }
    guard let records = settings[.records] else { return nil }
    self = Header(version: version, options: options, records: records)
  }
}

let data: [Header.Keys: UInt] = [.version: 5, .options: 5, .records: 121]

if let foo = Header(settings: data) {
  print(foo) // Header(version: 5, options: 5, records: 121)
}

如果您愿意,可以使用Dictionary甚至Array替换String之类的结构,但Dictionary是您要求的非常自然的结构。有些人甚至使用JSON字符串编码DictionaryArray结构来执行此操作。

是的,您可以使用Mirror以更自动的方式执行此类操作,但这可能会非常棘手并导致问题。编写更具体的编组数据的方法通常更安全。

更高级的用法和讨论在this chat room

答案 1 :(得分:0)

替代启发式解决方案:

let settings : [UInt] = [5, 5, 121, 700, 108, 1452, 6655, 10]

enum Fields: String {
    case version, options, records, timeout, left, right, middle, speed
}

struct Header {
    var version             : UInt8?
    var options             : UInt8?
    var records             : UInt16?
    var timeout             : UInt16?
    var left                : UInt16?
    var right               : UInt16?
    var middle              : UInt16?
    var speed               : UInt8?

    init(values: [UInt]) {
        let m = Mirror(reflecting: self)
        var labels : [Fields] = []
        for (n, _) in m.children {
            labels.append(Fields(rawValue: n!)!)
        }

        zip(labels, values).forEach { l, v in
            switch l {
            case .version:  self.version = UInt8(v)
            case .options:  self.options = UInt8(v)
            case .records:  self.records = UInt16(v)
            case .timeout:  self.timeout = UInt16(v)
            case .left   :  self.left    = UInt16(v)
            case .right  :  self.right   = UInt16(v)
            case .middle :  self.middle  = UInt16(v)
            case .speed  :  self.speed   = UInt8(v)
            default: ()
            }
        }
    }
}

var h = Header(values: settings)
print(h.version)
h.version = 7
print(h.version)

现在,如果我只能弄清楚如何从结构中动态生成枚举...