2016-06-30 11 views
0

Ich finde, dass ich häufig Werte an Wörterbuchlisten anhängen möchte, aber nur, wenn der Wert nicht bereits in der Liste ist. Deshalb versuche ich dies in einem Verfahren zu trennen, und ich kann nicht herausfinden, warum der folgende Code führt dies nicht erreichen:Wert nur dann zum Dictionary-Schlüssel hinzufügen, wenn dieser noch nicht vorhanden ist

proc DictAdd {_dictionary key value} { 

    upvar 1 $_dictionary dictionary 

    if { $value ni [dict get $dictionary $key] } { 
     dict lappend dictionary $key $value 
    } 
} 

Aufruf dieser Prozedur gibt den folgenden Fehler:

can't read "dictionary": no such variable 
    while executing 
"dict get $dictionary $key" 
    (procedure "DictAdd" line 5) 
    invoked from within 
"DictAdd $files baseline $fileName" 
    (procedure "getFilesToLoad" line 53) 
    invoked from within 
... 

Könnte mir bitte jemand sagen, was ich hier falsch mache? Vielen Dank.

+0

Versuchen Sie, die $, bevor Dateien zu entfernen: DictAdd Dateien Baseline $ Dateiname. –

Antwort

0

Im Aufruf

DictAdd $files baseline $fileName 

$files ist der Wert Ihres Wörterbuch, aber DictAdd erwartet den Namen des Wörterbuchs Variable. Wenn Sie es stattdessen wie folgt aufrufen:

DictAdd files baseline $fileName 

der Befehl funktioniert wie vorgesehen.

BTW: Wenn Sie DictAdd wie folgt definieren:

proc DictAdd {_dictionary key value} { 
    upvar 1 $_dictionary dictionary 

    if {[dict exists $dictionary $key]} { 
     dict with dictionary { 
      upvar 0 $key values 
      if {$value ni $values} { 
       lappend values $value 
      } 
     } 
    } else { 
     dict lappend dictionary $key $value 
    } 
} 

Sie keine Fehlermeldung erhalten, wenn der Schlüssel fehlt (es fügt den Wert unter diesem Schlüssel) (das Wörterbuch muss noch außerhalb existieren DictAdd) und der Prüf-/Hinzufügungscode wird etwas weniger unordentlich.

Warum der Name? Es ist wegen, wie upvar funktioniert. Der Befehl nimmt eine Stapelebene (in diesem Fall 1 = die Ebene des Aufrufers) und einen Variablennamen (enthalten in _dictionary; "Dateien" in diesem Fall); mit diesen sucht es eine Variable außerhalb des ausführenden Befehls und erstellt einen lokalen Alias ​​innerhalb des ausführenden Befehls (in diesem Fall mit dem Namen dictionary: files draußen ist jetzt im Grunde die gleiche Variable wie dictionary innen). Wenn Sie etwas anderes passieren, z. Der Wert von files, sagen {baseline {a b c}}, upvar wird nach einer Variablen namens {baseline {a b c}} suchen und höchstwahrscheinlich nicht finden. Es wird trotzdem den Alias ​​erstellen, und wenn Sie ihn initialisieren, wird tatsächlich eine Variable namens {baseline {a b c}} auf der Ebene des Aufrufers erstellt. Aber auch hier wollen Sie den Namen der Variablen verwenden (der Name der Variablen könnte natürlich der Wert einer anderen Variablen sein, wenn Sie den Befehl aufrufen ...).

Dokumentation: dict, if, lappend, ni Operator, proc, upvar

+0

Danke, Peter. Das hat perfekt funktioniert. Ich versuche immer noch herauszufinden, warum es so ist, dass die Prozedur den Namen der Wörterbuchvariablen und nicht ihren Wert erwartet. –

+0

@BruceJohnson: Ich habe eine Erklärung hinzugefügt, lass es mich wissen, wenn es nicht hilft. –

+0

@BruceJohnson: und jetzt wird die Erklärung tatsächlich hinzugefügt. Ich scheine die Seite ohne Speichern geschlossen zu haben. –

0

Das Problem ist höchstwahrscheinlich, dass die Wörterbuchvariable, auf die Sie sich beziehen, tatsächlich nicht gesetzt ist und daher unmöglich zu lesen ist. Versuchen Sie folgendes:

proc DictAdd {_dictionary key value} { 
    upvar 1 $_dictionary dictionary 
    if {![info exists dictionary]} { 
     set dictionary [dict create $key [list $value]] 
    } elseif {$value ni [dict get $dictionary $key]} { 
     dict lappend dictionary $key $value 
    } 
} 
Verwandte Themen