首页 > 解决方案 > 除非明确引用一个字典枚举键,否则编译器会抱怨

问题描述

我有以下枚举:

enum TaskKey: String{
    case title = "title"
    case completed = "completed"
    case children = "children"
}

现在使用这些键创建一个字典:

    let taskDescriptions : Array<[TaskKey:Any]> = [
        [ .title : "Buy milk",
          .completed : false ],

        [ .title     : "Sleep",
          .completed : false,
          .children  :
            [
                // `TaskKey` is required here
                [ TaskKey.title     : "Find a bed",
                  .completed : false
                ],

                [ .title     : "Wait",
                  .completed : false
                ]
            ] ],

        [ .title     : "Dance",
          .completed : false ]
        ]

现在,由于我的字典是键入<[TaskKey:Any]>的,我可以使用.title而不是TaskKey.title. 但是,对于.children整个字典的嵌套位置,我至少需要一个TaskKey.引用,否则编译器会抱怨。

对我来说,这似乎有点奇怪。我会假设编译器会像在示例中那样添加一个键后立即将子项从Anyto隐式键入。TaskKey:Any

我想知道我的假设是否正确。同样为了化妆品的缘故,我的字典中的嵌套条目也可以使用该.title语法。

标签: arraysswiftdictionarytypes

解决方案


嵌套的孩子是完全独立的。外部字典[TaskKey:Any]因此内部数组可以是任何类型。编译器需要一些关于 a.title是什么的信息。一旦你用 明确了其中一个键TaskKey.title,Swift 就会推断出其余的键。

另一种方法是使用显式转换(as [[TaskKey:Any]]或等效as Array<[TaskKey:Any]>)来告诉 Swift 内部类型:

let taskDescriptions : Array<[TaskKey:Any]> = [
    [ .title : "Buy milk",
      .completed : false ],

    [ .title     : "Sleep",
      .completed : false,
      .children  :
        [
            // `TaskKey` is required here
            [ .title     : "Find a bed",
              .completed : false
            ],

            [ .title     : "Wait",
              .completed : false
            ]
        ] as [[TaskKey:Any]] ],

    [ .title     : "Dance",
      .completed : false ]
]

注意:通过显式指定类型来简化 Swift 编译器将缩短编译时间。


考虑使用structor class

我不确定字典是这里数据结构的最佳选择。您可能需要考虑使用structor class

class Task: CustomStringConvertible {
    var title: String
    var completed: Bool
    var children: [Task]
    var description: String { return "Task(title: \(title), completed: \(completed), children: \(children)" }  

    init(title: String, completed: Bool, children: [Task] = []) {
        self.title = title
        self.completed = completed
        self.children = children
    }
}

var taskDescriptions : [Task] = [
    Task(title: "Buy milk",
         completed: false
    ),

    Task(title: "Sleep",
      completed: false,
      children:
        [
            Task(title: "Find a bed",
              completed: false
            ),

            Task(title: "Wait",
              completed: false
            )
        ]
    ),

    Task(title: "Dance",
      completed: false
    )
]

这将比必须处理转换Any为所需类型更容易访问。

使用 a classhere(优于 a struct)的优点是它使您能够轻松地更新内部任务:

例如:

// Mark all of the children tasks of the second task as completed
for task in taskDescriptions[1].children {
    task.completed = true
}

推荐阅读