【问题标题】:Tcl lappend returning unexpected resultsTcl lappend 返回意外结果
【发布时间】:2017-01-17 22:01:21
【问题描述】:

我正在查看Tcl tutorial,而 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”命令中使用它。这是我执行的行。前几个 'put' 只是表明尚未初始化任何内容:

% 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 命令的行为方式似乎不一致。

在此先感谢您提供任何帮助/见解。

【问题讨论】:

  • 您在这里调用了未定义的行为。当你运行lappend $l1 $l2 时,lappend 期望一个可写变量作为它的第一个参数,但你给它一个只读变量。如果是lappend l1 $l2(请注意l1 中没有$),它将按预期工作。 concat $l1 $l2 的等价物是 lappend '' $l1 $l2
  • 太棒了。谢谢。这是一个使用空字符串的巧妙小技巧。
  • 这不是一个空字符串。那是一个名为 '' 的变量。 Tcl 不使用单引号来引用任何内容。
  • 这都是因为“ {item 1} {item 2} {item 3} ”(带有空格)在 Tcl 中是一个有效的(但非常不寻常的)变量名。
  • 根据文档,用大括号括起来的所有内容都被视为文本。

标签: list tcl embedded-linux tclsh


【解决方案1】:

lappend $l1 $l2 将 l2 的内容附加到由 l1 的内容命名的变量中。你想要lappend l1 $l2,就像你通过set l1 whatever设置变量一样,而不是set $l1 whatever

【讨论】:

  • 啊。知道了谢谢。这有点像 C 风格的指针。我想要列表本身,而不是列表的内容?
  • @JoeGuichebarou 因为您要修改它,所以您希望 variable 保存列表,而不是列表 value在变量中。
【解决方案2】:

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

【讨论】:

  • 不幸的是,该教程在其语法规范中没有做出适当的区分。我认为暂时,您还需要打开手册页,以便您可以看到正确的语法。还有其他可用的教程。
猜你喜欢
  • 2017-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-10
相关资源
最近更新 更多