英文:
flag package in Go - do I have to always set default value?
问题
在Go语言的flag包中,是否可以不设置默认值?例如,在flag包中,你可以写出以下代码:
filename := flag.String("file", "test.csv", "要处理的文件名")
在上述代码中,我不想强制设置默认值,也就是在这种情况下是test.csv
,而是希望用户始终指定自己的文件名,如果没有指定,则希望引发错误并退出程序。
我想到的一种方法是,在执行flag.Parse()
之后,首先检查filename
的值,如果该值是test.csv
,则让程序以适当的错误消息退出。然而,如果可以避免编写这种多余的代码,我不想这样做,而且即使不能避免,我也想听听在这里处理这个问题的更好方法。
顺便说一下,你可以在Python的argparse
模块中执行这种操作 - 我只是想在Go语言中实现类似的功能,如果可能的话...
另外,我可以在flag包中同时实现短参数和长参数(也就是-f
和-file
参数)吗?
谢谢。
英文:
Is it possible not to set default value in flag package in Go? For example, in flag package you can write out the following line:
filename := flag.String("file", "test.csv", "Filename to cope with")
In the above code, I don't want to necessarily set default value, which is test.csv
in this case, and instead always make users specify their own filename, and if it's not specified then I want to cause an error and exit the program.
One of the way I came up with is that I first check the value of filename
after doing flag.Parse()
, and if that value is test.csv
then I have the program exits with the appropriate error message. However, I don't want to write such redundant code if it can be evaded - and even if it can't, I'd like to hear any better way to cope with the issue here.
You can do those kind of operations in Python's argparse
module by the way - I just want to implement the similar thing if I can...
Also, can I implement both short and long arguments (in other words both -f
and -file
argument?) in flag package?
Thanks.
答案1
得分: 24
我认为,设计标志值时,以暗示“不存在”为零值的方式是惯用法。例如:
optFile := flag.String("file", "", "源文件")
flag.Parse()
fn := *optFile
if fn == "" {
fn = "/dev/stdin"
}
f, err := os.Open(fn)
...
至于第二个问题:据我所知,标志包在设计上不区分“-flag”和“--flag”。也就是说,你可以在标志集中同时拥有“-f”和“--file”,并且在“f”和“file”之前可以写任意版本的“-”或“--”。然而,如果考虑另一个定义的标志“-g”,标志包将不会将“-gf foo”识别为“-g -f foo”的等价形式。
英文:
I think it's idiomatic to design your flag values in such a way which implies "not present" when equal to the zero value of their respective types. For example:
optFile := flag.String("file", "", "Source file")
flag.Parse()
fn := *optFile
if fn == "" {
fn = "/dev/stdin"
}
f, err := os.Open(fn)
...
Ad the 2nd question: IINM, the flag package by design doesn't distinguish between -flag
and --flag
. IOW, you can have both -f
and --file
in your flag set and write any version of -
or --
before both f
and file
. However, considering another defined flag -g
, the flag package will not recognize -gf foo
as being equvalent of -g -f foo
.
答案2
得分: 9
当我有一个不能有默认值的标志时,我经常使用值REQUIRED
或类似的值。我发现这样可以使--help
更容易阅读。
至于为什么没有内置这个功能,我猜想可能是因为它被认为不够重要。默认值无法满足每个需求。然而,--help
标志是类似的;它不能满足每个需求,但大多数情况下足够好用。
这并不是说必需的标志是一个坏主意。如果你足够热衷,一个flagutil
包可能会很不错。包装当前的flag
API,使Parse
返回描述缺失标志的错误,并添加RequiredInt
和RequiredIntVar
等函数。如果它被证明有用/受欢迎,它可以与官方的flag
包合并。
英文:
When I have a flag that cannot have a default value I often use the value REQUIRED
or something similar. I find this makes the --help
easier to read.
As for why it wasn't baked in, I suspect it just wasn't considered important enough. The default wouldn't fit every need. However, the --help
flag is similar; it doesn't fit every need, but it's good enough most of the time.
That's not to say the required flags are a bad idea. If you're passionate enough a flagutil
package could be nice. Wrap the current flag
api, make Parse
return an error that describes the missing flag and add a RequiredInt
and RequiredIntVar
etc. If it turns out to be useful / popular it could be merged with the official flag
package.
答案3
得分: 0
这是我实现命令参数解析器的方式。
由于已经有很多类似的项目,我决定不添加更多选择,除非有强烈的动力。
以下是一个示例,展示了如何使用它,可能会给某些人带来灵感,或者某些人可能会感兴趣。
// minarg.go
package main
import (
"fmt"
"self/argp"
)
func main() {
p := argp.New(nil)
p.Bool("continue", nil, "-v", "-g")
f := func(m, arg string) {
switch m {
case "__init__":
case "__defer__":
p.Set("server", p.GetString("-s") + ":" + p.GetString("-p"))
default:
arg, _ := p.Shift()
p.Set(m, arg)
}
}
p.Mode(f, "__init__", "__defer__", "-s", "-p", "-nstat", "-n")
p.Default("-s", "127.0.0.1", "-p", "1080", "-nstat", "100", "-n", "5")
p.Env("-s", "SERVER", "-p", "PORT")
p.Parse()
fmt.Println(p.Vars)
}
输出结果为:
$ go run minarg.go
&map[-g:{false continue <nil>} -n:5 -nstat:100 -p:1080 -s:127.0.0.1 -v:{false continue <nil>} server:127.0.0.1:1080]
$ export PORT=80
$ go run minarg.go -s 0.0.0.0 -n 3 -vg
&map[-g:{true continue <nil>} -n:3 -nstat:100 -p:80 -s:0.0.0.0 -v:{true continue <nil>} server:0.0.0.0:80]
英文:
This is how I implemented command argument parser.
Since there are already plenty of similar projects, I decided not to add more choices without strong impetus.
Here is an example of how it can be used, which might inspired somebody, or someone might be interested.
# minarg.go
package main
import (
"fmt"
"self/argp"
)
func main() {
p := argp.New(nil)
p.Bool("continue",nil,"-v","-g")
f := func(m, arg string) {
switch m {
case "__init__":
case "__defer__":
p.Set("server", p.GetString("-s") + ":" + p.GetString("-p"))
default:
arg, _ := p.Shift()
p.Set(m, arg)
}
}
p.Mode(f,"__init__","__defer__","-s","-p","-nstat","-n")
p.Default("-s","127.0.0.1", "-p","1080", "-nstat","100", "-n","5")
p.Env("-s","SERVER", "-p","PORT")
p.Parse()
fmt.Println(p.Vars)
}
The output is
$ go run minarg.go
&map[-g:{false continue <nil>} -n:5 -nstat:100 -p:1080 -s:127.0.0.1 -v:{false continue <nil>} server:127.0.0.1:1080]
$ export PORT=80
$ go run minarg.go -s 0.0.0.0 -n 3 -vg
&map[-g:{true continue <nil>} -n:3 -nstat:100 -p:80 -s:0.0.0.0 -v:{true continue <nil>} server:0.0.0.0:80]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论