确定Tcl中变量的类型

Tom*_*Tom 10 variables tcl object-type

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

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

    if {[string is boolean $a]} {
    #do something
    }
Run Code Online (Sandbox Code Playgroud)

这似乎适用于以下类型:
alnum,alpha,ascii,boolean,control,digit,double,false,graph,integer,lower,print,punct,space,true,upper,wordchar,xdigit

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

Don*_*ows 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])"
    }
}
Run Code Online (Sandbox Code Playgroud)

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

[来自评论的编辑]:对于JSON序列化,可以使用脏黑客来产生"正确的"序列化(严格地说,从Tcl的角度来看,所有字符串都是正确的,但这对其他语言来说并不是很有用).最初在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\""
}
Run Code Online (Sandbox Code Playgroud)

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


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


RHS*_*ger 5

其他答案都提供了非常有用的信息,但是值得注意的是,很多人一开始似乎并不讨厌。

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

string is integer $a
Run Code Online (Sandbox Code Playgroud)

你不是问

$ a中的值是整数吗?

你要问的是

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

考虑“这是整数”的思路时,考虑两个问题之间的区别是很有用的。每个整数也是(一个元素的)有效列表……因此can be used,任何string is一个都是整数,两个命令都将返回true(一个整数将返回其他几个命令)。


jk.*_*jk. 0

对于你想要的数组array exists 对于你想要的字典dict exists

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

proc isalist {string} {
  return [expr {0 == [catch {llength $string}]}]
}
Run Code Online (Sandbox Code Playgroud)