Before we start, let's ask you a classic Go question: how to judge whether the value of an interface {} is nil?
This is also a question that may be asked in the interview. This question is very "mysterious". Friends who usually don't pay special attention can easily be cut here.
I believe many people will answer subconsciously. Wouldn't it be good to judge directly?
I thought so a long time ago, but after writing a demo, I found that things were not so simple.
Take a look at the following code, and you can guess the output first.
package main
import (
"fmt"
)
func main() {
var a *string = nil
var b interface{} = a
fmt.Println(b==nil)
}
The answer should be the opposite of your subconscious answer.
The output result is false
Why? Next, we're going to talk about it.
# 1. Comparison of two interface s
The internal implementation of interface contains two fields, one is type and the other is data
For such a variable
var age interface{} = 25
In fact, the internal structure is
Therefore, the comparison between the two interface s is bound to be related to these two fields.
After verification, the two interface s will be equal only in the following two cases.
First case
Both type and data are equal
In the following code, the type of p1 and p2 is Profile, and the data is {"iswbm"}, so p1 and p2 are equal
Although the types of p3 and p3 are both * Profile, because data stores the address of the structure, and the two addresses and are different, p3 and p4 are not equal
package main
import "fmt"
type Profile struct {
Name string
}
type ProfileInt interface {}
func main() {
var p1, p2 ProfileInt = Profile{"iswbm"}, Profile{"iswbm"}
var p3, p4 ProfileInt = &Profile{"iswbm"}, &Profile{"iswbm"}
fmt.Printf("p1 --> type: %T, data: %v \n", p1, p1)
fmt.Printf("p2 --> type: %T, data: %v \n", p2, p2)
fmt.Println(p1 == p2) // true
fmt.Printf("p3 --> type: %T, data: %p \n", p3, p3)
fmt.Printf("p4 --> type: %T, data: %p \n", p4, p4)
fmt.Println(p3 == p4) // false
}
After operation, the output is as follows
p1 --> type: main.Profile, data: {iswbm}
p2 --> type: main.Profile, data: {iswbm}
true
p3 --> type: *main.Profile, data: 0xc00008e200
p4 --> type: *main.Profile, data: 0xc00008e210
false
The second case
Special case: both interface s are nil
When the type and data of an interface are in unset state, the type and value of the interface are nil
package main
import "fmt"
func main() {
var p1, p2 interface{}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == nil) // true
}
# 2. interface vs. non interface
When an interface is compared with a non interface, the non interface will be converted into an interface, and then the comparison will be performed according to the rule of {two interface comparison}.
Examples are as follows
package main
import (
"fmt"
"reflect"
)
func main() {
var a string = "iswbm"
var b interface{} = "iswbm"
fmt.Println(a==b) // true
}
The above example may be easy to understand, so please look at the following example (the example at the beginning of the article). Why is b not equal to nil?
package main
import (
"fmt"
)
func main() {
var a *string = nil
var b interface{} = a
fmt.Println(b==nil) // false
}
But when you use , b==nil , the nil on the right is not simply that the value we understand is nil, but the correct understanding should be that the type is nil and the value is also nil.
Go will first convert nil to interface (type=nil, data=nil), which is the same as b (type=*string, data=nil). Although the data is the same, the types are not equal, so they are not equal.
Is there any way to judge whether an interface {} is nil?
There are ways, but with the help of reflection, a reflect package that will not be used as a last resort.
package main
import (
"fmt"
"reflect"
)
func IsNil(i interface{}) bool {
vi := reflect.ValueOf(i)
if vi.Kind() == reflect.Ptr {
return vi.IsNil()
}
return false
}
func main() {
var a *string = nil
var b interface{} = a
fmt.Println(IsNil(b))
}
This paper introduces some internal implementation principles of Go during comparison through some examples. For many people, it may be a "new" knowledge. If they do not master it, they will dig a "big pit" for themselves in the coding process in the future. However, the "pit" in this language is not known or unknown. It is difficult to find it no matter how to check the code. I hope to take you to fill in this "pit" through this article.
This article originally belongs to the Go interview question bank column series. In the past, it was stated in the title that it was an interview question. Considering that some people have not been in the interview recently, they are afraid that you will miss such knowledge that you should master even if you don't interview. In the future, it may not be specially marked as an interview question in the title.
I have published this column series on Github: https://github.com/iswbm/golang-interview
This number has no message function. If there is something wrong with the article, you can go there and submit the issue to help me correct it. By the way, can you order me a small one ⭐⭐, There I sorted the question bank to facilitate index search.
Come on. See you next time