1

我有一组 procs 和一个命名空间,如下所示:

namespace eval ::_API { 
    if {[info exists ::_API::API_ids]} { 
        catch {API erase -ids [array names ::_API::API_ids]} 
    } 
    catch {unset API_ids} 
    array set API_ids "" 
} 

proc ::_API::erase { } { 
    foreach id [array names ::_API::API_ids] { 
        if {::_API::API_ids($id) == 0} { 
            continue 
        } 
        if {[catch {API -id $id -redraw 0}] != 0} { 
            set ::_API::API_ids($id) 0 
        } 
    } 
    Redraw ;# I'm not concerned about this part
            # and I'm fairly certain it can be ignored
} 

proc erase { } { 
    ::_API ::erase 
} 

::_API::API_ids是一个包含点的数组(例如0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)。该脚本所做的是擦除表格中的点。

我想将命名空间::_API转换为 proc,以便我可以使用 GUI 按钮来调用 proc。它目前直接在其他一些脚本(映射表中的点)之后,我只想在需要时删除它们;即何时按下按钮。

我已经尝试过::_API::erase直接运行,但它不起作用:

proc ::_API::erase { } {
foreach id [array names ::_API::API_ids] {
    if {::_API::API_ids($id) == 0} {
        continue
    }
    if {[catch {API -id $id -redraw 0}] != 0} {
        set ::_API::API_ids($id) 0
    }
}
Redraw
}

我认为命名空间可能缺少一些东西。我尝试阅读文档,但我不太了解它们是如何工作的。

4

2 回答 2

2

您真正必须做的第一件事是使用variable声明变量。由于一些相当丑陋的原因,不这样做可能会导致可变分辨率的“有趣”,从而使事情以您不期望的方式发生:

namespace eval ::_API {
    variable API_ids;   ##### <<<<<<< THIS <<<<<<< #####
    if {[info exists ::_API::API_ids]} { 
        catch {API erase -ids [array names ::_API::API_ids]} 
    } 
    catch {unset API_ids} 
    array set API_ids "" 
} 

其次,您可能应该真正考虑使用真正的 OO,而不是试图伪造它。例如,使用 TclOO,您将编写如下内容:

oo::class create APIClass {
    variable ids
    constructor {} {
        array set ids {}
    }
    method erase {} {
        foreach id [array names ids] {
            if {$ids($id) == 0} continue
            if {[catch {
                API -id $id -redraw 0
            }]} {
                set ids($id) 0
            }
        }
        Redraw
    }
    # Allow something to reference the ids variable from the outside world
    method reference {} {
        return [my varname ids]
    }
}
APIClass create _API
# [_API erase] will call the erase method on the _API object

这大大简化了事情,事实上,您可以从耦合绘图和数据管理的角度来考虑,这比我上面所做的要紧密得多;它只是表明你可以做什么。(我发现当我使用对象时它让事情变得更简单,因为它们比普通的命名空间对它们有更强烈的生命周期意识。)

于 2013-09-15T16:26:32.417 回答
1

您的意思是将命名空间初始化代码转换为过程。下面的例子应该实现这一点。

namespace eval ::_API {
}
proc ::_API::initialize {} {
    variable API_ids
    if {[info exists API_ids]} {
        catch {API erase -ids [array names API_ids]}
        unset API_ids
    }
    array set API_ids ""
}

... more definitions ...

::_API::initialize

我们首先声明命名空间。然后在一个过程中复制原始代码。由于取消设置不存在的变量没有意义,我们将取消设置移动到仅在变量存在时运行的块中。在命名空间定义的最后,通过调用其初始化函数来初始化命名空间。

于 2013-09-14T09:04:19.197 回答