2010-02-26 11 views
6

Ich schreibe einen Proc, um einen Header in einer Ausgabedatei zu erstellen.Wie kann ich sicher mit optionalen Parametern umgehen

Momentan braucht es einen optionalen Parameter, der ein möglicher Kommentar für den Header ist.

Ich habe Codierung dies als ein einzelnen optionalen Parameter endete

proc dump_header { test description {comment = ""}} 

aber würde gerne wissen, wie ich den gleichen mit args erreichen kann

proc dump_header { test description args } 

Es ist ganz einfach für args zu überprüfen sein ein einzelner leerer Parameter ($ args == ""), aber geht nicht gut, wenn mehrere Parameter übergeben werden - und ich brauche sowieso die negative Prüfung.

+0

Was möchten Sie tun, wenn Ihr Proc mit mehr als 3 Argumenten aufgerufen wird: dump_header mytest mydesc {Ein Kommentar} somethingselse? Behandle etwas als einen anderen Kommentar, verarbeite es anders? –

+0

Es ist falsch, $ args mit einer leeren Zeichenfolge zu vergleichen. Argumente ist eine Liste, keine Zeichenfolge. –

+0

Nun, es ist nicht per se falsch, da es eine String-Darstellung erstellen wird, aber dies ist möglicherweise unnötig, wenn Sie es als eine Liste sowieso behandeln wollen –

Antwort

13

Ihre Proc-Definition ist falsch (Sie erhalten die Fehlermeldung too many fields in argument specifier "comment = """). Sollte sein:

proc dump_header { test description {comment ""}} { 
    puts $comment 
} 

Wenn Sie args verwenden möchten, können Sie die llength davon untersuchen konnte:

proc dump_header {test desc args} { 
    switch -exact [llength $args] { 
     0 {puts "no comment"} 
     1 {puts "the comment is: $args"} 
     default { 
      puts "the comment is: [lindex $args 0]" 
      puts "the other args are: [lrange $args 1 end]" 
     } 
    } 
} 

Vielleicht möchten Sie auch Name-Wert-Paare in einer Liste übergeben:

proc dump_header {test desc options} { 
    # following will error if $options is an odd-length list 
    array set opts $options 

    if {[info exists opts(comment)]} { 
     puts "the comment is: $opts(comment)" 
    } 
    puts "here are all the options given:" 
    parray opts 
} 
dump_header "test" "description" {comment "a comment" arg1 foo arg2 bar} 

Einige bevorzugen eine Kombination von args und Name-Wert-Paare (a la Tk)

proc dump_header {test desc args} { 
    # following will error if $args is an odd-length list 
    array set opts $args 
    if {[info exists opts(-comment)]} { 
     puts "the comment is: $opts(-comment)" 
    } 
    parray opts 
} 
dump_header "test" "description" -comment "a comment" -arg1 foo -arg2 bar 
+0

Danke. Für andere Fälle denke ich, würde ich die Name-Wert-Paare bevorzugen ... aber in diesem Fall denke ich, Ihre Antwort übersetzt "um alle Fälle zu behandeln, die Sie als Array behandeln müssen". Was ist in Ordnung. – itj

5

Ich benutze tcllib 's cmdline Bibliothek, Optionsparsing zu tun.

Dies ist das Beispiel von cmdline Dokumentation:

set options { 
    {a   "set the atime only"} 
    {m   "set the mtime only"} 
    {c   "do not create non-existent files"} 
    {r.arg "" "use time from ref_file"} 
    {t.arg -1 "use specified time"} 
} 
set usage ": MyCommandName \[options] filename ...\noptions:" 
array set params [::cmdline::getoptions argv $options $usage] 

if { $params(a) } { set set_atime "true" } 
set has_t [expr {$params(t) != -1}] 
set has_r [expr {[string length $params(r)] > 0}] 
if {$has_t && $has_r} { 
    return -code error "Cannot specify both -r and -t" 
} elseif {$has_t} { 
    ... 
} 

in Ihrem Fall also würden, die Sie gerade args anstelle von argv in dem obigen Beispiel.

1

Es sollte explizit erwähnt werden, dass args ein spezielles Wort in Tcl ist, das, wenn es am Ende der Argumentliste verwendet wird, eine Liste aller verbleibenden Argumente enthält. Wenn kein args angegeben wird, wird kein Fehler erzeugt (im Gegensatz zu jedem anderen Variablennamen, der als erforderliches Argument betrachtet werden würde).

ich nach einer Möglichkeit, Funktionalität zu haben, ähnlich wie die Python kwargs (optional Schlüssel-Wert-Paar Argumente), und etwas, das schön ist (ähnlich wie Glenn letztes Beispiel) arbeitet:

proc my_proc {positional_required1 {positional_optional1 "a_string"} args} { 
    # Two optional arguments can be given: "opt1" and "opt2" 
    if {![string equal $args ""]} { 
     # If one or more args is given, parse them or assign defaults. 
     array set opts $args 
     if {[info exists opts(opt1)]} { set opt1 $opts(opt1) } else { set opt1 0 } 
     if {[info exists opts(op2)]} { set opt2 $opts(opt2) } else { set opt2 -1 } 
    } else { 
     # If no args are given, assign default values. 
     set op1 0 
     set op2 -1 
    } 
    # DO STUFF HERE 
} 

Und kann sein genannt wie:

my_proc "positional_required1_argument" 
# OR 
my_proc "positional_required1_argument" "a_string" 
# OR 
my_proc "positional_required1_argument" "a_string" opt1 7 
# OR 
my_proc "positional_required1_argument" "a_string" opt1 7 opt2 50 
# etc. 

ein potenzieller Nachteil (wie ich es derzeit implementiert habe) ist, dass, wenn ein Benutzer eine nicht genehmigte Schlüssel-Wert-Option geht, gibt es keinen Fehler ist.

Verwandte Themen