SoFunction
Updated on 2025-03-01

Implementation of Go language assertions and type query

1. Type Assertion

Type Assertion is an operation used on interface values ​​to check whether the value held by an interface type variable implements the desired interface or specific type.

In Go, the syntax format of type assertions is as follows:

// i.(TypeNname)
value, ok := x.(T)

Where x represents the type of an interface. If it is a specific type variable, the compiler will report it.non-interface type xxx on left, T represents a specific type (can also be an interface type).

This assertion expression will return the value of x (that is, value) and a boolean value (that is, ok). You can judge whether x is of type T based on the boolean value:

  • If T is a specific type, the type assertion checks whether the dynamic type of x is equal to the specific type T. If the check is successful, the result returned by the type assertion is a dynamic value of x, whose type is T.

  • If T is an interface type, the type assertion checks whether the dynamic type of x satisfies T. If the check is successful, the dynamic value of x will not be extracted, and the return value is an interface value of type T.

  • Regardless of the type T, if x is the nil interface value, the type assertion will fail.

The sample code is as follows:

package main

import (
	"fmt"
)

func main() {
	var x interface{}
	x = 10
	value, ok := x.(int)
	// 10,true
	(value, ",", ok)
}

The operation results are as follows:

# Program Results
10,true

It should be noted that if the second parameter is not received, that is, ok in the above code, a panic will be directly caused when the assertion fails. If x is nil, it will also be panic.

The sample code is as follows:

package main

import (
	"fmt"
)

func main() {
	var x interface{}
	x = "Hello"
	value := x.(int)
	(value)
}

The operation results are as follows:

# Output result
panic: interface conversion: interface {} is string, not int

Interface assertions can usually use the comma,ok statement to determine whether the interface binds to a certain instance type, or determine whether the instance type bound to the interface implements another interface.

re,ok := body.()
if,ok :=  .(*maxBytesReader);

2. Type query

The syntax format of interface type query is as follows:

switch v := i.(type){
	case typel:
		XXXX
	case type2:
		XXXX
	default:
		XXXX
}

Interface query has two layers of semantics. One is to query what is the specific type of the underlying variable bound to an interface variable, and the other is to query the underlying variable binding of an interface variable.

Whether layer variables also implement other interfaces.

(1) i must be interface type

The type of a specific type instance is static and will not change after the type is declared, so there is no type query for the specific type variable, and the type query must be

Operates on an interface variable. That is, i in the above must be an interface variable. If i is an uninitialized interface variable, the value of v is nil.

package main

import (
	"fmt"
	"io"
)

func main() {
	var i 
	// Here i is an uninitialized interface variable, so v is nil	switch v := i.(type) {
	case nil:
		//<nil>
		("%T\n", v)
	default:
		("default")
	}
}

(2) The case sentence can be followed by a non-interface type name or an interface type name. The matching is carried out in the order of the case clause.

  • If case is followed by an interface type name, and the instance type bound to the interface variable i implements the method of this interface type, it will be matched to: v is the interface type, and the instance bound to v is the underlying binding of the i-binding instance of the specific type.

  • If case is followed by a specific type name, and the instance type bound to the interface variable i is the same as the specific type, the match is successful. At this time, v is the specific type variable, and the value of v is a copy of the instance value bound to i.

  • If case is followed by multiple types and separated by commas, the instance type bound by the interface variable i matches one of the types, then o is directly assigned to v, which is equivalent to v:=o. This syntax is a bit strange. The compiler should not allow this operation. Language implementers may want to keep the type switch statement and ordinary switch statements in the same syntax rules to allow this to happen.

  • If all case statements are not satisfied, the default statement is executed, and the execution of v:=o is still v and the final value of v is o. There is no point in using v at this time.

  • The fallthrough statement cannot be used in a Type Switch statement.

package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	var i 
	// Here i is an uninitialized interface variable, so v is nil	switch v := i.(type) {
	case nil:
		// <nil>
		("%T\n", v)
	default:
		("default")
	}
	f, err := ("", os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		(err)
	}
	defer ()
	i = f
	switch v := i.(type) {
	// The binding instance of i is the *osFile type, which implements the interface, so the following case matches successfully	case :
		// v is the interface type, so you can call the Write method		([]byte("\n"))
		// Type Switch Result: 
		("Type Switch Result: ")
	// Since the previous case has matched, even if this case matches, it will not be here.	case *:
		([]byte("*\n"))
		("Type Switch Result: *")
		// Here you can call the specific type method		()
	default:
		("Type Switch Result: unknown")
		return
	}

	switch v := i.(type) {
	// The matching is successful, the type of v is the specific type*	case *:
		([]byte("*\n"))
		// Type Switch Result: *
		("Type Switch Result: *")
		()
	//Because the previous case has already matched, even if this case matches, it will not be here.	case :
		//v is the interface type, so you can call the Write method		([]byte("\n"))
		("Type Switch Result: ")
	default:
		("Type Switch Result: unknown")
		return
	}

	switch v := i.(type) {
	// Multiple types, f satisfies any of them as a match	case *, :
		// At this time, the execution power is equivalent to v:= i, v and i are equivalent, and using v has no meaning.		if v == i {
			// true
			(true)
		}
	default:
		return
	}
}

# Program output
<nil>
Type Switch Result:
Type Switch Result: *
true 

package main

import (
	"fmt"
)

func main() {
	var a int
	a = 10
	// the type of a is int
	getType(a)
}

func getType(a interface{}) {
	switch a.(type) {
	case int:
		("the type of a is int")
	case string:
		("the type of a is string")
	case float64:
		("the type of a is float")
	default:
		("unknown type")
	}
}

# Program output
the type of a is int

This is the end of this article about the implementation of Go language assertions and type query. For more relevant Go language assertions and type query content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!