Компилятор жалуется, если на один ключ перечисления словаря не ссылаются - PullRequest
0 голосов
/ 28 августа 2018

У меня есть следующее перечисление:

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 голосов
/ 28 августа 2018

Вложенные дети полностью независимы. Внешний словарь - [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 с помощью явного указания типов сократит время компиляции.


Попробуйте использовать struct или class:

Я не уверен, что словарь - лучший выбор структуры данных здесь. Возможно, вы захотите использовать struct или 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 к нужному типу.

Преимущество использования class здесь (над struct) заключается в том, что оно позволяет легко обновлять внутренние задачи:

Например:

// Mark all of the children tasks of the second task as completed
for task in taskDescriptions[1].children {
    task.completed = true
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...