The flag.Var function in Go is used to define a custom flag that implements the flag.Value interface. This allows you to create flags with types other than the standard types provided by the flag package (like int, string, etc.). By implementing the flag.Value interface, you can define how your custom flag parses and stores its value.
Syntax
func Var(value flag.Value, name string, usage string)
Parameters:
value: A variable that implements theflag.Valueinterface, which defines methods for setting and getting the flag’s value.name: The name of the command-line flag (e.g.,-flagname).usage: A short description of the flag’s purpose, which is shown in the help output.
Returns:
- The
flag.Varfunction does not return any value.
Example Usage
Basic Example: Creating a Custom Flag
This example demonstrates how to use flag.Var to define a custom flag that stores a comma-separated list of strings.
Step 1: Define a Type that Implements flag.Value
First, you need to define a type that implements the flag.Value interface. This interface requires implementing two methods: Set(string) error and String() string.
package main
import (
"flag"
"fmt"
"strings"
)
// Define a custom type
type StringList []string
// Implement the Set method for the custom type
func (s *StringList) Set(value string) error {
*s = strings.Split(value, ",")
return nil
}
// Implement the String method for the custom type
func (s *StringList) String() string {
return strings.Join(*s, ",")
}
Step 2: Use flag.Var to Define the Custom Flag
Now, you can use flag.Var to define the custom flag.
package main
import (
"flag"
"fmt"
)
func main() {
// Declare a variable of the custom type
var list StringList
// Use flag.Var to define the flag with the custom type
flag.Var(&list, "list", "comma-separated list of strings")
// Parse the command-line flags
flag.Parse()
// Use the flag value
fmt.Printf("List: %v\n", list)
}
Output:
If the program is run with go run main.go -list=apple,banana,cherry:
List: [apple banana cherry]
If the program is run without any flags:
List: []
Explanation:
- The
StringListtype is defined to store a list of strings, implementing theSetandStringmethods required by theflag.Valueinterface. - The
flag.Varfunction is used to define the-listflag, which allows the user to input a comma-separated list of strings. - The
flag.Parsefunction processes the command-line flags, and the program outputs the parsed list.
Custom Flag with Complex Types
You can also use flag.Var with more complex types, such as a custom struct that holds multiple fields.
Example
package main
import (
"flag"
"fmt"
"strconv"
"strings"
)
// Define a custom type for an IP address and port
type Address struct {
IP string
Port int
}
// Implement the Set method for the Address type
func (a *Address) Set(value string) error {
parts := strings.Split(value, ":")
if len(parts) != 2 {
return fmt.Errorf("invalid address format")
}
a.IP = parts[0]
port, err := strconv.Atoi(parts[1])
if err != nil {
return err
}
a.Port = port
return nil
}
// Implement the String method for the Address type
func (a *Address) String() string {
return fmt.Sprintf("%s:%d", a.IP, a.Port)
}
func main() {
// Declare a variable of the custom type
var addr Address
// Use flag.Var to define the flag with the custom type
flag.Var(&addr, "address", "IP address and port (e.g., 127.0.0.1:8080)")
// Parse the command-line flags
flag.Parse()
// Use the flag value
fmt.Printf("Address: %v\n", addr)
}
Output:
If the program is run with go run main.go -address=192.168.1.1:8080:
Address: 192.168.1.1:8080
If the program is run without any flags:
Address: :0
Explanation:
- The
Addresstype is defined to store an IP address and port, implementing theSetandStringmethods required by theflag.Valueinterface. - The
flag.Varfunction is used to define the-addressflag, which allows the user to input an IP address and port in the formatIP:Port. - The
flag.Parsefunction processes the command-line flags, and the program outputs the parsed address.
Handling Invalid Input
If the input provided to the flag does not match the expected format, the Set method should return an error. This will cause the program to exit and display an appropriate error message.
Example
package main
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// Define a custom type for an IP address and port
type Address struct {
IP string
Port int
}
// Implement the Set method for the Address type
func (a *Address) Set(value string) error {
parts := strings.Split(value, ":")
if len(parts) != 2 {
return fmt.Errorf("invalid address format: %s", value)
}
a.IP = parts[0]
port, err := strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("invalid port number: %s", parts[1])
}
a.Port = port
return nil
}
// Implement the String method for the Address type
func (a *Address) String() string {
return fmt.Sprintf("%s:%d", a.IP, a.Port)
}
func main() {
// Declare a variable of the custom type
var addr Address
// Use flag.Var to define the flag with the custom type
flag.Var(&addr, "address", "IP address and port (e.g., 127.0.0.1:8080)")
// Parse the command-line flags
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
// Use the flag value
fmt.Printf("Address: %v\n", addr)
}
Output:
If the program is run with an invalid format, such as go run main.go -address=invalid_address:
invalid value "invalid_address" for flag -address: invalid address format: invalid_address
Usage of /tmp/go-build123456789/b001/exe/main:
-address IP address and port (e.g., 127.0.0.1:8080)
exit status 1
Explanation:
- The
Setmethod checks the format of the input string and returns an error if the format is invalid. - If an error is returned by the
Setmethod, the program prints an error message and exits.
Conclusion
The flag.Var function in Go is used that allows you to create custom command-line flags for more complex types. By implementing the flag.Value interface, you can control how your custom flags are parsed and stored, making it possible to handle a wide range of input formats and data structures. This flexibility is particularly useful when building command-line applications that require more sophisticated argument parsing beyond the standard types provided by the flag package.