Переменные 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\""
}
Предупреждение: Указанный выше код не поддерживается. Itзависит от грязных хаков.Это может сломаться без предупреждения.(Но он работает . Портирование на Tcl 8.5 потребует небольшого расширения C для считывания аннотаций типов.)
[*] Строго говоря, он предоставляет неподдерживаемый интерфейсдля обнаружения текущей аннотации типа значения в 8.6 - как часть ::tcl::unsupported::representation
- но эта информация находится в сознательно понятной для человека форме и может быть изменена без объявления.Это для отладки, а не кода.Кроме того, Tcl использует довольно много различных типов внутри себя (например, кэшированные имена команд и переменных), которые вы не захотите проверять в обычных условиях;под капотом все довольно сложно…