Протоколы и связанные типы в массивах - PullRequest
0 голосов
/ 19 января 2019

У меня есть протокол Node:

protocol Node {
   var parent: Node?
   var children: [Node]
}

который реализуется классами:

class TreeNode: Node {
   var parent: Node?
   var children: [Node]
}

Но это создает проблему, так как доступ к родителю в TreeNode теперь дает мне Node, и я хочу сделать TreeNode определенных операций над ними. Поэтому я хочу изменить протокол на:

protocol Node {
   associatedtype T: Node

   var parent: T?
   var children: [T]
}

Что позвольте мне определить класс как:

class TreeNode: Node {
   var parent: TreeNode?
   var children: [TreeNode]
}

Отлично! Но тут есть подвох. Если я хочу написать вспомогательный метод для Node, который работает с массивами:

func getReversedChildren<T: Node>(node: T) -> [T] {
   return node.children.reversed()
}

Компилятор завершается с ошибкой: Cannot convert return expression of type 'ReversedCollection<[T.T]>' to return type '[T]'

Из того, что я могу собрать об этой проблеме, мне нужно создать механизм стирания типов для поддержки этой архитектуры. Но как это можно сделать на моем примере?

1 Ответ

0 голосов
/ 19 января 2019

Вы, вероятно, хотите, чтобы родительский и дочерний узлы были того же типа , что и сам узел, а не просто некоторый тип, соответствующий Node.Это будет Self в определении протокола:

protocol Node {
    var parent: Self? { get set }
    var children: [Self] { get set }
}

Теперь вы можете определить конкретный класс (см. Требование к протоколу Swift, которое может быть удовлетворено только при использовании окончательного класса дляпочему класс должен быть final):

final class TreeNode: Node {
    var parent: TreeNode? = nil
    var children: [TreeNode] = []
}

и

func getReversedChildren<T: Node>(node: T) -> [T] {
    return node.children.reversed()
}

компилируется без проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...