我有以下枚举:

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.引用,否则编译器会抱怨。
对我来说这有点奇怪。我假设编译器在我像在示例中那样添加一个键时就隐式地将子项从Any键入soTaskKey:Any
我不知道我的假设是否正确。为了美观起见,也可以对我的字典中的嵌套条目使用.title语法。

最佳答案

嵌套的子级是完全独立的。外部字典是[TaskKey:Any]所以内部数组可以是任何类型。编译器需要一些关于.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编译器的工作变得容易,这将提高编译时间。
考虑使用structclass
我不确定字典是这里数据结构的最佳选择。您可能需要考虑使用structclass
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转换为所需类型要容易得多。
在这里使用class的优点是(相对于struct)它使您能够轻松地更新内部任务:
例如:
// Mark all of the children tasks of the second task as completed
for task in taskDescriptions[1].children {
    task.completed = true
}

10-01 19:54