在TCL中,参数的默认值是否可以作为函数调用的返回值?
proc GetParameterValue { } {
# calculation for value...
return value
}
proc TestFunction { {paramVal [GetParameterValue]} } {
puts $paramVal
}
TestFunction
这将导致打印“ [GetParameterValue]”。而不是调用过程GetParameterValue。是否可以在TCL中做到这一点,还是需要重新设计这段代码?
答案 0 :(得分:4)
参数的默认值只能是您在声明过程时计算的常量(最常见的是它们是文字,这意味着您无需使用list
进行构造) :
proc TestFunction [list [list paramVal [GetParameterValue]]] {
...
}
要在过程调用时计算默认值,必须将计算结果移到过程主体中。有几种方法可以检测是否执行计算,但是它们归结为三个选项:使用标记值,获取呼叫中的单词计数以及完全控制解析。
诀窍是找到一些真正不太可能传递的值。例如,如果要向用户显示一段文本,则该值仅包含不会出现ASCII NUL;将其设置为默认值,然后您就可以知道是否具有默认值,并可以用复杂代码提供的内容代替。
proc TestFunction {{paramVal "\u0000"}} {
if {$paramVal eq "\u0000"} {
set paramVal [GetParameterValue]
}
...
}
这取决于info level
自省命令的功能。特别地,info level 0
向当前过程报告实际参数的完整列表。稍加计数,我们就可以知道是否传递了真实值。
proc TestFunction {{paramVal "dummy"}} {
if {[llength [info level 0]] < 2} {
# Note that the command name itself is always present
set paramVal [GetParameterValue]
}
...
}
这是一种完全通用的方法,因此不必担心有人会提供意外的极端情况,但是当您有多个参数时,这会变得更加复杂,因为您需要自己计算出应该出现多少个参数。在这种情况下,这很简单,但是随着参数的增加,难度会逐渐增加。
最终,您还可以决定创建一个完全控制其参数解析的过程。为此,可以给它一个单独的参数args
,然后可以使用任何要处理实际参数列表的方法。 (在这种情况下,我倾向于不将形式参数列表放在括号 中,但这只是我自己的样式。)
proc TestFunction args {
if {[llength $args] == 0} {
set paramVal [GetParameterValue]
} elseif {[llength $args] == 1} {
set paramVal [lindex $args 0]
} else {
# IMPORTANT! Let users discover how to use the command!
return -code error -errorcode {TCL WRONGARGS} \
"wrong # args: should be \"TestFunction ?paramVal?\""
}
...
}
这是目前做任何真正高级的事情的唯一方法,例如,在强制参数之前有可选参数。如果在C中实现了该命令,这也几乎是您在C中要做的,尽管已针对另一种语言进行了调整。缺点是,与使用proc
命令的实现所提供的内置基本参数解析支持代码相比,这肯定是更多的工作。
答案 1 :(得分:1)
这是对Donal详尽回答的补充。过去,有时我会借助[subst]
来帮助计算默认值:
proc GetParameterValue {} { return computedDefault }
proc TestFunction {{paramVal [GetParameterValue]}} {
puts [subst -novariables $paramVal]
}
TestFunction; # returns "computedDefault"
TestFunction "providedValue"
TestFunction {$test}
这避免了对参数的完全控制(实现),并搭载在内置参数处理程序上。它还允许使用匿名proc而不是显式命名的proc来计算默认值:
proc TestFunction {{paramVal "[apply {{} { return computedValue }}]"}} {
puts [subst -novariables ${paramVal}]
}
TestFunction; # returns "computedDefault"
TestFunction "providedValue"
TestFunction {$test}
不用说,后面还有一些假设,这些假设根据个人的应用情况而变成重要的限制:
您必须遵守一些纪律,在参数列表中使用方括号作为默认值,并将[subst]
放在参数变量的使用位置。
它假定您对参数有一定的控制权,或者可以保证某些特殊用途的字符不是参数值域的有效成员。
观看:
TestFunction {[xxx]}
抛出
invalid command name "xxx"
并且必须进行消毒
TestFunction {\[xxx\]}