Roman Pushkin
Roman Pushkin

Reputation: 6079

Golang errors.As changes the state of an error?

I have the following code (also at 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))

}

Result is:

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

And it makes sense. However, if I uncomment the line if errors.As... the result is completely different:

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

It says true for the last check.

Why did errors.As mutated the err variable?

Upvotes: 0

Views: 6147

Answers (1)

simran-ahuja
simran-ahuja

Reputation: 165

As per the documentation:

As unwraps its first argument sequentially looking for an error that can be assigned to its second argument, which must be a pointer. If it succeeds, it performs the assignment and returns true. Otherwise, it returns false.

Thus, when you do errors.As(err, &pathError), pathError gets set to err.

You can verify it by this code:

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))

}

Upvotes: 9

Related Questions