Variables 确定Tcl中变量的类型
我正在寻找一种在Tcl中查找变量类型的方法。例如,如果我有一个变量$a,我想知道它是否是一个整数 到目前为止,我一直在使用以下工具:Variables 确定Tcl中变量的类型,variables,tcl,object-type,Variables,Tcl,Object Type,我正在寻找一种在Tcl中查找变量类型的方法。例如,如果我有一个变量$a,我想知道它是否是一个整数 到目前为止,我一直在使用以下工具: if {[string is boolean $a]} { #do something } 这似乎对以下类型非常有效: alnum、alpha、ascii、boolean、control、digit、double、false、graph、integer、lower、print、putch、space、true、upper、wordchar
if {[string is boolean $a]} {
#do something
}
这似乎对以下类型非常有效:alnum、alpha、ascii、boolean、control、digit、double、false、graph、integer、lower、print、putch、space、true、upper、wordchar、xdigit
但是,它不能告诉我我的变量是数组、列表还是字典。有人知道一种方法来判断一个变量是否是这三个变量中的一个吗?对于您想要的数组
数组存在
对于您想要的dictdict存在
对于一个列表,我不认为在8.5?之前有一个内置的方式,这是从
Tcl的变量没有类型(除了它们是否真的是变量的关联数组-即使用
$foo(bar)
语法-您使用数组存在
),但Tcl的值有。嗯,有点。Tcl可以根据需要在不同类型之间改变值,并且不公开此信息[*];您真正能做的就是检查值是否符合特定类型
此类一致性检查是使用字符串is
(出于历史原因,您需要-strict
选项):
请注意,所有值都符合字符串的类型;Tcl的值总是可序列化的
[EDIT from comments]:对于JSON序列化,可以使用肮脏的黑客来使用Tcl 8.6生成“正确”的序列化(严格地说,从Tcl的角度来看,将所有内容放在一个字符串中是正确的,但这对其他语言没有帮助)。最初发布在上的执行此操作的代码是:
警告:不支持上述代码。这取决于肮脏的黑客。它很容易在没有警告的情况下坏掉。(但它确实有效。移植到Tcl 8.5需要一个小小的C扩展来读取类型注释。)
[*]严格地说,它确实提供了一个不受支持的接口,用于发现8.6中某个值的当前类型注释(作为
::tcl::unsupported::representation
)的一部分),但该信息是故意以人类可读的形式出现的,可能会在不经宣布的情况下进行更改。这是为了调试,而不是代码。此外,Tcl在内部使用了很多不同的类型(例如,缓存的命令和变量名),在正常情况下您不希望对这些类型进行探测;要确定一个变量是否是一个数组,事情是相当复杂的…:
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
如果您想处理JSON,那么我强烈建议您阅读Tcl wiki上的JSON页面:
在那个页面上,我发布了一个简单的函数,该函数在给定格式描述符的情况下将Tcl值编译为JSON字符串。我还发现该页面上的讨论内容非常丰富。其他答案都提供了非常有用的信息,但值得注意的是,许多人一开始似乎并不喜欢这些信息 在Tcl中,值没有类型。。。他们的问题是它们是否可以用作给定的类型。你可以这样想
string is integer $a
你不是在问
美元中的值是整数吗
你问的是
我可以使用$a中的值作为整数吗
当你沿着“这是一个整数”的思路思考这两个问题的区别时,它是有用的。每个整数也是(一个元素的)有效列表。。。因此它可以用作,并且两个字符串都是命令将返回true(对于整数,其他几个命令也会返回true)。对于判断值是否可用作字典的特定情况,tcllib有一个
dict is_dict
命令,如果
可以作为一个值,它将返回一个真值。谢谢:)您能解释一下在这种情况下如何使用dict吗?我尝试过这样使用它:如果{[dict exists$testData2 nullval]}{#do something},但如果变量不是dict,它将返回错误@Tom,在这种情况下,我会将if语句包装为“catch”,这将允许您处理变量不是dict的情况。谢谢您的反馈,但这似乎行不通。在if{[string is list$foo]}{部分。包含多个单词的字符串也可以看到als列表。此外,如果我的列表包含偶数项,则此代码将始终将其分类为字典。我不确定我尝试执行的操作是否可行,但您的代码也可能是最好的解决方案。@Tom,这是因为包含mul的字符串tiple words与使用“list”命令创建的变量没有区别。例如,尝试以下操作:set foo“ab bb dd”;lindex$foo 1isstring是list
8.5或8.6?,据我所知,Tom可能无法使用它?它在8.5中,这是当前的标准生产级别版本。在8.4上(或之前!)将使您有资格成为“过时的”(或被困在Java中)。@Tom:嗯,所有偶数长度的列表都是有效的字典,尽管可能表示形式不太理想(例如,重复键)。你需要它的什么版本?你能解释一下为什么你首先需要它吗?我的意思是,既然TCL本质上是一种无类型语言,你所要求的看起来像是在自找麻烦。@Kostix,当然不是。我需要它的原因是创建一个过程,在这个过程中,字典被解析为JSON。例如,JSON中的字符串是surroun由“”编码,而整数不是。另外,如果字典要包含另一个字典,该字典应该在JSON对象中获得自己的JSON对象。@Tom,我会选择另一种方法,并要求包的用户向序列化程序提供一个(人工的)使用显式类型标记的带注释的结构。如序列化[object$mykey1[int$value]$mykey2[float$bar]]
等。尝试推断无类型值的类型是错误的
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\""
}
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
string is integer $a