Tcl не делает полных замыканий, но может делать их ограниченные версии для ключевых случаев использования;если вы видите {*}
, примененное к очевидному первому слову команды, то это именно то, что происходит.Например, вы использовали (объект) callback сценарий использования.Это довольно просто сделать:
set performPath [namespace code [list my performPath $url {*}$args]]
(namespace code
гарантирует, что обратный вызов будет оценен в правильном пространстве имен, даже если он запускается извне объекта.)
Мы могли бы дажесделайте это аккуратнее, определив вспомогательную процедуру:
proc ::oo::Helpers::callback {method args} {
tailcall namespace code [list my $method {*}$args]
}
set performPath [callback performPath $url {*}$args]
Аналогичным образом, можно также использовать вариант использования переменная перехват .Вот простейшая версия, предполагающая, что все переменные не являются массивами:
proc closure {body} {
set binding {}
foreach v [uplevel 1 info locals] {
upvar 1 $v var
if {[info exists var]} {
lappend binding [list $v $var]
}
}
return [list apply [list $binding $body [uplevel 1 namespace current]]]
}
Демонстрация того, как его использовать:
proc foo {n} {
set result {}
for {set i 1} {$i <= $n} {incr i} {
lappend result [closure {
puts "This is $i of $n"
}]
}
return $result
}
foreach c [lreverse [foo 10]] {
{*}$c
}
(Обработка массивов и аргументов делает это несколько более сложным.)
Если вам нужно изменить состояние в «замыкании», то вам нужно использовать объект или сопрограмму для хранения состояния.Основная проблема с любым из них заключается в том, что вам нужно явно очистить результирующую команду, когда вы закончите;стандартный Tcl не собирает неиспользуемые команды.