如何安全地处理可选参数

发布于 2024-08-23 14:30:35 字数 336 浏览 4 评论 0原文

我正在编写一个过程来在输出文件中创建标头。

目前它需要一个可选参数,这是标题的可能注释。

我最终将其编码为单个可选参数

proc dump_header { test description {comment = ""}}

,但想知道如何使用 args 实现相同的效果

proc dump_header { test description args }

很容易检查 args 是否为单个空白参数($args ==“”),但无法应对好吧,如果传递多个参数 - 而且我无论如何都需要否定检查。

I am writing a proc to create a header in an output file.

Currently it needs to take an optional parameter, which is a possible comment for the header.

I have ended up coding this as a single optional parameter

proc dump_header { test description {comment = ""}}

but would like to know how I can achieve the same using args

proc dump_header { test description args }

It's quite easy to check for args being a single blank parameter ($args == ""), but doesn't cope well if passing multiple parameters - and I need the negative check anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

牵你手 2024-08-30 14:30:35

您的过程定义不正确(您会收到错误消息参数说明符“comment =”“”中的字段太多)。应该是:

proc dump_header { test description {comment ""}} {
    puts $comment
}

如果您想使用args,您可以检查它的llength

proc dump_header {test desc args} {
    switch -exact [llength $args] {
        0 {puts "no comment"}
        1 {puts "the comment is: $args"}
        default {
            puts "the comment is: [lindex $args 0]"
            puts "the other args are: [lrange $args 1 end]"
        }
    }
}

您可能还想在列表中传递名称-值对:

proc dump_header {test desc options} {
    # following will error if $options is an odd-length list
    array set opts $options

    if {[info exists opts(comment)]} {
        puts "the comment is: $opts(comment)"
    }
    puts "here are all the options given:"
    parray opts
}
dump_header "test" "description" {comment "a comment" arg1 foo arg2 bar}

有些人更喜欢组合args 和名称-值对(a la Tk)

proc dump_header {test desc args} {
    # following will error if $args is an odd-length list
    array set opts $args
    if {[info exists opts(-comment)]} {
        puts "the comment is: $opts(-comment)"
    }
    parray opts
}
dump_header "test" "description" -comment "a comment" -arg1 foo -arg2 bar

Your proc definition is incorrect (you'd get the error message too many fields in argument specifier "comment = """). Should be:

proc dump_header { test description {comment ""}} {
    puts $comment
}

If you want to use args, you could examine the llength of it:

proc dump_header {test desc args} {
    switch -exact [llength $args] {
        0 {puts "no comment"}
        1 {puts "the comment is: $args"}
        default {
            puts "the comment is: [lindex $args 0]"
            puts "the other args are: [lrange $args 1 end]"
        }
    }
}

You might also want to pass name-value pairs in a list:

proc dump_header {test desc options} {
    # following will error if $options is an odd-length list
    array set opts $options

    if {[info exists opts(comment)]} {
        puts "the comment is: $opts(comment)"
    }
    puts "here are all the options given:"
    parray opts
}
dump_header "test" "description" {comment "a comment" arg1 foo arg2 bar}

Some prefer a combination of args and name-value pairs (a la Tk)

proc dump_header {test desc args} {
    # following will error if $args is an odd-length list
    array set opts $args
    if {[info exists opts(-comment)]} {
        puts "the comment is: $opts(-comment)"
    }
    parray opts
}
dump_header "test" "description" -comment "a comment" -arg1 foo -arg2 bar
掩于岁月 2024-08-30 14:30:35

我使用 tcllibcmdline 库来进行选项解析。

这是 cmdline 文档中的示例:

set options {
    {a          "set the atime only"}
    {m          "set the mtime only"}
    {c          "do not create non-existent files"}
    {r.arg  ""  "use time from ref_file"}
    {t.arg  -1  "use specified time"}
}
set usage ": MyCommandName \[options] filename ...\noptions:"
array set params [::cmdline::getoptions argv $options $usage]

if {  $params(a) } { set set_atime "true" }
set has_t [expr {$params(t) != -1}]
set has_r [expr {[string length $params(r)] > 0}]
if {$has_t && $has_r} {
    return -code error "Cannot specify both -r and -t"
} elseif {$has_t} {
    ...
}

因此,在您的情况下,您只需使用 args 代替上面示例中的 argv 即可。

I use tcllib's cmdline library to do option parsing.

This is the example from cmdline documentation:

set options {
    {a          "set the atime only"}
    {m          "set the mtime only"}
    {c          "do not create non-existent files"}
    {r.arg  ""  "use time from ref_file"}
    {t.arg  -1  "use specified time"}
}
set usage ": MyCommandName \[options] filename ...\noptions:"
array set params [::cmdline::getoptions argv $options $usage]

if {  $params(a) } { set set_atime "true" }
set has_t [expr {$params(t) != -1}]
set has_r [expr {[string length $params(r)] > 0}]
if {$has_t && $has_r} {
    return -code error "Cannot specify both -r and -t"
} elseif {$has_t} {
    ...
}

So, in your case, you'd just use args in place of argv in the above example.

世界等同你 2024-08-30 14:30:35

应该明确指出,args 是 Tcl 中的一个特殊词,当在参数列表末尾使用时,它包含所有剩余参数的列表。如果没有给出 args,则不会产生错误(与任何其他变量名称不同,它被视为必需参数)。

我一直在寻找一种具有类似于 python 的 kwargs (可选键值对参数)的功能的方法,并且效果很好的方法是(类似于 Glenn 的最后一个示例):

proc my_proc {positional_required1 {positional_optional1 "a_string"} args} {
    # Two optional arguments can be given: "opt1" and "opt2"
    if {![string equal $args ""]} {
        # If one or more args is given, parse them or assign defaults.
        array set opts $args
        if {[info exists opts(opt1)]} { set opt1 $opts(opt1) } else { set opt1 0 } 
        if {[info exists opts(op2)]} { set opt2 $opts(opt2) } else { set opt2 -1 }
    } else {
        # If no args are given, assign default values. 
        set op1 0
        set op2 -1
    }   
    # DO STUFF HERE
}

调用:

my_proc "positional_required1_argument" 
# OR
my_proc "positional_required1_argument" "a_string"
# OR
my_proc "positional_required1_argument" "a_string" opt1 7
# OR
my_proc "positional_required1_argument" "a_string" opt1 7 opt2 50
# etc.

并且可以这样 潜在的缺点(正如我目前已经实现的那样)是,如果用户传递未经批准的键值选项,则不会出现错误。

It should be mentioned explicitly that args is a special word in Tcl that, when used at the end of the argument list, contains a list of all the remaining arguments. If no args are given, then no error is produced (unlike any other variable name, which would be considered a required argument).

I was looking for a way to have functionality similar to python's kwargs (optional key-value pair arguments), and something that works nicely is (similar to Glenn's last example):

proc my_proc {positional_required1 {positional_optional1 "a_string"} args} {
    # Two optional arguments can be given: "opt1" and "opt2"
    if {![string equal $args ""]} {
        # If one or more args is given, parse them or assign defaults.
        array set opts $args
        if {[info exists opts(opt1)]} { set opt1 $opts(opt1) } else { set opt1 0 } 
        if {[info exists opts(op2)]} { set opt2 $opts(opt2) } else { set opt2 -1 }
    } else {
        # If no args are given, assign default values. 
        set op1 0
        set op2 -1
    }   
    # DO STUFF HERE
}

And can be called like:

my_proc "positional_required1_argument" 
# OR
my_proc "positional_required1_argument" "a_string"
# OR
my_proc "positional_required1_argument" "a_string" opt1 7
# OR
my_proc "positional_required1_argument" "a_string" opt1 7 opt2 50
# etc.

A potential downside (as I've currently implemented it) is that if a user passes a non-approved key-value option, there is no error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文