In some cases, Go returns false when comparing nil variable and nil. This might be confusing for beginners. But this leads to some benefits too.
🇨🇿 V češtině si lze článek přečíst na kutac.cz
The following code is a nice example when variable val
is nil
but the comparison in the function returns false. A similar situation is with readFile
function, which returns error
. You can run code in Go Playground to prove to yourself it is true.
func nilPrint(val interface{}) string {
if val == nil {
return "I got nil"
}
return fmt.Sprintf("I got %T type with value '%v'", val, val)
}
func readFile() error {
var err *fs.PathError
fmt.Println(err == nil)
return err
}
func main() {
// Prints: I got string type with value 'Some value'
fmt.Println(nilPrint("Some value"))
// Prints: I got nil
fmt.Println(nilPrint(nil))
// Prints: true
// but then: I got *string type with value '<nil>'
var val *string
fmt.Println(val == nil) // Prints true
fmt.Println(nilPrint(val))
fmt.Println("\nWith error interface")
// Prints: true (inside readFile)
// but then: false (in main method)
err := readFile()
fmt.Println(err == nil)
}
The reason of this is interface
This behavior is caused by using interface{}
as an input type. Which is something like Any. The second function returns error
, which is also interface. The
comparison then returns false
, because the value is null, but it has also data type. That is the reason why it is not equal to "raw" nil
. If you are comparing variable with a known type, you are not affected by this behavior.
Solution with reflection
The way to fix the function which is returning error
is simple. Do not set concrete error type, but stay with error
type. So changing first line to this var err error
. That is also best practise.
In the second case it might be little bit trickier. Changing data type is not so easy, because we want to accept anything. So the reflection package must be used here.
if val == nil || (reflect.ValueOf(val).Kind() == reflect.Ptr && reflect.ValueOf(val).IsNil()) {
return "I got nil"
}
Calling methods on nil object
I'm not sure this is related to behavior described above. But in my eyes it is similar.
Go doesn't have methods like other OOP languages. In Go, we call it receivers, which acts similarly. But there is a main difference. If the variable of type is nil, you can still call its receivers, or methods if you want. The code below does not panic but works correctly. Check it on Go Playground.
type JSONParser struct {
raw string
}
func (p *JSONParser) Length() int {
if p == nil {
return 0
}
return len(p.raw)
}
func main() {
var parser *JSONParser
fmt.Println(parser.Length()) // Prints: 0
parser = &JSONParser{raw: `{"just": "show", "some_result": 255}`}
fmt.Println(parser.Length()) // Prints: 36
}
Top comments (0)