Элемент экземпляра в качестве параметра по умолчанию - PullRequest
1 голос
/ 05 апреля 2020

Я пытаюсь использовать свойство root в качестве параметра по умолчанию в функции add, как показано ниже, и выдает ошибку:

Невозможно использовать элемент экземпляра 'root' в качестве параметр по умолчанию.

Однако, когда я использую root во вложенной функции search, он работает нормально.

class Trie {
   var root = TrieNode()

   func add(value: String, node: TrieNode? = root) { // error
      var myNode = node
      if myNode == nil {
        myNode = root
      }
      if value.count == 0 {
        node?.setEnd()
        return
      } else if myNode!.keys[String(value.first!)] == nil {
        myNode!.keys[String(value.first!)] = TrieNode()
        return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
    } else {
        return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
    }
   }


  func allWords() -> [String] {
    var words = [String]()
    func search(node: TrieNode = root, string: String) { // Here it is working fine.
        if node.keys.count != 0 {
            for key in node.keys.keys {
                search(node: node.keys[key]!, string: string+key)
            }
            if node.isEnd {
                words.append(string)
            }
        } else {
            if string.count > 0  {
                words.append(string)
            }
        }
    }

    search(node: self.root, string: "")
    return words
}
}

Может кто-нибудь сказать мне, почему я не может использовать свойство в качестве параметра по умолчанию?

Ответы [ 3 ]

1 голос
/ 05 апреля 2020

Причина в видимости другого контекста, контекст аргументов интерфейсной функции external относительно объявления класса, поэтому члены не видны, но вложенная функция объявлена ​​ внутри класса context, как и тело другой функции, поэтому члены видимы.

Таким образом, решение может быть stati c, как уже предлагалось, но у него могут быть недостатки (например, для ссылочных элементов по умолчанию), поэтому я рекомендую используйте его только для констант.

Другие возможные решения ниже

func add(value: String, node: TrieNode?) { // no error
    func _add(value: String, node: TrieNode? = root) { // in-context
        var myNode = node
        if myNode == nil {
            myNode = root
        }
        if value.count == 0 {
            node?.setEnd()
            return
        } else if myNode!.keys[String(value.first!)] == nil {
            myNode!.keys[String(value.first!)] = TrieNode()
            return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
        } else {
            return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
        }
    }
    _add(value: value, node: node)
}
0 голосов
/ 05 апреля 2020

Другие ответы объяснили почему вы не можете этого сделать.

Я предлагаю, чтобы самый простой способ достичь того, что вы хотите, - это оператор nil coalescing

func add(value: String, node: TrieNode? = nil) { // error
  var myNode = node ?? root

  guard let key = value.first, keyStr = String(key) else {
      myNode.setEnd()
      return
  }

  let updateNode = myNode.keys[keyStr, default: TrieNode()]
  return add(value: String(value.dropFirst(), node: updateNode)
 }
0 голосов
/ 05 апреля 2020

Вы можете ввести переменную stati c, как предложено в комментариях, а затем обновить ее значение, когда root изменит

class Trie {
    static var defaultNode = TrieNode()

    var root = TrieNode() {
        didSet {
            Trie.defaultNode = root
        }
    }

func add(value: String, node: TrieNode? = Trie.defaultNode) {

Основная проблема в том, что defaultNode будет то же самое для всех экземпляров Tr ie, а также для того, чтобы все экземпляры могли изменить его, конечно, вы можете let объявить его так, чтобы он был постоянным, но тогда какой смысл иметь его вообще (хотя я не видите, что вы когда-либо меняли root?).

Другой вариант - пропустить значение по умолчанию в объявлении функции и вместо этого поместить его в функцию

class Trie {
    var root = TrieNode()

    func add(value: String, node: TrieNode?) { 
        let myNode = node ?? root
        if value.count == 0 {
            myNode.setEnd()
            return
        }
        //... rest of code
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...