Reputation: 57471
I was reading the source code for the Output()
method of the Cmd
type in Go's exec
module (https://golang.org/pkg/os/exec/#Cmd.Output):
// Output runs the command and returns its standard output.
// Any returned error will usually be of type *ExitError.
// If c.Stderr was nil, Output populates ExitError.Stderr.
func (c *Cmd) Output() ([]byte, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
var stdout bytes.Buffer
c.Stdout = &stdout
captureErr := c.Stderr == nil
if captureErr {
c.Stderr = &prefixSuffixSaver{N: 32 << 10}
}
err := c.Run()
if err != nil && captureErr {
if ee, ok := err.(*ExitError); ok {
ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
}
}
return stdout.Bytes(), err
}
I'm struggling a bit to understand this part:
if ee, ok := err.(*ExitError); ok {
ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
}
As I understand it, the ee
pointer will no longer be in scope at the end of the if
block, and since the body of the if
block is just setting the Stderr
field of this instance, the only way this could be useful is through a side effect (like actually writing the prettified error). I don't immediately grasp how this is happening, though.
What does this bit of code do, essentially?
Upvotes: 0
Views: 595
Reputation: 51587
if ee, ok := err.(*ExitError); ok {
If err
is of type *ExitError
, then ee
will be a pointer to the ExitError stored in err
. So, even though ee
will go out of scope, the *ExitError
will still be there, pointed to by err
, and any changes made to it will stick.
Upvotes: 3