确定 Tcl 中变量的类型 [英] Determine type of a variable in Tcl

查看:40
本文介绍了确定 Tcl 中变量的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking for a way to find the type of a variable in Tcl. For example if I have the variable $a and I want to know whether it is an integer.

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

I have been using the following so far:

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

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

and this seems to work great for the following types:
alnum, alpha, ascii, boolean, control, digit, double, false, graph, integer, lower, print, punct, space, true, upper, wordchar, xdigit

但是它无法告诉我我的变量是数组、列表还是字典.有谁知道一种方法来判断一个变量是否是这三个中的任何一个?

However it is not capable to tell me if my variable might be an array, a list or a dictionary. Does anyone know of a way to tell if a variable is either of those three?

推荐答案

Tcl 的变量没有类型(除了它们是否真的是变量的关联数组——即,使用 $foo(bar) 语法 — 您使用 array exists) 但 Tcl 的值可以.嗯,有点.Tcl 可以在它认为合适的情况下改变不同类型之间的值,并且不会公开此信息[*];您真正能做的就是检查一个值是否符合特定类型.

Tcl's variables don't have types (except for whether or not they're really an associative array of variables — i.e., using the $foo(bar) syntax — for which you use array exists) but Tcl's values do. Well, somewhat. Tcl can mutate values between different types as it sees fit and does not expose this information[*]; all you can really do is check whether a value conforms to a particular type.

这样的一致性检查是用 string is 完成的(因为丑陋的历史原因,你需要 -strict 选项):

Such conformance checks are done with string is (where you need the -strict option, for ugly historical reasons):

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 的值总是可序列化.

Note that all values conform to the type of strings; Tcl's values are always serializable.

[来自评论的编辑]:对于 JSON 序列化,可以使用脏黑客来生成正确"的序列化(严格地说,从 Tcl 的角度来看,将所有内容都放在一个字符串中是正确的,但这对其他语言并没有帮助)TCL 8.6.执行此操作的代码最初发布在 Rosetta Code 上是:

: For JSON serialization, it's possible to use dirty hacks to produce a "correct" serialization (strictly, putting everything in a string would be correct from Tcl's perspective but that's not precisely helpful to other languages) with Tcl 8.6. The code to do this, originally posted on Rosetta Code is:

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 扩展来读出类型注释.)

Warning: The above code is not supported. It depends on dirty hacks. It's liable to break without warning. (But it does work. Porting to Tcl 8.5 would require a tiny C extension to read out the type annotations.)

[*] 严格地说,它确实提供了一个不受支持的接口,用于发现 8.6 中值的当前类型注释——作为 ::tcl::unsupported::representation 的一部分——但该信息是以人为可读的形式,如有更改,恕不另行通知.它用于调试,而不是代码.此外,Tcl 在内部使用了相当多的不同类型(例如,缓存的命令和变量名称),在正常情况下您不会想要探查这些类型;幕后的事情相当复杂......

[*] Strictly, it does provide an unsupported interface for discovering the current type annotation of a value in 8.6 — as part of ::tcl::unsupported::representation — but that information is in a deliberately human-readable form and subject to change without announcement. It's for debugging, not code. Also, Tcl uses rather a lot of different types internally (e.g., cached command and variable names) that you won't want to probe for under normal circumstances; things are rather complex under the hood…

这篇关于确定 Tcl 中变量的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆