1
votes

Membre d'instance comme paramètre par défaut

J'essaie d'utiliser une propriété root comme paramètre par défaut dans la fonction add comme ci-dessous et cela me donne une erreur:

Impossible d'utiliser le membre d'instance 'root' comme paramètre par défaut .

Cependant, lorsque j'utilise root dans une fonction imbriquée search , cela fonctionne bien.

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
}
}

Quelqu'un peut-il me dire pourquoi je ne peux pas utiliser une propriété comme paramètre par défaut?


3 commentaires

Cela ressemble à un doublon de Swift: utilisation de la constante de membre comme valeur par défaut pour le paramètre de fonction pour moi.


@MartinR: Je suis d'accord, mais je voulais savoir comment une propriété peut être utilisée comme paramètre par défaut dans une fonction imbriquée.


Est-ce que cela répond à votre question? Swift: utilisation de la constante de membre comme valeur par défaut pour le paramètre de fonction < / a>


3 Réponses :


3
votes

La raison est dans une visibilité de contexte différente, le contexte des arguments de la fonction d'interface est externe par rapport à la déclaration de classe, donc les membres ne sont pas visibles, mais la fonction imbriquée est déclarée à l'intérieur em > contexte de classe, comme tout autre corps de fonction, afin que les membres soient visibles.

La solution peut donc être statique, comme déjà proposé, mais elle peut avoir des inconvénients (par exemple pour les membres par défaut de référence), je recommande donc de l'utiliser uniquement pour constantes.

Les autres solutions possibles sont ci-dessous

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)
}


1 commentaires

le contexte des arguments de la fonction d'interface est externe pourquoi dites-vous qu'il est externe? Si c'était une propriété privée, j'aurais accepté, mais root est une propriété visible / publique. Pourquoi ne peut-il pas être traité comme une fonction est traitée?



0
votes

Vous pouvez introduire une variable statique comme suggéré dans les commentaires, puis en mettre à jour la valeur lorsque root change

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
    }

Le principal problème avec ceci est que defaultNode serait le même pour toutes les instances de Trie et aussi que toutes les instances peuvent le changer, bien sûr vous pouvez laisser le déclarer pour qu'il soit constant mais alors quel est le point de l'avoir du tout (même si je ne vois pas que vous ayez jamais changé root?).

Une autre option est de sauter la valeur par défaut dans la déclaration de fonction et de l'avoir à la place à l'intérieur de la fonction

class Trie {
    static var defaultNode = TrieNode()

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

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


0 commentaires

2
votes

D'autres réponses ont expliqué pourquoi vous ne pouvez pas le faire.

Je suggère que le moyen le plus simple d'obtenir ce que vous voulez est d'utiliser l ' opérateur de fusion nil

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 commentaires