2008-10-31 2 views
2

Работа с TCL, и я хотел бы реализовать что-то вроде Strategy Pattern. Я хочу перейти в «стратегию» для вывода на печать в функции TCL, поэтому я могу легко переключаться между печатью на экран и печатью в файл журнала. Каков наилучший способ сделать это в TCL?Есть ли у TCL какое-то понятие указателей функций?

+0

Не просите указатели на функцию в TCL, если вы вопрос о реализации Плана стратегии. – JesperE 2008-10-31 13:24:31

ответ

18

TCL позволяет хранить имя процедуры в переменной, а затем вызывать процедуру с использованием этой переменной; так

proc A { x } { 
    puts $x 
} 

set strat A 
$strat Hello 

будет вызывать ргос A и распечатать Hello

1

Как насчет использования переменных функций? Я не помню, много TCL (это было в то время как ...), но, может быть, один из них будет делать то, что вам нужно:

  • [$ вар param1 param2]
  • [$ вар] param1 param2
  • $ вар param1 param2

Если я не прав, кто свободен, поправьте меня.

+0

Это последний, который вы должны использовать. – 2008-10-31 14:24:04

4

Несколько расширен пример того, что было перечислено выше, которые могли бы проиллюстрировать стратегию шаблон более четко:

proc PrintToPDF {document} { 
<snip logic> 
} 

proc PrintToScreen {document} { 
<snip logic> 
} 

proc PrintToPrinter {document} { 
<snip logic> 
} 


set document "my cool formatted document here" 

set printMethod "printer" 


switch -- $printMethod { 
    "printer" { 
     set pMethodName "PrintToPrinter" 
    } 
    "pdf" { 
     set pMethodName "PrintToScreen" 
    } 
    "screen" { 
     set pMethodName "PrintToPDF" 
    } 
} 

$pMethodName $document 
4

В дополнение к ответ, показывающий, как вы назначаете процедуру переменной, вы также можете передать имя процедуры в качестве аргумента другой процедуре. Вот простой пример:


proc foo { a } { 
    puts "a = $a" 
} 

proc bar { b } { 
    puts "b = $b" 
} 

proc foobar { c } { 
    $c 1 
} 

foobar foo 
foobar bar 

Это напечатает а = 1, Ь = 1

0

Чтобы выяснить, почему метод Джексона работает, помните, что в TCL, все является строкой. Независимо от того, работаете ли вы с литеральной строкой, функцией, переменной или каким бы то ни было, все - это строка. Вы можете передать «указатель функции» так же, как вы можете «указатель данных»: просто используйте имя объекта без ведущего «$».

3

Помимо использования proc, вы можете использовать блок кода вместо этого. Есть несколько вариантов этого. первый является наиболее очевидным, всего лишь eval.

set strategy { 
    puts $x 
} 

set x "Hello" 
eval $strategy 
unset x 

Это работает, но есть несколько недостатков. Во-первых, очевидно, что оба фрагмента кода должны сговориться об использовании общего имени для аргументов. Это заменяет одну головную боль в пространстве имен (procs) другим (locals), и это, возможно, фактически хуже.

Менее очевидно, что eval намеренно интерпретирует свой аргумент без компиляции байт-кода. Это связано с тем, что предполагается, что eval будет вызываться с динамически генерируемыми, обычно уникальными аргументами, а компиляция в байт-код будет неэффективной, если байт-код будет использоваться только один раз, относительно просто интерпретировать блок немедленно. Это легче исправить, так вот идиома:

set x "Hello" 
if 1 $strategy 
unset x 

if, в отличие от eval, компилируется и кэшировать его блок кода.Если блок $strategy - это только один или только несколько различных возможных значений, то это работает очень хорошо.

Это не помогает с яростью передачи аргументов блоку с локальными переменными. Есть много способов обойти это, например, делать substitutions тем же способом, что и tk выполняет подстановки по аргументам команды с %. Вы можете попробовать сделать некоторые хакерские вещи, используя uplevel или upvar. Например, вы можете сделать это:

set strategy { 
    puts %x 
} 

if 1 [string map [list %% % %x Hello] $strategy] 

На авось, что аргументы передается не меняются очень много, это работает хорошо с точки зрения байткода компиляции. Если, с другой стороны, аргумент часто изменяется, вы должны использовать eval вместо if 1. В любом случае это не намного лучше, с точки зрения аргументов. Существует меньше вероятность путаницы в том, что прошло, а что нет, потому что вы используете специальный синтаксис. Также это полезно в случае, если вы хотите использовать замену переменных перед возвратом кодового блока: как в set strategy "$localvar %x".

К счастью, tcl 8.5 имеет true anonymous functions, используя команду apply. Первым словом команды apply будет список аргументов и тела, как если бы эти аргументы proc были отменены. Остальные аргументы передаются в анонимную команду как аргументы немедленно.

set strategy [list {x} { 
    puts $x 
}] 

apply $strategy "Hello" 
+0

+1 для Tcl 8.5 информация – 2009-07-25 04:59:01

1
% set val 4444 
4444 

% set pointer val 
val 

% eval puts $$pointer 
4444 

% puts [ set $pointer ] 
4444 

% set tmp [ set $pointer ] 
4444 
Смежные вопросы