golang 类型转换不能按(我)预期的那样工作

Posted

技术标签:

【中文标题】golang 类型转换不能按(我)预期的那样工作【英文标题】:golang type conversion not working as (I) expected 【发布时间】:2013-08-27 06:50:22 【问题描述】:

我正在使用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 的 sn-p 如下所示:

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,
    

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

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

如您所见,newError() 返回“*Error”作为它的类型。但是上面的匿名函数返回类型“错误” - 所以这些类型必须兼容。(?)

但是现在回到最初的问题——我只是想看看我的“err”是否是一个“Error”并且成员“Type”是否等于 ErrHelp。所以我试试这个:

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

甚至只是这样:

fmt.Printf("test:", flags.Error(err))

无论哪种方式编译器都会给我:

main.go:37: cannot convert err (type error) to type flags.Error

但没有说明为什么不能进行转换。有什么想法吗?

(我不明白“*Error”是如何在上面的匿名函数中成功转换为“error”的,我更不明白为什么如果这样有效,那么我不能以另一种方式将其转换回来。 ..我一定错过了一些非常愚蠢的东西,但我没有看到它是什么。)

【问题讨论】:

【参考方案1】:

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

flags.Error 有这样的方法,所以可以作为error 使用。

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

可以做的是,我认为这是您问题的答案,如果您在error 中有一个flags.Value,那么您可以投射@ 987654329@ 回到底层类型。其语法为e := err.(*flags.Error)。这将为您提供*flags.Error 类型的值(或恐慌,如果基础类型不是*flags.Error)。在这种情况下,您可以使用逗号-ok 形式来避免恐慌,即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.
     
  

【讨论】:

好的,谢谢,这确实有效!我在文档中找不到该语法的含义...“err.(*flags.Error)”的意思是“给我一个指向 err 但类型为 flags.Error 的指针”? (我假设就像你说的我不能直接转换为 Error,但我可以转换为 Error 指针 - 这是有道理的。)

以上是关于golang 类型转换不能按(我)预期的那样工作的主要内容,如果未能解决你的问题,请参考以下文章

ComboBox DataSource 没有按我预期的那样工作[重复]

文件大小转换字节到 kb/mb/gb 函数不能按预期工作

带有 LocalDateTime 的 SpringBoot2 @DateTimeFormat 注释不能按我的预期工作

Golang HTTP Timeout 测试,没有按预期超时

golang ctx取消没有按预期工作

Django REST 权限类不能在 OR 中一起工作,而是按预期独立工作