我试着在另一个问题中问这个问题,但做得很差。第一块代码来自David Flanagan书中的JS示例。该示例的要点是,在getCounter()
返回后,方法next
和reset
共享的作用域是私有的,代码的其余部分不再可以访问。换句话说,除非通过这两种方法,否则不能更改n
。
第二块代码来自John Ousterhout关于Tcl的书中的一个例子,它引用了名称空间。我并不是在暗示他的例子与范围有关;我只是想知道是否可以这样做。它的工作原理与JS示例大致相同,只是让过程更改num
的值,但范围不是私有的。外部代码可以简单地set counter::num 10
,这在JS示例中是无法做到的。至少似乎没有办法访问n
。
我的问题是,除了使用OOP Tcl库之外,是否还有一种方法可以像JS示例中那样使Tcl中的作用域私有?
谢谢。
"use strict";
function getCounter () {
var n = 0;
return {
next: function () { return ++n; },
reset: function () { n = 0; }
};
}
var counter = getCounter();
console.log(counter.next()); // 1
console.log(counter.next()); // 2
console.log(counter.next()); // 3
counter.reset();
console.log(counter.next()); // 1
console.log(counter.next()); // 2
console.log(counter.next()); // 3
// Cannot access n from here because
// private scope.
namespace eval counter {
variable num 0
proc next {} {
variable num
return [incr num]
}
proc reset {} {
variable num
set num 0
}
}
chan puts [counter::next]; # 1
chan puts [counter::next]; # 2
chan puts [counter::next]; # 3
counter::reset
chan puts [counter::next]; # 1
chan puts [counter::next]; # 2
chan puts [counter::next]; # 3
set counter::num 10
chan puts [counter::next]; # 11
chan puts [counter::next]; # 12
不是真的,主要是因为tcl并没有真正的引用/指针(所有东西都是一个值)。你引用的js机制是闭包,如果没有引用(多个变量引用同一个对象),就不可能有闭包。看见https://wiki.tcl-lang.org/page/Closures进行长时间的讨论。
但tcl确实有一种大多数其他语言都没有的机制,可以用来限制访问——只是它不会是你正在考虑的那种逻辑。Tcl具有interp功能,能够从Tcl本身创建、删除、操作和执行整个Tcl解释器。tcl中有一个概念叫做安全解释器(很多关于这个主题的文章)。一个安全的解释器基本上是一个tcl解释器,您可以在其中删除所有不希望脚本访问的功能。
这是可能的,因为Tcl允许您重新定义或重命名函数/procs,包括内置函数。例如,如果您不希望脚本访问网络,您可以简单地删除socket
命令。在您的情况下,您可以创建一个没有set
函数的interp,从而无法创建或修改变量。当然,你自己也需要set
函数来运行你自己的代码,所以你不必删除它,而是可以将其重命名为第三方猜不到的东西,比如笑脸表情符号(-这是一个完全合法的proc名称!)或一行3个NUL字符(