Golang类型转换不像我预期的那样工作

10

我正在使用go-flags来解析命令行选项。

根据go-flags文档:

...如果在命令行参数中指定了-h或--help,则会自动打印帮助信息。此外,还将返回特殊的错误类型ErrHelp。

我正在调用的方法是:

func (p *Parser) Parse() ([]string, error) {

我正在使用以下方式进行调用:

var opts struct {
    // ...
}

func main() {

    parser := flags.NewParser(&opts, flags.Default)

    args, err := parser.Parse()

定义 ErrHelp 的文件片段如下所示:

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,
    }
}

所以他们有一个名为“Error”的自定义类型。在上面的Parse()方法中,内部使用以下代码块创建错误:

    help.ShowHelp = func() error {
        var b bytes.Buffer
        p.WriteHelp(&b)
        return newError(ErrHelp, b.String())
    }

正如您所看到的,newError()返回类型为"*Error"。但是上面的匿名函数返回类型为"error",因此这两种类型必须兼容。(?)

现在回到最初的问题——我只是想确定我的"err"是否为"Error",并且其成员"Type"是否等于ErrHelp。所以我尝试了这个:

if err != nil && flags.Error(err).Type == flags.ErrHelp {

甚至只需要这个:
fmt.Printf("test:", flags.Error(err))

无论哪种方式,编译器都会给我以下错误提示信息:
main.go:37: 无法将err(类型为error)转换为flags.Error类型
但是它没有说明为什么不能进行此转换。有任何想法吗?
(我不明白为什么“* Error”在上面的匿名函数中成功地转换为“error”,更不明白为什么如果那样运行,则无法将其转换回另一种方式……我一定错过了某些非常愚蠢的东西,但我没有看到它是什么。)
1个回答

21

错误是一个具有单个方法Error() string的接口。参见http://golang.org/pkg/builtin/#error

flags.Error具有这样的方法,因此它可以用作error

然而,相反地,flags.Error是一个结构体,无法将任意值转换为结构体。

你可以做的是,如果你有一个在error中的flags.Value,那么你可以将error强制转换回基础类型。其语法为e := err.(*flags.Error)。这将给你一个类型为*flags.Error的值(如果底层类型不是*flags.Error,则会出现panic)。在这种情况下,你可以使用逗号-ok形式来避免panic,即e,ok := err.(*flags.Error)

具体来说,你可以写:

  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.
     }
  }

1
好的,明白了 - 谢谢,它确实有效!我在文档中找不到那个语法的含义... "err.(*flags.Error)" 是指“给我一个指向 err 的指针,但类型为 flags.Error”吗?(我假设像你说的那样,我不能直接转换为 Error,但我可以转换为 Error 指针 - 这是有道理的。) - Brad Peabody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接