Returning an error

In the last section, we wired up our user's arguments and passed it to our sum function. What happens if the user passes in a string value? What about a decimal?

# ./math sum 1 2 3 foo
6

# ./math sum 1 2 3 2.1
6

Our sum function isn't even batting an eye! It's just completely ignoring the string foo, and the decimal 2.1 value. That's because we ignored our error when we converted from []string to []int. Take a look at the line with block [1].:

// ...
    for i, v := range args {
            vAsInt, _ := strconv.Atoi(v)       // [1]
            values[i] = vAsInt
    }
// ...

Here we use the strconv module's Atoi function to convert the string value to an integer, and then we disregard the second return value which is an error. Ideally, we want to return that error, but we have a bit of a problem. Our sumCommandRun function doesn't return an error, but that's easy enough to fix:

func sumCommandRun(cmd *cobra.Command, args []string) error { // return an error
	// convert args which is []string to []int
	values := make([]int, len(args))
	for i, v := range args {
		vAsInt, err := strconv.Atoi(v)
        if err != nil {     // new code!
            return fmt.Errorf("you provide a value that was not an integer: %s", v)
        }
		values[i] = vAsInt
	}

	fmt.Println(sum(values...))

    return nil // all went well, return no error
}

As soon as we reconfigure our function, our sumCmd should show an error that reads:

cannot use sumCommandRun
    (value of type func(cmd *cobra.Command, args []string) error)
as
    func(cmd *cobra.Command, args []string) value in struct literal

This is because the cobra.Command.Run key enforces a specific function signature that matched what we were using previously. If we want to return an error in our function, we can do so by instead assigning our function to RunE. Its function signature is identical, but it returns an error.

//...
var sumCmd = &cobra.Command{
	Use:   "sum",
    //...

    //Run: sumCommandRun        // this is what we used before
	RunE: sumCommandRunE,        // and replaced it with this.
}
/...

By convention, I've also renamed our sumCommandRun to sumCommandRunE to make it match the command struct key to which it applies.

The project should be happy, and you should see an error returned when the user provides non-integer values.

$ go build -o math . && ./math sum 1 2 3 foo
Error: you provide a value that was not an integer: foo
Usage:
  math sum [flags]

Flags:
  -h, --help   help for sum

And since we've returned an error, the help output is provided to the user.