golang type conversion not working as (I) expected
An error
is an interface with a single method Error() string
. See http://golang.org/pkg/builtin/#error
A flags.Error
has such a method, so it can be used as an error
.
Conversely, however, a flags.Error
is a struct, and there's no way to convert an arbitrary value to a struct.
What you can do is, and I think this is the answer to your question, is that if you've got a flags.Value
inside an error
, then you can cast the error
back to the underlying type. The syntax for that is e := err.(*flags.Error)
. This'll give you a value of type *flags.Error
(or panic, if the underlying type isn't *flags.Error
). You can avoid the panic in this case by using the comma-ok form, which is e, ok := err.(*flags.Error)
.
Concretely, you would write:
args, err := flags.Parse()
if err != nil {
if ferr, ok := err.(*flags.Error); ok {
// ... something using ferr
} else {
// ... deal with non-flags.Error case, if that's possible.
}
}
![Brad Peabody](https://lh3.googleusercontent.com/-sx37srgARV4/AAAAAAAAAAI/AAAAAAAAAhw/XUlBN6N5Y6E/photo.jpg?sz=256)
Comments
-
Brad Peabody almost 2 years
I'm using go-flags to parse command line options.
Per the go-flags docs:
... [if] either -h or --help was specified in the command line arguments, a help message will be automatically printed. Furthermore, the special error type ErrHelp is returned.
The method I'm calling is:
func (p *Parser) Parse() ([]string, error) {
I'm calling it with:
var opts struct { // ... } func main() { parser := flags.NewParser(&opts, flags.Default) args, err := parser.Parse()
A snippet from the file that defines ErrHelp looks like this:
type ErrorType uint const ( // Unknown or generic error ErrUnknown ErrorType = iota // Expected an argument but got none ErrExpectedArgument // ... // The error contains the builtin help message ErrHelp // ... ) // Error represents a parser error. The error returned from Parse is of this // type. The error contains both a Type and Message. type Error struct { // The type of error Type ErrorType // The error message Message string } // Get the errors error message. func (e *Error) Error() string { return e.Message } func newError(tp ErrorType, message string) *Error { return &Error{ Type: tp, Message: message, } }
So they have this custom "Error" type. And in the Parse() method above, internally, the error is getting created with a block of code like this:
help.ShowHelp = func() error { var b bytes.Buffer p.WriteHelp(&b) return newError(ErrHelp, b.String()) }
As you can see newError() returns "*Error" as it's type. But the anonymous function just above returns type "error" - so those types must be compatible.(?)
But now back to the original problem - I'm just trying to see if my "err" is an "Error" and has member "Type" equal to ErrHelp. So I try this:
if err != nil && flags.Error(err).Type == flags.ErrHelp {
Or even just this:
fmt.Printf("test:", flags.Error(err))
And either way the compiler gives me:
main.go:37: cannot convert err (type error) to type flags.Error
But does not state why that conversion can't be done. Any ideas?
(I don't get how "*Error" successfully converts to "error" in the anonymous function above, and I even more don't get why if that works then I can't convert it back the other way... I must be missing something really dumb here, but I'm not seeing what it is.)
-
Brad Peabody almost 11 yearsOk gotcha - thanks and that does work! I can't find in the docs what that syntax means... "err.(*flags.Error)" means "give me a pointer to err but with type flags.Error"? (I'm assuming like you said I can't convert directly to Error, but I can convert to an Error pointer - that would make sense.)