【问题标题】:How to initialize a struct with dictionaries in Swift如何在 Swift 中使用字典初始化结构
【发布时间】:2021-11-15 20:27:14
【问题描述】:

我想每次都用字典初始化一个结构。稍后,我将使用它的属性而不是字典的键和值——这似乎更容易。但是,当我尝试下面的代码时,它告诉我“从初始化程序返回而不初始化所有存储的属性”和“1. 'self.one' 未初始化”和“2. 'self.two' 未初始化”。我的问题是如何从字典中初始化一个结构,以便我基本上拥有一个包含字典内容的结构?或者怎么转成struct?

struct Blabla {
    var one: String
    var two: [Int]

    init(three: [String: [Int]]) {
        for i in three {
            self.one = i.key
            self.two = i.value
        }

    } ERROR! - Return from initializer without initializing all stored properties
}

【问题讨论】:

  • 只是猜测,但我怀疑这与在 for 循环中设置 self.oneself.two 的条件性质有关。
  • 您到底想达到什么目的? [String: [Int]](又名Dictionary<String, Array<Int>>)有多个键值对,每个键值对由一个字符串和多个整数(在一个数组中)组成。在您的代码中,如果three 为空,则永远不会设置self.oneself.two,如果它有多个n 条目,它们将被覆盖n-1 次,因此它们的最终值是最后一个字典的键/值对(它本身是不确定的,因为字典没有定义的顺序)

标签: swift initialization


【解决方案1】:

结构布拉布拉{ 变量一:字符串 变量二:[整数]

init(three: [String: [Int]]) {
    one = ""
    two = []
    for i in three {
        self.one = i.key
        self.two = i.value
    }

} ERROR! - Return from initializer without initializing all stored properties

}

【讨论】:

    【解决方案2】:

    for in 子句可能有零次运行,在这种情况下,结构属性将不会被初始化。你必须提供默认值(如果你真的需要,也可以发出 fatalError)。

    虽然我认为您的示例是纯综合的,但无需遍历数组,您可以将属性设置为其最后一个条目。

    【讨论】:

      【解决方案3】:

      问题是如果three 是空的Dictionary,实例属性onetwo 不会被初始化。此外,您正在覆盖 for 循环的每次迭代中的属性,编译器无法保证在编译时会有任何循环迭代,因此会出现编译器错误。

      您可以通过检查字典实际上是否包含至少一个键值对并将第一个键值对分配给您的属性来使初始化程序无法解决此问题。

      struct Blabla {
          var one: String
          var two: [Int]
      
          init?(three: [String: [Int]]) {
              guard let key = three.keys.first, let value = three[key] else { return nil }
              one = key
              two = value
          }
      }
      

      但是,您应该重新考虑您实际尝试实现的目标是什么,因为在您当前的设置下,您的 init 输入值和结构的属性之间存在不匹配。

      【讨论】:

        【解决方案4】:

        这段代码应该可以编译,但我觉得以这种方式初始化 Struct 不安全,因为:

        • 假定您的字典中有值。
        • 您存储的属性将始终具有您循环访问的最后一个值。
        • 为了提取值以满足编译器的要求,您需要强制解包它们。 (使用 Dávid Pásztor 的防卫方法,可以避免这种情况)
        struct Blabla {
            var one: String
            var two: [Int]
        
            init(three: [String: [Int]]) {
                self.one = three.keys.first!
                self.two = three[three.keys.first!]!
            }
        }
        
        let input = ["pizza": [1,2]]
        let l = Blabla(three: input)
        

        如果我是你,我会让你免费获得的成员初始化器做它的事情,并提供一个专门的初始化器来处理你将字典作为输入的情况,或者将解析移到另一个函数/类/等。 ..

        【讨论】:

        • OP 不想获得第一个条目,而是最后一个条目(至少,他的代码这么说)并且强制展开通常不是很好的事情,特别是如果您认为像 swiftlint 这样的一些工具会默认情况下不通过强制解包
        • 是的,强制展开并不理想,尤其是在初始化程序中。
        【解决方案5】:

        编译器错误很明显:如果字典为空,则永远不会初始化结构成员。但是代码无论如何都没有意义,因为字典的每次迭代都会覆盖值。

        也许您的意思是将字典映射到结构数组

        struct Blabla {
            let one: String
            let two: [Int]
        }
        
        let three = ["A":[1,2], "B":[3,4]]
        let blabla = three.map{Blabla(one: $0.key, two: $0.value)}
        
        print(blabla) // [Blabla(one: "A", two: [1, 2]), Blabla(one: "B", two: [3, 4])]
        

        【讨论】:

          【解决方案6】:

          结构 blabla{
          var a : 字符串
          变量 b : [int] = []
          初始化(_数据:[字符串:[int]]){
          // 随心所欲
          }

          }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-29
            • 2020-10-08
            • 2017-09-14
            • 2021-05-26
            相关资源
            最近更新 更多