是否可以将参数的默认值设置为函数的返回值?(TCL)

3
在 TCL 中,是否可以将参数的默认值设置为函数调用的返回值?
proc GetParameterValue { } {
    # calculation for value...
    return value
}

proc TestFunction { {paramVal [GetParameterValue]} } { 
    puts $paramVal
}

TestFunction

这会导致打印“[GetParameterValue]”,而不是调用过程GetParameterValue。在TCL中是否可以这样做,还是我需要重新设计这段代码?
2个回答

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中实现该命令,那么这基本上就是您必须要做的,尽管需要进行不同语言的调整。缺点是,与使用内置的基本参数解析支持代码相比,它确实更费力。


1
这是对Donal详细答案的补充。过去,我有时会使用[subst]来计算默认值:
proc GetParameterValue {} { return computedDefault }

proc TestFunction {{paramVal [GetParameterValue]}} { 
    puts [subst -novariables $paramVal]
}

TestFunction; # returns "computedDefault"
TestFunction "providedValue"
TestFunction {$test}

这样可以避免对参数进行完全控制的需要,并且利用内置的参数处理程序。它还允许使用匿名过程而不是显式命名的过程来计算默认值:
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\]}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接