【问题标题】:tcl: proc body in quotes instead of curly bracketstcl: proc 正文用引号代替大括号
【发布时间】:2021-05-18 13:07:20
【问题描述】:

如果 proc 的主体用引号而不是花括号提供,是否有任何问题(例如性能损失)?

我的代码在其他过程中生成过程(作为类似 OOP 的方法),例如

proc dataObject {name someData} {
  # more stuff
  proc ${name}.getData {args} \
    "checkArgs \$args 0; return $someData"
  # more stuff
}

为了简单起见,我使用引号来启用变量替换。它可以工作,但我只是担心代码可能没有被预编译或什么的。

感谢您的帮助!

【问题讨论】:

  • 当你可以使用 oo::object 时,为什么要做类似 OOP 的东西?

标签: tcl proc


【解决方案1】:

我只是担心代码可能没有预编译或什么的。

这个不用担心,另外,Tcl 中没有预编译或类似的东西。第一次执行后,生成的 proc 的主体将被字节编译(但是主体脚本是组装的)。

但是,您的 proc 生成器并不可靠。当someData 包含一个导致正文脚本或其命令之一不完整的字符串时,引号下的变量替换将破坏您的正文脚本,例如:

dataObject test "do it"

会失败,因为它转换成

return do it;

有几种方法可以以稳健的方式组合脚本(命令序列字符串),一种是使用list 保护:

proc dataObject {name someData} {
    set procName ${name}.getData
    append body {checkArgs $args 0} \;
    append body [list return $someData] \;
    proc $procName {args} $body
    return [namespace which -command $procName]
}

正如 Donal in another answer 所指出的,嵌套 proc 调用并不一定会达到您的预期。但是,在您的情况下,作为生成器,它可能是可以接受的。不过,您可能需要考虑使用 Tcl lambda 或适当的(嗯,数据)对象?

【讨论】:

  • 非常感谢,非常有用的提示和更优雅的解决方案。请问:当你提到一个“合适的对象”时,你想到的 Tcl 结构是什么?
  • ::oo::object::oo::class 正如 Donal 所指出的那样。
  • 请看我对 Donal Fellows 回答的评论:它更像是一个模块,而不是一个类的对象。对 Tcl 中的模块机制有什么建议吗?
【解决方案2】:

很难进行完全可靠的代码生成,但并非不可能,并且在过程主体周围使用双引号是完全合法的。我建议在进行代码生成之前将插入单词的空间限制为非空字母数字;这几乎阻止了所有的恶作剧;需要引用其他值(list 命令可以完全正确引用您需要的一点鼓励)。通常更容易生成一个别名,将一些额外的参数集中到一个不变过程的调用上。这是我的意思的一个非常简单的例子:

proc saySomething {a b} {
    puts -nonewline $a
    puts $b
}

proc makeSpeaker {cmd prefix} {
    interp alias {} $cmd {} saySomething "[string trimright $prefix] "
}

makeSpeaker hello "Hello to"
hello Ralf
# ==> Hello to Ralf

如您所见,我们已经“生成”了包含一个带有空格的单词的代码,而无需进行复杂的引用。它不能做所有事情,但它可以做很多事情。

并且不要编写自己的伪 OO 代码。不是这些天。从 8.6 开始,Tcl 带有一个 OO 系统核心,这使得做这些事情变得更快、更可靠。

oo::class create Speaker {
    variable Prefix
    constructor {prefix} {
        set Prefix "[string trimright $prefix] "
    }
    method say {suffix} {
        puts -nonewline $Prefix
        puts $suffix
    }
}

Speaker create greeting "Hello to"
greeting say Ralf

当然,您可以将这两者混合在一起以获得一些真正强大的方法,但是这个示例有点长,无法快速理解......

【讨论】:

  • 非常感谢,非常有帮助,一如既往。我会考虑切换到oo。不过,我很难理解你的第一个例子。可能interp 手册页中的这句话是至关重要的“源命令的命令过程接受其参数并将它们与别名的 targetCmd 和 args 合并以创建新的参数数组。”?
  • 我想过切换到oo,但我注意到我的“方法”更像是模块的函数而不是对象的方法,因为只有一个实例。所以定义一个类没有意义,除非定义“静态”类方法(如在 C++ 中)。您对 Tcl 中的高效模块机制有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 2017-09-07
  • 2020-10-10
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多