Let's first look at a simple example. We customize an error to put multiple errors together to output:
type CustomError struct {
errors []string
}func (c *CustomError) Add(err string) {
= append(, err)
}func (c *CustomError) Error() string {
return (, ";")
}
Because it's doneError() string
method, so it implements the error interface.
Now we want to implement a function of adding courseware, but before adding, we need to verify the legality of the parameters, so we created a Validate method, which we might write like this:
package main import ( "errors" "fmt" "strings" ) type CustomError struct { errors []string } func (c *CustomError) Add(err error) { = append(, ()) } func (c *CustomError) Error() string { return (, ";") } type Courseware struct { Name string Code string } func (c *Courseware) Validate() error { var m *CustomError // 1 if == "" { // 2 m = &CustomError{} (("The courseware name cannot be empty")) } if == "" { // 3 if m == nil { m = &CustomError{} } (("Courseware number cannot be empty")) } return m // 4 } func main() { m := Courseware{ Name: "Multimedia Courseware", Code: "CW330", } if err := (); err != nil { ("valid err: ", err) } }
It seems like there is no problem at all:
- Define a pointer of type CustomError
- If Name is empty, initialize m and call Add method to add the error to
- If Code is empty, if m has not been initialized, initialize it first, call the Add method to add the error to
- Finally, the custom error is returned
But when we execute the above code, we will find that the result is not what we want:
go run valid err: <nil>
We found that we had actually come to the judgment of printing error, but the error printed was actually anil
。
In Go, we must know that the pointer receiver can be nil. Let's look at a simple example:
package main import ( "fmt" ) type Demo struct { } func (d *Demo) Print() string { return "demo" } func main() { var d *Demo (d) (()) }
go run <nil> demo
The Demo is initialized to nil, but this code works fine. Instructions nil pointer can also be used as a receiver.
In fact, the Print method above is equivalent to:
func Print(d *Demo) string { return "demo" }
Because passing nil pointer to a function is valid. So using nil pointer as a receiver is also effective.
Let's continue to go back to the custom error above.
m is initialized to the zero value of the pointer: nil. If all validations pass, the return statement returns the result not nil, but a nil pointer. Because the nil pointer is a valid receiver, converting the result to an error interface will not produce a nil value.
So although we return a nil pointer, it is not an nil interface when converted to an error interface (although it is a nil pointer, it is of *CustomError type and implements error).
To solve this problem, we just need to return the nil value directly, not the nil pointer:
package main import ( "errors" "fmt" "strings" ) type CustomError struct { errors []string } func (c *CustomError) Add(err error) { = append(, ()) } func (c *CustomError) Error() string { return (, ";") } type Courseware struct { Name string Code string } func (c *Courseware) Validate() error { var m *CustomError if == "" { m = &CustomError{} (("The courseware name cannot be empty")) } if == "" { if m == nil { m = &CustomError{} } (("Courseware number cannot be empty")) } // If the m pointer is nil here, return nil directly if m == nil { return nil } return m } func main() { m := Courseware{ Name: "Multimedia Courseware", Code: "CW330", } if err := (); err != nil { ("valid err: ", err) } }
Or we directly return an error of type *CustomError:
package main import ( "errors" "fmt" "strings" ) type CustomError struct { errors []string } func (c *CustomError) Add(err error) { = append(, ()) } func (c *CustomError) Error() string { return (, ";") } type Courseware struct { Name string Code string } // Return *CustomErrorfunc (c *Courseware) Validate() *CustomError { var m *CustomError if == "" { m = &CustomError{} (("The courseware name cannot be empty")) } if == "" { if m == nil { m = &CustomError{} } (("Courseware number cannot be empty")) } return m } func main() { m := Courseware{ Name: "Multimedia Courseware", Code: "CW330", } if err := (); err != nil { ("valid err: ", err) } }
But this is not desirable. In order to extend, we implement the error interface, we also need to return an error of type error.
This is all about this article about nil receivers in golang. For more related golangnil receiver content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!