为什么没有内置于" dict的异常处理得到"命令?

时间:2015-05-18 17:14:19

标签: tcl

当字典首次实现并添加到Tcl时,为什么dict get命令的实现方式允许在尝试检索字典中不存在的键的值时发生错误? / p>

如果要确保命令完全安全,则每次使用时都需要将命令包装在catch语句中。在我看来,像这样经常使用的命令会内置某种异常处理。

3 个答案:

答案 0 :(得分:2)

我想这就是我们提供dict exists命令的原因。

您可能希望dict get返回该关键元素的空字符串不存在。但是,如果任何键本身的实际值是空字符串,那么像它们这样的实现将导致问题。

% set demo {id {} name Dinesh}
id {} name Dinesh
% dict get $demo id
% dict get $demo age
key  "age" not known in dictionary
% 

如果您想跳过dict exists,请使用catch

答案 1 :(得分:2)

dict命令实现为ensemble。这意味着你可以很容易地自己扩展它来实现这一目标。我喜欢调用此dict get?并让它返回一个空值,如果该键不存在。我们可以按如下方式添加这个新的子命令:

proc ::tcl::dict::get? {dict key} {
    if {[dict exists $dict $key]} {
        return [dict get $dict $key]
    }
   return
}
namespace ensemble configure dict \
    -map [linsert [namespace ensemble configure dict -map] end get? ::tcl::dict::get?]

正如您所看到的那样,通过dict exists调用简单地包含了dict get调用,但由于集合更新,它将其作为dict命令的内置部分显示。在使用中它看起来像这样:

if {[dict get? $meta x-check-query] eq "yes"} {
    ... do stuff ...
}

(这可以在Tcl测试套件httpd test server代码中看到。)

答案 2 :(得分:2)

它是Tcl(以及其他一些语言)的常见设计选择。当dict get(或更常见的是open)之类的命令失败时,程序必须处理它,这意味着它必须以某种方式警告失败。

最常见的选项是使失败的命令

  1. 返回域外值(例如,在包含它的语言中为null),或

  2. 提出异常。

  3. (例如lsearch命令如果成功则返回索引值,如果失败则返回-1(第一个选项)。dict get命令如果成功则返回一个值,如果它成功则引发异常失败(第二个选项)。)

    第一个选项对于dict get命令来说并不实际可行,因为没有域外值。任何Tcl值都可能存储在字典中,因此您无法查看dict get的结果并知道它未能找到值。空字符串通常用作Tcl中的伪空值,但很可能空字符串是字典中的实际值。

    因此dict get失败时会引发异常。它不是那么糟糕。异常具有许多简洁的属性,例如将控制权直接控制到最近的封闭处理程序,而不管它必须展开多少堆栈级别。

    (实际上不可能处理命令中的所有异常:处理程序必须知道如何处理错误,并且dict get无法知道。)

    无论哪种方式,可能失败的命令都需要包含在某种检查中。如果foo命令用于获取可能不可用且没有合理默认值的资源,则调用它的代码必须如下所示:

    if {[set x [foo]] ne {BAD_RETURN_VALUE}} {
        # use the resource
    } else {
        # deal with failure
    }
    

    或者像这样:

    try {
        foo
    } on ok x {
        # use the resource
    } on error {} {
        # deal with failure
    }
    

    或类似(如果预测foo成功的谓词函数是否存在):

    if {[foo-will-succeed]} {
        set x [foo]
        # use the resource
    } else {
        # deal with failure
    }
    

    在每种情况下,这都是很麻烦的。由于域外值在Tcl中很少见,并且错误处理非常通用,因此谓词或异常策略通常都受到青睐。

    patthoyts已经展示了一种向dict集合添加错误抑制getter函数的方法。另一个相对轻量级的调用是

    set foo [try {dict get $bar xyzzy} on error {} {}]
    

    如果成功则返回dict get调用的结果,如果没有则返回空字符串,并压缩引发的任何错误。

    set foo [try {dict get $bar xyzzy} on error {} {return 42}]
    

    此调用设置失败时使用的默认返回值。

    如果调用仍然很麻烦,可以将其作为命令:

    proc dictget args {
        set default {}
        if {[lindex $args 0] eq {-default}} {
            set args [lassign $args - default]
        }
        try {
            dict get {*}$args
        } on error {} {
            set default
        }
    }
    

    这个概要是

    dictget -default ? <?EM> dictionaryValue ? ? key ...?

    文档:dictifprocreturnsettry