除非明确引用了一个字典枚举键,否则编译器会抱怨

时间:2018-08-28 09:19:35

标签: arrays swift dictionary types

我有以下枚举:

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键入为TaskKey:Any

我想知道我的假设是否正确。同样,为了美观起见,也可以对字典中的嵌套条目使用.title语法。

1 个答案:

答案 0 :(得分:4)

嵌套的孩子是完全独立的。外部字典是[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
}