我正在寻找一种在Tcl中找到变量类型的方法。例如,如果我有变量$ a,我想知道它是否是整数。
到目前为止,我一直在使用以下内容:
if {[string is boolean $a]} {
#do something
}
这似乎适用于以下类型:
alnum,alpha,ascii,布尔,控制,数字,双,假,图,整数,低,打印,punct,空间,真实,上部,wordchar,xdigit
然而,它无法告诉我我的变量是否可能是数组,列表或字典。有没有人知道如何判断一个变量是否是这三个中的任何一个?
答案 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 used
和string 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>
可以作为一个值,则返回真值。