Tcl lappend возвращает неожиданные результаты

Я просматриваю руководство по Tcl, и оператор lappend возвращая неожиданные результаты.

Я запускаю это на интерфейсе командной строки оборудования для балансировки нагрузки F5. Вот соответствующая системная информация:

~ \#  cat /proc/version
  Linux version 2.6.32-431.56.1.el6.f5.x86_64 (f5cm@build19) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Wed Jun 8 11:41:48 PDT 2016

% puts $tcl_version
8.5

Я пробовал все перестановки группировки переменных, какие только мог придумать, и все равно не смог получить ожидаемых результатов. Похоже, что есть буфер, в котором хранятся все результаты команды: команда «puts» и использование ее в команде «lappend». Вот строки, которые я выполнил. Первые несколько «путей» просто показывают, что еще ничего не инициализировано:

% puts $l1

can't read "l1": no such variable

% puts $l2

can't read "l2": no such variable

% puts $l3

can't read "l3": no such variable

% puts $l4

can't read "l4": no such variable

% puts $l5

can't read "l5": no such variable

% set l1 { {item 1} {item 2} {item 3} }

 {item 1} {item 2} {item 3}

% set l2 { {item 4} {item 5} {item 6} }

 {item 4} {item 5} {item 6}

% set l3 [concat $l1 $l2]

{item 1} {item 2} {item 3} {item 4} {item 5} {item 6}

#things working as expected here
% puts $l3

{item 1} {item 2} {item 3} {item 4} {item 5} {item 6}

#this is where things start to get squirrelly. I would expect this to return the result of $l1 concat with $l2 and the result stored in $l1
% lappend $l1 $l2

{ {item 4} {item 5} {item 6} }

#as you can see, it appears to return the second argument when that argument is a list. 
% lappend $l2 $l1

{ {item 1} {item 2} {item 3} }

# $l1 remains unchanged. at the very least, according to the documentation,
# I would expect that second item would be treated as a single entity
# when it is a list, and that the fourth item in '% lappend $l2 $l1' would be $l1
% puts $l1

 {item 1} {item 2} {item 3}

#neither $l2 nor $l1 are modified as the result of the 'lappend' command.
% puts $l2

 {item 4} {item 5} {item 6}

#more squirrelly-ness. when the arguments being passed are individual, it seems as though the last call to 'puts' is what 'lappend' uses for its first argument. this is confirmed on the last 3 commands below. **strong text**
% lappend $l1 "a" "b" "c"

{ {item 4} {item 5} {item 6} } a b c

% puts $l1

 {item 1} {item 2} {item 3}

% lappend "$l1" "$l2"

**{ {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} }**

% puts $l1

 {item 1} {item 2} {item 3}

% puts $l2

 {item 4} {item 5} {item 6}

% set l4 [lappend $l1 $l2]

 **{ {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} } { {item 4} 
{item 5} {item 6} }**

% puts $l4

 { {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} } { {item 4} 
{item 5} {item 6} }

# confirmed. 'lappend' is using last call to 'puts' as its argument for it's first argument. this can't be intended behavior right?
% puts $l1
 {item 1} {item 2} {item 3}
% set l5 [lappend $l2 "a" "b" "c"]
 { {item 1} {item 2} {item 3} } a b c
% puts $l2
 {item 4} {item 5} {item 6}

Я не могу представить, что такое поведение предназначено.

Вот как я представляю, как это должно работать:

#should return something like [$list1, [$list2]] or something like concat $list1 $list2
% lappend $list1 $list2

#should return each item concatenated to the end of $list1
% lappend $list1 "a" "b" "c"

Если ответ заключается в том, что lappend не изменяет первый аргумент на месте, и мне приходится использовать команду set для сохранения результатов команды lappend, это нормально; Однако команда lappend, похоже, ведет себя непоследовательно.

Заранее спасибо за любую помощь/понимание.


person Joe Guichebarou    schedule 17.01.2017    source источник
comment
Вы вызываете здесь неопределенное поведение. Когда вы запустили lappend $l1 $l2, lappend ожидает доступную для записи переменную в качестве своего первого аргумента, но вы даете ей переменную только для чтения. Если бы это был lappend l1 $l2 (обратите внимание на отсутствие $ в l1), он будет работать как положено. Эквивалентом concat $l1 $l2 является lappend '' $l1 $l2.   -  person alvits    schedule 18.01.2017
comment
классно. Благодарю. это изящный маленький трюк с пустой строкой.   -  person Joe Guichebarou    schedule 18.01.2017
comment
Это не пустая строка. Это переменная с именем '' . Tcl не использует одинарные кавычки для цитирования чего-либо.   -  person Brad Lanam    schedule 18.01.2017
comment
Это все потому, что « {item 1} {item 2} {item 3} » (с пробелами) является допустимым (но очень необычным) именем переменной в Tcl.   -  person Donal Fellows    schedule 18.01.2017
comment
согласно документации, все, что заключено в фигурные скобки, рассматривается как текст.   -  person Joe Guichebarou    schedule 18.01.2017


Ответы (2)


lappend $l1 $l2 добавляет содержимое l2 к переменной NAMED по содержимому l1. Вам нужен lappend l1 $l2, почти так же, как вы устанавливаете переменные через set l1 whatever, а не set $l1 whatever.

person jasonharper    schedule 17.01.2017
comment
Ах. понял, спасибо. Это похоже на указатели в стиле C. Мне нужен сам список, а не содержимое списка? - person Joe Guichebarou; 18.01.2017
comment
@JoeGuichebarou Поскольку вы модифицируете его, вам нужна переменная, содержащая список, а не значение списка, которое было в переменной. - person Donal Fellows; 18.01.2017

lappend принимает в качестве первого аргумента имя переменной, а не список. В этом случае:

   set l1 [list a b c]
   lappend $l1 x
   puts [set {a b c}]
   # returns: x

x добавляется к переменной с именем {a b c}.

Вместо этого используйте имя переменной в качестве первого аргумента для lappend:

   set l1 [list a b c]
   set l2 [list d e f]
   lappend l1 {*}$l2
   # result: a b c d e f

Общее правило, которое следует помнить, состоит в том, что если команда Tcl изменяет свой аргумент, необходимо передать имя переменной. Если команда Tcl не изменяет свой аргумент, передать значение (это правило не работает для массивов).

Ссылки: lappend

person Brad Lanam    schedule 17.01.2017
comment
И, к сожалению, этот учебник не делает надлежащего различия в своих спецификациях синтаксиса. Я думаю, что на данный момент вам нужно также просмотреть страницы руководства, чтобы вы могли увидеть правильный синтаксис. Также доступны другие обучающие программы. - person Brad Lanam; 18.01.2017