为什么这里的 Tcl 可选参数不是可选的?

Why is not optional the Tcl optional argument here?

在下面的代码中,我想采用可变数量的参数,甚至零参数。 但是解释器说错误的参数编号错误。

% interp alias {} func {} proc
% func var {varname = args} {
  if {$args eq ""} {
    set varname
  } else {
    upvar $varname v
    set v $args
  }
}
% var part1 = Sal
Sal
% puts $part1
Sal
% var part1
wrong # args: should be "var varname = ?arg ...?"

为什么?

您提供的所有参数都会传递给该过程。该过程已由您 声明 以接受三个参数,正式名称为 varname=args(其中最后一个是特殊的并接收所有剩余参数的列表)。这意味着它有两个强制参数和一个完全无限数量的可选参数。

如果你想让=成为一个可选参数,你必须在声明中给它一个默认值,也许像这样:

# I've put the value in quotes for highlighting purposes only
proc var {varname {= "="} args} {

(如果你愿意,你可以叫它func,但我会使用标准名称。)

如果形式参数有默认值,则在调用过程时它们被认为是可选的。但是,他们在 之前 消耗参数 args


我建议使用 [llength $args] == 0 检查列表是否为空,而不是 $args eq "";后者强制转换为字符串并且可能很昂贵。

总的来说,这更接近于惯用语(并且基本上是一种冗长的方式来写一些 几乎 就像标准 set 命令一样。)

proc var {varname {= "="} args} {
    upvar 1 $varname v
    if {[llength $args]} {
        set v $args
    }
    return $v
}