确定Tcl中变量的类型

时间:2011-09-15 08:36:49

标签: variables tcl object-type

我正在寻找一种在Tcl中找到变量类型的方法。例如,如果我有变量$ a,我想知道它是否是整数。

到目前为止,我一直在使用以下内容:

    if {[string is boolean $a]} {
    #do something
    }

这似乎适用于以下类型:
alnum,alpha,ascii,布尔,控制,数字,双,假,图,整数,低,打印,punct,空间,真实,上部,wordchar,xdigit

然而,它无法告诉我我的变量是否可能是数组,列表或字典。有没有人知道如何判断一个变量是否是这三个中的任何一个?

6 个答案:

答案 0 :(得分:12)

Tcl的变量没有类型(除了它们是否真的是一个变量的关联数组 - 即使用$foo(bar)语法 - 你使用array exists)但是Tcl的值做。嗯,有点。 Tcl可以在它认为合适时改变不同类型之间的值,并且不会暴露这些信息[*];你所能做的就是检查一个值是否符合特定的类型。

此类一致性检查是使用string is完成的(出于丑陋的历史原因,您需要-strict选项):

if {[string is integer -strict $foo]} {
    puts "$foo is an integer!"
}

if {[string is list $foo]} {    # Only [string is] where -strict has no effect
    puts "$foo is a list! (length: [llength $foo])"
    if {[llength $foo]&1 == 0} {
        # All dictionaries conform to lists with even length
        puts "$foo is a dictionary! (entries: [dict size $foo])"
    }
}

请注意,所有值都符合字符串的类型; Tcl的值始终可序列化。

[来自评论的编辑]:对于JSON序列化,可以使用脏黑客来产生“正确的”序列化(严格地说,从Tcl的角度来看,所有字符串都是正确的,但这对其他语言并不是很有帮助) Tcl 8.6。最初发布在Rosetta Code上的代码是:

package require Tcl 8.6

proc tcl2json value {
    # Guess the type of the value; deep *UNSUPPORTED* magic!
    regexp {^value is a (.*?) with a refcount} \
        [::tcl::unsupported::representation $value] -> type

    switch $type {
        string {
            # Skip to the mapping code at the bottom
        }
        dict {
            set result "{"
            set pfx ""
            dict for {k v} $value {
                append result $pfx [tcl2json $k] ": " [tcl2json $v]
                set pfx ", "
            }
            return [append result "}"]
        }
        list {
            set result "\["
            set pfx ""
            foreach v $value {
                append result $pfx [tcl2json $v]
                set pfx ", "
            }
            return [append result "\]"]
        }
        int - double {
            return [expr {$value}]
        }
        booleanString {
            return [expr {$value ? "true" : "false"}]
        }
        default {
            # Some other type; do some guessing...
            if {$value eq "null"} {
                # Tcl has *no* null value at all; empty strings are semantically
                # different and absent variables aren't values. So cheat!
                return $value
            } elseif {[string is integer -strict $value]} {
                return [expr {$value}]
            } elseif {[string is double -strict $value]} {
                return [expr {$value}]
            } elseif {[string is boolean -strict $value]} {
                return [expr {$value ? "true" : "false"}]
            }
        }
    }

    # For simplicity, all "bad" characters are mapped to \u... substitutions
    set mapped [subst -novariables [regsub -all {[][\u0000-\u001f\\""]} \
        $value {[format "\\\\u%04x" [scan {& } %c]]}]]
    return "\"$mapped\""
}

警告:不支持上述代码。这取决于脏黑客行为。它可能会在没有警告的情况下破裂。 (但它确实工作。移植到Tcl 8.5需要一个微小的C扩展来读出类型注释。)


[*]严格来说,它确实提供了一个不受支持的界面,用于发现8.6中值的当前类型注释 - 作为::tcl::unsupported::representation的一部分 - 但该信息是故意以人类可读的形式并且可能会发生变化没有公告。它用于调试,而不是代码。此外,Tcl在内部使用了很多不同的类型(例如,缓存的命令和变量名称),在正常情况下你不想探测它们;引擎盖下的事情相当复杂......

答案 1 :(得分:4)

其他答案都提供了非常有用的信息,但值得注意的是很多人一开始并不喜欢这样的事情。

在Tcl中,值没有类型......问题是它们是否可以用作给定类型。你可以这样思考

string is integer $a

你不是在问

  

$ a中的值是否为整数

你问的是

  

我可以将$ a中的值用作整数

当您按照“这是一个整数”的思路时,考虑两个问题之间的区别是有用的。每个整数也是一个有效的列表(一个元素)...所以它can be usedstring is两个命令都会返回true(和其他几个整数一样)。

答案 2 :(得分:1)

如果你想处理JSON,我强烈建议你阅读Tcl wiki上的JSON页面:http://wiki.tcl.tk/json

在那个页面上,我发布了一个简单的函数,它在给定格式描述符的情况下将Tcl值编译为JSON字符串。我还发现该页面上的讨论非常有用。

答案 3 :(得分:0)

对于您想要的数组array exists 对于您想要的词组dict exists

对于列表我认为在8.5之前没有内置方式?有来自http://wiki.tcl.tk/440

proc isalist {string} {
  return [expr {0 == [catch {llength $string}]}]
}

答案 4 :(得分:0)

确定变量是否为数组:

proc is_array {var} {
    upvar 1 $var value
    if {[catch {array names $value} errmsg]} { return 1 } 
    return 0
}   

# How to use it
array set ar {}
set x {1 2 3}
puts "ar is array? [is_array ar]"; # ar is array? 1
puts "x is array? [is_array x]";   # x is array? 0

答案 5 :(得分:0)

对于告诉值是否可以用作字典的特定情况,tcllib的dicttool package有一个dict is_dict <value>命令,如果<value>可以作为一个值,则返回真值。