Есть ли обходной путь для передачи переменного количества аргументов без использования аргументов - PullRequest
1 голос
/ 16 марта 2020

Вот код:

>cat /tmp/test_args.tcl
proc t1 {args} {
    return $args
}

proc t2 {args} {
    puts "t2:[llength $args]"
    return
    set len [llength $args]
    if {$len == 1} {
        proc_len_1 [lindex $args 0]
    } elseif {$len == 2} {
        proc_len_2 [lindex $args 0]  [lindex $args 1]
    } else {
        proc_len_x $args
    }
}

set tup3 [t1 1 2 3 4 5 6]
puts "before calling t2:[llength $tup3]"
t2 $tup3
t2 100
t2 100  200

Вот вывод:

>tclsh /tmp/test_args.tcl
before calling t2:6
t2:1
t2:1
t2:2

Я использую TCL 8.6.

Вы можете увидеть это перед вызовом t2 , $ tup3 является списком, но pro c t2 получает $ tup3 как одно единственное значение, поэтому вместо * списка значений pro c t2 получает список списка значений.

Но намерение pro c t2, как видно из кода после «возврата», состоит в том, чтобы иметь дело с различным количеством аргументов и, основываясь на количестве аргументов, делать разные вещи. Теперь вызов t2 с помощью переменной списка и литерала обрабатывается одинаково. Это проблема.

Единственное решение, которое я могу придумать, это изменить

t2 $tup3

на

t2 {*}$tup3

Но у меня есть ограничение: $ tup3 нужно оставайтесь такими же, когда оно передается другому профессионалу c. Например, у меня может быть такой pro c, который также ожидает $ tup3:

proc t3 {arg1} {
}
t3 $tup3

Так что в идеале, если каким-то образом я смогу сделать так, чтобы «args» не переносил значения в список, тогда моя проблема решена. Ну, я знаю, что так работает TCL.

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

Спасибо.

Ответы [ 2 ]

0 голосов
/ 16 марта 2020

Tcl, по своей конструкции, очень усложняет процедуру (или определяемую C команду) синтаксис ее вызова. Совершенно очевидно, что так оно и есть, так как это значительно упрощает произвольное составление команд. Команды, которым необходимо уделять особое внимание синтаксису их вызова, рекомендуется выполнить дополнительный шаг для обработки своего аргумента с соответствующими вызовами для выполнения действий в среде вызывающей стороны (тривиально в C, немного сложнее в Tcl процедур из-за дополнительного кадра стека).

proc example inputString {
    # Parse the string and work out what we want to do
    if {[regexp {^\$(\w+)$} $inputString -> varName]} {
        upvar 1 $varName value
    } else {
        set value $inputString
    }
    # Do something with the result
    puts "my input string was '$inputString'"
    puts "my value is '$value'"
    catch {
        puts "its length is [llength $value]"
    }
}

example {foo bar boo}
set x 123
example {$x}

Это печатает:

my input string was 'foo bar boo'
my value is 'foo bar boo'
its length is 3
my input string was '$x'
my value is '123'
its length is 1

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

proc example inputString {
    puts "I was called as: [dict get [info frame -1] cmd]"
}

# To show why this can be awkward, be aware that you get to see *all* the details...
example {foo bar boo}
example "quick brown fox"
example [expr {1 + sqrt(rand())}]
set x 123
example $x

Что печатает:

I was called as: example {foo bar boo}
I was called as: example "quick brown fox"
I was called as: example [expr {1 + sqrt(rand())}]
I was called as: example $x

Первый подход, приведенный выше, с передачей литерала, который вы анализируете сами (при необходимости с помощью Tcl): считается хорошим стилем Tcl. Встраивание языка в Tcl (который может быть самим Tcl или каким-либо другим языком; люди показали, что это работает со встроенными C и Fortran, и нет никаких оснований ожидать, что любой другой язык будет большой проблемой, хотя и получал полезную семантику оценки иногда может быть ... хитрым) абсолютно нормально.

0 голосов
/ 16 марта 2020

Если вы хотите передать список, просто примите его в качестве аргумента:

proc a { mylist } {
    b $mylist
}
proc b { mylist } {
   foreach {k} $mylist {
      puts $k
   }
}
set tup3 [t1 1 2 3 4 5 6]
a $tup3

Редактировать:

Для переменного числа аргументов, используя обработка командной строки самая простая.

proc a { args } {
   array set arguments $args
   if { [info exists arguments(-tup3)] } {
      puts "tup3: $arguments(-tup3)"
   }
   if { [info exists arguments(-tup1)] } {
      puts "tup1: $arguments(-tup1)"
   }
   parray arguments
}
set tup3 [list 1 2 3 4 5 6]
a -tup1 test1 -tup3 $tup3 -tup2 test2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...