2010-02-26 42 views
6

我正在写一个proc来在输出文件中创建一个头文件。我怎样才能安全地处理可选参数

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

我已经结束了编码这是一个可选参数

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

,但想知道怎样才能达到使用ARGS相同

proc dump_header { test description args } 

这是很容易检查ARGS是一个空白参数($ args ==“”),但如果传递多个参数则不能很好地处理 - 而且我仍然需要负面检查。

+0

如果你的proc被超过3个参数调用,你想要做什么:dump_header mytest mydesc {One comment} somethingelse?把somethingelse作为另一种评论,以其他方式处理? – 2010-02-26 12:58:36

+0

将$ args与空字符串进行比较是错误的。参数是一个列表,而不是一个字符串。 – 2010-02-26 18:16:12

+0

好吧,它本身并没有错,因为它会创建一个字符串表示,但是如果您要将它作为列表反正 – 2010-03-01 11:29:26

回答

13

您的proc定义不正确(您会收到错误消息too many fields in argument specifier "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 
+0

谢谢,这可能是不必要的。 对于其他情况,我认为我更喜欢名称 - 值对......但在这种情况下,我想您的答案将转换为“处理所有您必须视为数组的情况”。这很好。 – itj 2010-03-01 13:39:13

5

我使用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

1

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

我一直在寻找工作的好听点是(类似格伦的最后一个例子)的方式也有类似的Python的kwargs(可选的键值对参数)的功能,以及东西:

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. 

一个潜在的不利因素(如我目前实现了它)是,如果用户通过未经批准的键值选项,没有错误。