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

Я попытался сделать следующее в TCL и получил следующую ошибку: «список должен состоять из четного числа элементов», потому что $args рассматривается как один список при передаче в B.

Есть ли умный способ передать $args в B?

proc A {a args} {        
    #call B and pass it args
    B 2 $args
}

proc B {b args} {
    set options(-flag1)  0
    set options(-option) serial

    array set options $args
    #use options
}

person abdullam    schedule 16.02.2016    source источник
comment
Вы используете команду array set? Поделитесь полным кодом.   -  person Dinesh    schedule 16.02.2016
comment
Вот, @Dinesh, я обновил код   -  person abdullam    schedule 16.02.2016


Ответы (1)


Попробуй это:

B 2 {*}$args

Если немного упростить процедуры:

proc A args {
    puts [info level 0]
    B $args
}
proc B args {
    puts [info level 0]
}

Если мы вызовем A с некоторыми значениями, B получит эти значения, упакованные в список. Этот список, будучи отдельным элементом в args, не подходит для передачи в array set, так как этой команде нужен список четного размера.

% A a b c d
A a b c d
B {a b c d}

Измените вызов B на это:

proc A args {
    puts [info level 0]
    B {*}$args
}

Теперь, если мы вызовем A, каждый аргумент A станет отдельным аргументом B, а $args теперь можно будет использовать в качестве аргумента array set.

% A a b c d
A a b c d
B a b c d

Как указывает Нурдгоу, в Tcl 8.4 и более ранних версиях нет синтаксиса {*}, что означает, что для вызова B необходимо использовать eval. Один из способов сделать это

eval [linsert $args 0 B]

но можно также использовать немного менее безопасный (это может привести к потере структуры аргумента)

eval B $args

Tcl 8.4 больше не поддерживается, и есть все основания для обновления до 8.5 или 8.6.

Документация: eval, info, linsert, proc, puts, {*}

person Peter Lewerin    schedule 16.02.2016
comment
Просто расставить точки над последним i... Оператор {*} появился в Tcl 8.5. Если вы действительно должны использовать более раннюю версию, вам нужно вызвать B через более непрозрачный eval [linsert $args 0 B], который создает новый список, содержащий B и все отдельные аргументы, а затем оценивает этот список как команду. - person nurdglaw; 16.02.2016
comment
Учитывая, что это args, который гарантированно является правильным списком, вам подойдет eval [list B] $args. Это более понятно, чем версия linsert. Но обязательно обновите, так как 8.4 больше не поддерживается. - person Donal Fellows; 17.02.2016
comment
Черт!! Питер и @nurdglaw, я не могу вас отблагодарить. Спас мой день. А по поводу версии, я использую 8.3. Я только начинаю работать в крупной компании, и у меня нет кода. Я не думаю, что они захотят обновляться в ближайшее время. Но я спрошу. - person abdullam; 17.02.2016