Значения параметров по умолчанию могут быть только константами, которые вы вычисляете во время объявления процедуры (чаще всего это литералы, что означает, что вам не нужно использовать list
для построения):
proc TestFunction [list [list paramVal [GetParameterValue]]] {
...
}
Чтобы вычислить значение по умолчанию во время вызова процедуры, необходимо переместить вычисление в тело процедуры.Есть несколько способов определить, выполнять ли вычисления, но они сводятся к трем вариантам: использование значения маркера, получение количества слов в вызове и полный контроль над синтаксическим анализом.
Использование значения маркера
Хитрость в том, чтобы найти какое-то значение, которое действительно вряд ли будет передано. Например, если это должен быть фрагмент текста, показанный пользователюзначение, не имеющее ничего, кроме ASCII NUL в нем, не произойдет;установите его в значение по умолчанию, тогда вы сможете определить, есть ли у вас значение по умолчанию, и можете заменить его тем, что предоставляет сложный код.
proc TestFunction {{paramVal "\u0000"}} {
if {$paramVal eq "\u0000"} {
set paramVal [GetParameterValue]
}
...
}
Получение количества слов в вызове
Этоопирается на возможности команды info level
introspection.В частности, info level 0
сообщает полный список фактических аргументов текущей процедуре.Немного подсчитаем, и мы сможем узнать, было ли передано реальное значение.
proc TestFunction {{paramVal "dummy"}} {
if {[llength [info level 0]] < 2} {
# Note that the command name itself is always present
set paramVal [GetParameterValue]
}
...
}
Это абсолютно общий подход, поэтому не стоит беспокоиться о случае, когда кто-то предоставляет неожиданный крайний случай, но это большеСложно, когда у вас есть несколько аргументов, так как вам нужно выяснить, сколько аргументов должно присутствовать и так далее.Это просто в этом случае, но становится все сложнее, когда у вас появляется больше аргументов.
Полный контроль над синтаксическим анализом
В конечном счете, вы также можете принять решение о создании процедуры, которая получает полный контроль надразбор его аргументов.Вы делаете это, давая ему единственный аргумент args
, и затем вы можете использовать любой подход, который вы хотите обработать фактический список аргументов.(Я обычно не ставлю формальный список аргументов в скобках , в данном случае только , но это только мой стиль.)
proc TestFunction args {
if {[llength $args] == 0} {
set paramVal [GetParameterValue]
} elseif {[llength $args] == 1} {
set paramVal [lindex $args 0]
} else {
# IMPORTANT! Let users discover how to use the command!
return -code error -errorcode {TCL WRONGARGS} \
"wrong # args: should be \"TestFunction ?paramVal?\""
}
...
}
В настоящее время это единственный способ сделать что-то действительно продвинутоеНапример, иметь необязательные аргументы перед обязательными.Это также в значительной степени то, что вам пришлось бы делать в C, если бы вы реализовали команду там, хотя и с поправкой на другой язык.Недостатком является то, что это определенно больше работы, чем использование встроенного базового кода поддержки синтаксического анализа аргументов, предоставляемого реализацией команды proc
.