This is a creation in Article, where the information may have evolved or changed.
First, let's look at an example
type Stringer interface { String() string}type String struct { data string}func (s *String) String() string { return data}
Above is the type, and then
func GetString() *String { return nil}func CheckString(s Stringer) bool { return s == nil}func main() { println(CheckString(GetString()))}
What do you think the answer is?
Of course, such a strange way of questioning the answer is unreasonable false.
In the CheckString
inside, S is not equal to nil.
If you think it's incredible, you can keep looking.
It should be emphasized that this article only applies to Golang.
Type conversions
The official documentation clearly states how the type T can be converted to V, and normally, T must be explicitly declared to be converted to V.
func check64(v int64){}func check(v int){}a := 5b := int64(10)check64(int64(a))check(int(b))check64(a) // panic
However, if the assignability is satisfied, the type conversion can be performed automatically without an explicit declaration
Among them, the more easily overlooked is the two:
- X is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
- X is an untyped constant representable by a value of type T.
const a = 5func check64(v int64){}func checkSlice(v []int){}check64(a) // -> check64(int64(a))check64(1024) // -> check64(int64(1024))checkSlice(nil) // -> checkSlice([]int(nil))
The above code is able to execute correctly, it should be noted that 1024 is also a constant (here is a description of Integer literals
a integer constant
).
Analysis
When you know it, look at the example I just started.
func GetString() *String { return nil}println(interface{}(GetString()))
What is thrown out here is actually *String(nil)
, if print comes out, it should be a value of (0x****, 0x0)
What is required PS is that when print prints a interface, the first value is a pointer to a variable's dynamic type, and the second value is a pointer to the actual value. Here in order to get the dynamic type, deliberately converted to interface{}
Then, to CheckString
,
func CheckString(s Stringer) bool { return s == nil}
This nil
will be converted Stringer(nil)
, printed with print Dafa, and the result is(0x0, 0x0)
Is it strange that print prints out the first is a type of pointer, why is it 0? First, a variable has a dynamic type and a static type, and if it is not interface, the static type is the same as the dynamic type, and when interface, the static type is the value of interface, and the dynamic type is the actual type of the value that he stores. Print is a dynamic type, because here he has a value of 0, and the dynamic type is certainly 0.
When executing at CheckString(GetString())
this time, S *String(nil)
is, and nil is <nil>(nil)
(null type of NULL pointer), when the equals judgment, according to spec, interface will be the dynamic type
same as dynamic value
the exact time to return true. So this is obviously false.
How to not step on the pit
Although the example seems to be unreasonable, but in fact it is easier to step on the pit, especially when you want to die ...
type SpecError struct { err Error}func NewSpecError(err error) *SpecError { if err == nil { return nil } return &SpecError{err}}func (se *SpecError) Error() string { return se.err.Error()}func GetObjByID(id string) (*Obj, error) { obj, err := xxxxx(id) return obj, NewSpecError(err)}func main(){ obj, err := GetObjByID("123") if err != nil { panic(err) } 。。。}
Well, I admit that if you don't die, you're not going GetObjByID
to get it. if err != nil
Thinking
type RouterString func() stringtype RouterBytes func() []bytefunc AddRouter(router interface{}) { switch router := router.(type) { case RouterString: println("string") case RouterBytes: println("bytes") default: println("unknown types") }}func main() { AddRouter(func() string{ println("hello?") })}
What's wrong with this piece of code? How to change?