将Namespace转换为单个proc

时间:2013-09-13 22:32:55

标签: oop tcl

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

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
}

我认为关于命名空间可能会遗漏一些东西。我试过阅读documentation,但我不太明白它们是如何工作的。

2 个答案:

答案 0 :(得分: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

这简化了一些事情,实际上你可以考虑将绘图和数据管理耦合得比我上面的更接近;它只是表明你能做什么。 (我发现当我使用对象时它会使事情变得更简单,因为它们比普通命名空间对它们有更强的生命周期感。)

答案 1 :(得分: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

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