Equivalent of #define in tcl?

2020-07-23 06:06发布

问题:

Is there a command in tcl that is equivalent to C++ #define? I've seen ways to implement "define" using overloading of the proc function, just wanted to know if anyone knows of a more starightforward way

回答1:

Tcl has a mechanism that lets you define aliases to procedures in an interpreter.

If you have

proc foo {one two three} {do something with $one $two $three}

and you find you're always passing $a and $b as the first two arguments, you can write:

interp alias {} foo_ab {} foo $a $b

And now you can say:

foo_ab $d   ;# same as "foo $a $b $d"
foo_ab $e   ;# same as "foo $a $b $e"

example:

proc foo {one two three} {puts [join [list $one $two $three] :]}
set a Hello
set b World
interp alias {} foo_ab {} foo $a $b
foo_ab example  ;# prints "Hello:World:example"

The empty braces in the interp alias command merely signify the current interpreter. You can do lots of fun things with slave interpreters.



回答2:

The use of interp alias allows you to use the contents of a and b at the time the alias was created:

interp alias {} foo_ab {} foo $a $b

If you need to use the values at the time it is called, you need a helper procedure instead:

proc foo_ab args {
    global a b
    uplevel 1 [list foo $a $b {*}$args]
    # Or this in older Tcl: uplevel 1 [list foo $a $b] $args
}

In 8.5, this can also be written with aliases and apply:

interp alias {} foo_ab {} apply {args {
    global a b
    uplevel 1 [list foo $a $b {*}$args]
}}

In 8.6, you can optimize further by using tailcall:

interp alias {} foo_ab {} apply {args {
    global a b
    tailcall foo $a $b {*}$args
}}

You could also use some other, dirtier tricks like this:

interp alias {} foo_ab {} namespace inscope :: {foo $a $b}

That's not especially fast though, but it does work in all Tcl 8.* versions.



回答3:

Alternatively you can define your proc to expect both d and e as input parameters with a default value (e.g. empty string) e.g.

proc foo {a b c {d ""} {e ""} }.....

If you're going to have an unkown number of input parameters you can use the word args, which will create a list containing each value in args e.g.

   proc foo {a b c args } {
     foreach bar $args {
       #do whatever...
     }
   }

cheers Brian



回答4:

If by "receives the same arguments" you mean that you are repeatedly passing the same values for $a, $b, and $c, then one option you have is to use globals instead of function parameters. Store values in them before calling your function, and then your function call simplifies down to foo $d, etc.