flag package in Go - do I have to always set default value?
Asked Answered
H

3

28

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.

Hypothalamus answered 25/8, 2013 at 13:47 Comment(1)
Please only ask one question per question.Aleutian
L
25

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.

Lapides answered 25/8, 2013 at 14:25 Comment(2)
Does the flag package provide a way to check whether a flag is set? I'm not talking about default values, or no values. I mean, whether a flag is present in the command line.Outport
@Kiril, you can use the Bool option. If its value is true, then the flag is set. ExampleOxidase
L
9

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.

Laurielaurier answered 25/8, 2013 at 17:45 Comment(1)
Thanks for the flagutil package. I'll give it a shot.Hypothalamus
A
0

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]
Angele answered 26/5, 2022 at 13:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.