问题
I have a question about passing parameters in Tcl regarding to the following code:
set name "Ronaldo"
proc GET_PLAYER_INFO {player_id {player_name "$name"}} {
global name
puts $player_name
}
regarding to the code above, we have a global variable "name", and in the parameter list of proc GET_PLAYER_INFO, the default value of parameter player_name is set to "$name"? if the value of name is "ronaldo", it is already double quotation,do we need to put double quotation in the parameters list like this: player_name "$name"? and before we execute the "global name" command, is the default value of player_name is "Ronaldo"? is so, why we need to have "global name" command in our proc?
回答1:
That won't work as it stands; the $name won't be evaluated at all so the default will be those literal five characters.
If you're binding the default value at the time you create the procedure, you'd do it like this:
proc GET_PLAYER_INFO [list player_id [list player_name $name]] {
...
}
That is, the arguments to proc are just normal things you can construct with Tcl commands and substitutions. This is one of the great things about Tcl.
However, if you're wanting to evaluate that $name at the time the procedure is called, you've got to do it differently. If you've got some kind of value that will never be used for the player name (e.g., the empty string) then it's pretty easy:
proc GET_PLAYER_INFO {player_id {player_name ""}} {
if {$player_name eq ""} {
set player_name $::name
}
...
}
Note that I've used the fully-qualified variable name there. There are other ways to get that name too (e.g., with global, with upvar, with variable, …)
The place where things get tricky is when you've not got a suitable sentinel value at all. At that point, you have to see how many arguments were actually supplied:
proc GET_PLAYER_INFO {player_id {player_name ""}} {
if {[llength [info level 0]] == 2} {
set player_name $::name
}
...
}
The command info level 0 returns the full list of argument words to the current procedure call. This includes the GET_PLAYER_INFO itself and would be a list of length 2 or 3 in a valid call to the definition above. Once the list is available, checking its length is a trivial exercise in llength and numeric comparison. (Using a sentinel value is easier though, and works in 99.99% of cases.)
The final option is to use the special args formal parameter and do the parsing manually:
proc GET_PLAYER_INFO args {
if {[llength $args] < 1 || [llength $args] > 2} {
return -code error "wrong # args: should be \"GET_PLAYER_INFO player_id ?player_name?\""
}
set player_id [lindex $args 0]
if {[llength $args] > 1} {
set player_name [lindex $args 1]
} else {
set player_name $::name
}
...
}
As you can see, this is rather long-winded...
来源:https://stackoverflow.com/questions/9736524/in-tcl-can-we-pass-parameters-in-this-way