tcl中如何将变量参数从一个函数传递到另一个函数

发布于 2024-10-09 20:18:12 字数 789 浏览 3 评论 0原文

我想将一个函数中获得的变量参数传递给另一个函数,但我无法这样做。函数获取偶数个变量参数,然后必须将其转换为数组。下面是示例。

过程 abc1 获取两个参数 (k k),而不是形成 abc1 过程,这些参数必须传递给 proc abc,其中列表到数组的转换就完成了。列表到数组的转换在 proc1 即 abc1 中有效,但在第二个 proc 即 abc 中无效,

下面给出了错误

proc abc {args} {
    puts "$args"
    array set arg $args
}

proc abc1 {args} {
    puts "$args"
    array set arg $args
    set l2 [array get arg]
    abc $l2
}

abc1 k k
abc k k

输出:

k k
{k k}
list must have an even number of elements
    while executing
"array set arg $l1"
    (procedure "abc" line 8)
    invoked from within
"abc $l2"
    (procedure "abc1" line 5)
    invoked from within
"abc1 k k"
    (file "vfunction.tcl" line 18)

I want to pass variable arguments obtained in one function to other function but I am not able to do so. Function gets even number of variable arguments and then it has to be converted in array. Below is the example.

Procedure abc1 gets two arguments (k k) and not form abc1 procedure these have to be passed to proc abc where list to array conversion it to be done. List to array conversion works in proc1 i.e. abc1 but not in second proc i.e. abc

Error obtained is given below

proc abc {args} {
    puts "$args"
    array set arg $args
}

proc abc1 {args} {
    puts "$args"
    array set arg $args
    set l2 [array get arg]
    abc $l2
}

abc1 k k
abc k k

Output:

k k
{k k}
list must have an even number of elements
    while executing
"array set arg $l1"
    (procedure "abc" line 8)
    invoked from within
"abc $l2"
    (procedure "abc1" line 5)
    invoked from within
"abc1 k k"
    (file "vfunction.tcl" line 18)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

新人笑 2024-10-16 20:18:12

最佳解决方案:扩展替换

正确的方法是确保外部过程(以堆栈术语来说)正确调用内部过程;如果需要多个参数,则应该提供这些参数。随着 Tcl 8.5 的出现,这可以通过称为扩展替换的小语言语法轻松完成:

proc abc1 {args} {
    puts "$args"
    array set arg $args
    set l2 [array get arg]
    abc {*}$l2
    # Or combine the two lines above into: abc {*}[array get arg]
}

所有 {*} 确实是说单词的其余部分应该被分解(使用列出语法规则)并用作多个参数,而不是 Tcl 默认的“一个视觉单词形成一个单词”规则。这是理想

旧的解决方案:Eval 命令

如果由于某种原因您仍在使用旧版本的 Tcl(即 Tcl 8.4 或之前),那么您可以使用 eval 命令而不是上面的语法:

eval abc $l2

有一些有点 -对上述eval更有效的方法,您可能会在旧代码中看到;例如:

eval [linsert $l2 0 abc]
eval [list abc] [lrange $l2 0 end]
# ... etc ...

但实际上它们都被 abc {*}$l2 废弃了,它更短、编写更简单、速度更快。 (它只是在 8.4 或更早版本中不可用,并且太多部署尚未升级。)如果可以,请使用扩展语法。 事实上,8.5 及更高版本的惯用 Tcl 代码几乎不需要 评估;事实证明这一点的正确程度甚至令该语言的维护者感到相当惊讶。

Best Solution: Expansion Substitution

The right approach is to ensure that the outer procedure (in stack terms) calls the inner one correctly; if multiple arguments are expected, that's what should be supplied. With the advent of Tcl 8.5, that's trivially done with a little language syntax called an expansion substitution:

proc abc1 {args} {
    puts "$args"
    array set arg $args
    set l2 [array get arg]
    abc {*}$l2
    # Or combine the two lines above into: abc {*}[array get arg]
}

All the {*} does is say that the rest of the word should be broken up (using list syntax rules) and used as multiple arguments instead of Tcl's default “one visual word forms a single word” rules. It's ideal for this.

Old Solution: Eval Command

If you're still using old versions of Tcl for some reason (i.e., Tcl 8.4 or before) then you use the eval command instead of the above syntax:

eval abc $l2

There are some somewhat-more-efficient approaches to the above eval, which you might see in older code; for example:

eval [linsert $l2 0 abc]
eval [list abc] [lrange $l2 0 end]
# ... etc ...

But really they're all rendered obsolete by abc {*}$l2 which is shorter, simpler to write, and faster. (It's just not available in 8.4 or before, and too many deployments have yet to upgrade.) Use the expansion syntax if you can. Indeed, idiomatic Tcl code for 8.5 and later hardly ever needs eval; the extent to which this has proved true has even been rather surprising to the language's maintainers.

鲜肉鲜肉永远不皱 2024-10-16 20:18:12

之间有很大的区别

abc k k

abc [array get arg]

。在第一种情况下,您传递两个参数,每个参数都是 k。在第二种情况下,您将传递一个列表 - 在您的示例中,是两个 k 的列表:k k

Nir 的答案 故意绕过这个问题,但更好的解决方案是编写 abc1 以便它正确调用 abc

proc abc1 {args} {
  array set arg $args
  set l2 [array get arg]
  eval abc $l2
  # or just
  # eval abc $args
}

There's a big difference between

abc k k

and

abc [array get arg]

In the first case, you're passing two arguments, each of which is k. In the second case you're passing a list of things - in your example, a list of two k's: k k.

Nir's answer knowingly hacks around this problem, but the better solution is to write abc1 so that it calls abc properly:

proc abc1 {args} {
  array set arg $args
  set l2 [array get arg]
  eval abc $l2
  # or just
  # eval abc $args
}
痴者 2024-10-16 20:18:12

当您传递 abc $l2 时,您将 abc1 的 args 作为单个参数传递给 abc。因此,在 abc 中,args 包含一个包含单个项目 ({kk}) 的列表。

你可以这样做:

proc abc {args} {    
  #the next line assumes that if $args has only a single item, then it is 
  #a list in itself. It's a risky decision to make but should work here.
  if { [llength $args] == 1 } { set args [lindex $args 0] }
  puts "$args"
  array set arg $args
}

When you pass abc $l2 you are passing abc1's args as a single argument to abc. So in abc args holds a list with a single item ({k k}).

You can do something like this:

proc abc {args} {    
  #the next line assumes that if $args has only a single item, then it is 
  #a list in itself. It's a risky decision to make but should work here.
  if { [llength $args] == 1 } { set args [lindex $args 0] }
  puts "$args"
  array set arg $args
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文