我有以下代码(也位于https://play.golang.org/p/9MlhhUPZRog):

package main

import (
    "errors"
    "fmt"
    "os"
)

func main() {
    var pathError *os.PathError

    // Generate the error
    _, err := os.Open("I_DO_NOT_EXIST.TXT");

    // Print, everything is OK here
    fmt.Println(err);

    // Wrap the error multiple times
    err = fmt.Errorf("%w; another error", err)
    err = fmt.Errorf("%w; another error", err)

    // Is it path error?
    fmt.Println(err, " ---- is path error? ----> ", errors.Is(err, pathError))

    // !!! UNCOMMENT THE LINE BELOW TO SEE THE DIFFERENCE !!!
    // if errors.As(err, &pathError) {}

    // Is it path error now?
    fmt.Println(err, " ---- is path error? ----> ", errors.Is(err, pathError))

}

结果是:
open I_DO_NOT_EXIST.TXT: no such file or directory
open I_DO_NOT_EXIST.TXT: no such file or directory; another error; another error  ---- is path error? ---->  false
open I_DO_NOT_EXIST.TXT: no such file or directory; another error; another error  ---- is path error? ---->  false

这是有道理的。但是,如果我取消注释if errors.As...行,结果将完全不同:
open I_DO_NOT_EXIST.TXT: no such file or directory
open I_DO_NOT_EXIST.TXT: no such file or directory; another error; another error  ---- is path error? ---->  false
open I_DO_NOT_EXIST.TXT: no such file or directory; another error; another error  ---- is path error? ---->  true

最后一次检查时显示true

为什么errors.As突变了err变量?

最佳答案

根据文档:

当顺序解包其第一个参数时,寻找可以分配给其第二个参数的错误,该错误必须是一个指针。如果成功,它将执行分配并返回true。否则,它返回false。

因此,当您执行errors.As(err, &pathError)时,pathError将设置为err。

您可以通过以下代码进行验证:

package main

import (
    "errors"
    "fmt"
    "os"
)

func main() {
    var pathError *os.PathError

    // Generate the error
    _, err := os.Open("I_DO_NOT_EXIST.TXT");

    // Print, everything is OK here
    fmt.Println(err);

    //pathError is nil here
    fmt.Println(pathError)

    // Is it path error?
    fmt.Println(err, " ---- is path error? ----> ", errors.Is(err, pathError))
    fmt.Println()


    //pathError is set to err here
    if errors.As(err, &pathError) {}

    fmt.Println(err);

    //pathError as err here
    fmt.Println(pathError)

    // Is it path error?
    fmt.Println(err, " ---- is path error? ----> ", errors.Is(err, pathError))

}

07-27 13:42