Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Tcl 在“array”集合中创建新命令时出现问题_Tcl - Fatal编程技术网

Tcl 在“array”集合中创建新命令时出现问题

Tcl 在“array”集合中创建新命令时出现问题,tcl,Tcl,我想创建一个方便的命令array values arrayName,作为array names命令的另一面 创建一个简单的过程非常简单: proc array_values {arrayName} { upvar 1 $arrayName ary set values {} foreach {name value} [array get ary] {lappend values $value} return $values } array set a {foo

我想创建一个方便的命令array values arrayName,作为array names命令的另一面

创建一个简单的过程非常简单:

proc array_values {arrayName} {
    upvar 1 $arrayName ary
    set values {}
    foreach {name value} [array get ary] {lappend values $value}
    return $values
}

array set a {foo bar baz qux}
puts [array_values a]           ;# => bar qux
但是,在::tcl::数组命名空间中创建命令时遇到困难:

首先是一些家庭作业:

数组是名称空间集合吗?对

% namespace ensemble exists array
1
名称空间是什么

% namespace ensemble configure array -namespace
::tcl::array
子命令是什么

% namespace ensemble configure array -subcommands
% namespace ensemble configure array -map
anymore ::tcl::array::anymore donesearch ::tcl::array::donesearch exists ::tcl::array::exists get ::tcl::array::get names ::tcl::array::names nextelement ::tcl::array::nextelement set ::tcl::array::set size ::tcl::array::size startsearch ::tcl::array::startsearch statistics ::tcl::array::statistics unset ::tcl::array::unset
好的,一切都好。让我们将数组_值proc添加到名称空间中

% namespace eval ::tcl::array {
    proc values {arrayName} {
        upvar 1 $arrayName ary
        set values {}
        foreach {name value} [array get ary] {lappend values $value}
        return $values
    }
}
% array set a {foo bar baz qux}
% puts [::tcl::array::values a]
这个错误是从哪里来的?我尝试将proc中的values变量重命名为其他名称,但它仍然发出变量is array error

注意:我可以将第一个过程添加到集合中:

% namespace ensemble config array -map [list values ::array_values {*}[namespace ensemble config array -map]]
% array values a
bar qux
但是my::tcl::array::values proc有什么问题?

您的set values{}命令在::tcl::array命名空间中执行,因此它运行::tcl::array::set命令。换句话说,它相当于数组集值{}。因此,它使值成为一个没有成员的数组。然后lappend values$value命令失败,因为此时值是一个数组

解决方案应该是使用::set values{}

或者,您可以使用以下方法完全避免该问题:

proc array_values {arrayName} {
    upvar 1 $arrayName ary
    return [lmap {name value} [get ary] {string cat $value}]
}
set values{}命令在::tcl::array命名空间中执行,因此它运行::tcl::array::set命令。换句话说,它相当于数组集值{}。因此,它使值成为一个没有成员的数组。然后lappend values$value命令失败,因为此时值是一个数组

解决方案应该是使用::set values{}

或者,您可以使用以下方法完全避免该问题:

proc array_values {arrayName} {
    upvar 1 $arrayName ary
    return [lmap {name value} [get ary] {string cat $value}]
}

我想补充一点,鉴于可能存在冲突的集成命令是一个移动目标,修补集成可能会在任何地方发生,我看到核心开发人员在::tcl::array::命名空间之外保留额外的集成命令:

proc arrayValues {arrayName} {
    upvar 1 $arrayName ary
    set values {}
    foreach {name value} [array get ary] {lappend values $value}
    return $values
}

# implant "arrayValues" into [array] ensemble as "values"
namespace ensemble configure ::array -map \
    [dict replace [namespace ensemble configure ::array -map] \
     values [namespace which arrayValues]]

这样,您就不必担心意外的解决冲突,不管这在Tcl中意味着什么。

我想补充一点,考虑到可能存在冲突的集合命令是一个移动目标,修补集合可能会在任何地方发生,我见过核心开发人员在::tcl::array::命名空间之外保留额外的集成命令:

proc arrayValues {arrayName} {
    upvar 1 $arrayName ary
    set values {}
    foreach {name value} [array get ary] {lappend values $value}
    return $values
}

# implant "arrayValues" into [array] ensemble as "values"
namespace ensemble configure ::array -map \
    [dict replace [namespace ensemble configure ::array -map] \
     values [namespace which arrayValues]]

这样一来,您就不必担心意外的解决冲突,不管这在Tcl中意味着什么。

对于好奇的人来说,这就是我的结论:

$HOME/tcl/lib/monkeypatches/monkeypatches.tcl

# a set of useful additions to built-in ensembles

package provide monkeypatches 0.1

namespace eval ::monkeypatches {
    # https://wiki.tcl-lang.org/page/wrapping+commands
    proc append_subcommand {cmd subcmd procname} {
        set map [namespace ensemble configure $cmd -map]
        dict set map $subcmd [namespace which $procname]
        namespace ensemble configure $cmd -map $map
    }


    # array foreach
    # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
    #
    # example:
    #   array set A {foo bar baz qux}
    #   array foreach {key val} A {puts "name=$key, value=$val"}
    #
    proc array_foreach {vars arrayName body} {
        if {[llength $vars] != 2} {
            error {array foreach: "vars" must be a 2 element list}
        }
        lassign $vars keyVar valueVar

        # Using the complicated `upvar 1 $arrayName $arrayName` so that any
        # error messages propagate up with the user's array name
        upvar 1 $arrayName $arrayName \
                $keyVar    key \
                $valueVar  value

        set sid [array startsearch $arrayName]
        # If the array is modified while a search is ongoing, the searchID will
        # be invalidated: wrap the commands that use $sid in a try block.
        try {
            while {[array anymore $arrayName $sid]} {
                set key [array nextelement $arrayName $sid]
                set value [set "${arrayName}($key)"]
                uplevel 1 $body
            }
            array donesearch $arrayName $sid
        } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
            return -options $e "detected attempt to modify the array while iterating"
        }
        return
    }
    append_subcommand ::array foreach array_foreach


    # array values arrayName
    # https://stackoverflow.com/q/53379995/7552
    #
    # example:
    #   array set x {foo bar baz qux}
    #   array get x             ;# => foo bar baz qux
    #   array names x           ;# => foo baz
    #   array values x          ;# => bar qux
    #
    proc array_values {arrayName} {
        upvar 1 $arrayName ary
        set values [list]
        array foreach {name value} ary {lappend values $value}
        return $values
    }
    append_subcommand ::array values array_values


    # info formalargs procName
    # https://core.tcl.tk/tips/doc/trunk/tip/65.md
    #
    # example:
    #   proc test {one {two 2} {three {3 4 5}} args} {return}
    #   info args test          ;# => one two three args
    #   info formalargs test    ;# => one {two 2} {three {3 4 5}} args
    #
    proc info_formalargs {procname} {
        # [info args] throws an error if $procname is not a procedure.
        return [lmap arg [info args $procname] {
            set has_d [info default $procname $arg value]
            if {$has_d} then {list $arg $value} else {set arg}
        }]
    }
    append_subcommand ::info formalargs info_formalargs
}
及其关联的pkgIndex.tcl

和$HOME/.tclshc

set lib_dir [file join $env(HOME) tcl lib]
if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
unset lib_dir
package require monkeypatches

对于好奇的人来说,这就是我的结局:

$HOME/tcl/lib/monkeypatches/monkeypatches.tcl

# a set of useful additions to built-in ensembles

package provide monkeypatches 0.1

namespace eval ::monkeypatches {
    # https://wiki.tcl-lang.org/page/wrapping+commands
    proc append_subcommand {cmd subcmd procname} {
        set map [namespace ensemble configure $cmd -map]
        dict set map $subcmd [namespace which $procname]
        namespace ensemble configure $cmd -map $map
    }


    # array foreach
    # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
    #
    # example:
    #   array set A {foo bar baz qux}
    #   array foreach {key val} A {puts "name=$key, value=$val"}
    #
    proc array_foreach {vars arrayName body} {
        if {[llength $vars] != 2} {
            error {array foreach: "vars" must be a 2 element list}
        }
        lassign $vars keyVar valueVar

        # Using the complicated `upvar 1 $arrayName $arrayName` so that any
        # error messages propagate up with the user's array name
        upvar 1 $arrayName $arrayName \
                $keyVar    key \
                $valueVar  value

        set sid [array startsearch $arrayName]
        # If the array is modified while a search is ongoing, the searchID will
        # be invalidated: wrap the commands that use $sid in a try block.
        try {
            while {[array anymore $arrayName $sid]} {
                set key [array nextelement $arrayName $sid]
                set value [set "${arrayName}($key)"]
                uplevel 1 $body
            }
            array donesearch $arrayName $sid
        } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
            return -options $e "detected attempt to modify the array while iterating"
        }
        return
    }
    append_subcommand ::array foreach array_foreach


    # array values arrayName
    # https://stackoverflow.com/q/53379995/7552
    #
    # example:
    #   array set x {foo bar baz qux}
    #   array get x             ;# => foo bar baz qux
    #   array names x           ;# => foo baz
    #   array values x          ;# => bar qux
    #
    proc array_values {arrayName} {
        upvar 1 $arrayName ary
        set values [list]
        array foreach {name value} ary {lappend values $value}
        return $values
    }
    append_subcommand ::array values array_values


    # info formalargs procName
    # https://core.tcl.tk/tips/doc/trunk/tip/65.md
    #
    # example:
    #   proc test {one {two 2} {three {3 4 5}} args} {return}
    #   info args test          ;# => one two three args
    #   info formalargs test    ;# => one {two 2} {three {3 4 5}} args
    #
    proc info_formalargs {procname} {
        # [info args] throws an error if $procname is not a procedure.
        return [lmap arg [info args $procname] {
            set has_d [info default $procname $arg value]
            if {$has_d} then {list $arg $value} else {set arg}
        }]
    }
    append_subcommand ::info formalargs info_formalargs
}
及其关联的pkgIndex.tcl

和$HOME/.tclshc

set lib_dir [file join $env(HOME) tcl lib]
if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
unset lib_dir
package require monkeypatches

作为Schelte回答的后续:如果我是对的,foreach也必须是合格的,因为::tcl::array::foreach将在8.7中可用?另请参阅我的补充答案。为了结束这个循环,TP 421实现了array for-Correct,我被祖先关于相应的赏金的讨论弄糊涂了:作为Schelte答案的后续:也必须对foreach进行限定,因为::tcl::array::foreach将在8.7中可用,如果我是对的话?另请参阅我的补充答案。为了结束这个循环,TP 421实现了array for-Correct,我被祖先关于相应赏金的讨论弄糊涂了:我刚刚发现你已经整理好了anyways::array_值。我刚刚发现你已经整理好了anyways::array_值。