doucheng9634 2014-06-28 09:37
浏览 12
已采纳

结构不能为零,但这正在编译中

I'm playing with Go Playground and find this code:

package main

import (
    "fmt"
    "time"
)

type MyError struct {
    When time.Time
    What string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}

func run() error {
    return &MyError{
        time.Now(),
        "it didn't work",
    }
}

func main() {
    if err := run(); err != nil {
        fmt.Println(err)
    }
}

So here I can see that *MyError implements error interface. However if I remove & in error func and return MyError instead, I receive compile time error: prog.go:19: cannot use MyError literal (type MyError) as type error in return argument: MyError does not implement error (Error method has pointer receiver). OK I can understand that, so I can make the function Error like this and this will compile and run successfully:

func (e MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}

func run() error {
    return MyError{
        time.Now(),
        "it didn't work",
    }
}

Then I see in main func that there is check if err is nil so if I understand correctly it is perfectly possible func error to return nil in some situations. So it is possible for MyError struct to take nil values. But then if I try to compile this:

import (
    "fmt"
    "time"
)

type MyError struct {
    When time.Time
    What string
}

func (e MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}

func run() error {
    return nil
    return MyError{
        time.Now(),
        "it didn't work",
    }
}

func main() {
    var err2 MyError = nil

    fmt.Println(err2)
    if err := run(); err != nil {
        fmt.Println(err)
    }
}

go compiler said that: prog.go:27: cannot use nil as type MyError in assignment [process exited with non-zero status]

Why in the upper case the compilation is successful and in this case the compilation fails? Is it possible for structs to be nil (I guess not, but then why run func compiles?)

  • 写回答

2条回答 默认 最新

  • douchanxiu5636 2014-06-28 09:49
    关注

    In the first example, *MyError implemented the error interface. As you can see, it's a pointer, and a pointer can have the nil value.

    var err *MyError
    err == nil // true
    
    var err *MyError = new(MyError)
    err == nil // false
    

    But in the second example, it is MyError which implements the error interface, and that is not a pointer any more.

    var err MyError
    err == MyError{} // true
    &err == nil // false
    err == nil // Compilation error
    

    It is the adress of err this time that can be nil, not the variable itself.


    As a comparison, consider the int type: var i int. You can check i == 0 for instance, but it would be an error to test if i == nil, because nil is not an integer (exactly as it was not a MyError before). But you could still check if the address of i is nil: &i == nil.


    EDIT

    Be aware that this function will always return nil (the execution stops right after the first return):

    func run() error {
        return nil
        return MyError{
            time.Now(),
            "it didn't work",
        }
    }
    

    It compiles because the prototype of the function tells that it must return an error, and indeed, nil is a valid error, and so is a MyError{} variable. But try to change this function prototype to this one:

    func run() MyError
    

    You will see that the compilation fails, because nil is not a MyError variable, even though it is a valid value for the error type.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 thinkphp6配合social login单点登录问题
  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch