Vaya notas de combate de idiomas (veinticuatro) | Vaya reflexión

Al igual que el lenguaje Java, Go también implementa la reflexión en tiempo de ejecución, lo que nos brinda la capacidad de manipular cualquier tipo de objeto en tiempo de ejecución. Por ejemplo, podemos ver el tipo específico de una variable de interfaz, ver cuántos campos tiene una estructura, cómo modificar el valor de un campo, etc.

TypeOf 和 ValueOf

En la definición de reflexión de Go, cualquier interfaz se compone de dos partes, una es el tipo específico de interfaz y la otra es el valor correspondiente al tipo específico. Por ejemplo var i int = 3 , debido a que interface{}puede representar cualquier tipo, la variable ise puede convertir a interface{}, por lo que la variable se puede considerar icomo una interfaz, entonces la representación de esta variable en la reflexión de Go es <Value,Type>, donde Valor es el valor de la variable 3y el Tipo variable es el tipo int.

En la reflexión de Go, la biblioteca estándar nos proporciona dos tipos para representar su reflect.Valuesuma reflect.Typey dos funciones para obtener la Valuesuma de cualquier objeto Type.

func main() {
	u:= User{"张三",20}
	t:=reflect.TypeOf(u)
	fmt.Println(t)
}

type User struct{
	Name string
	Age int
}
   

reflect.TypeOfPuede obtener el tipo específico de cualquier objeto, y puede ver main.Usereste tipo de estructura imprimiendo aquí . reflect.TypeOfLa función acepta una interfaz vacía interface{}como parámetro, por lo que este método puede aceptar cualquier tipo de objeto.

Siguiendo el ejemplo anterior, veamos cómo hacer que un objeto se refleje Value.

	v:=reflect.ValueOf(u)
	fmt.Println(v)
   

Al igual que la TypeOffunción, también puede aceptar cualquier objeto, puede ver la impresión como {张三 20}. Para los dos tipos de salida anteriores, Go language también fmt.Printfnos proporciona métodos convenientes a través de funciones.

    fmt.Printf("%T\n",u)
	fmt.Printf("%v\n",u)
   

Este ejemplo es el mismo que el resultado del ejemplo anterior.

reflexionar Valor al tipo primitivo

En el ejemplo anterior, podemos reflect.ValueOfconvertir cualquier tipo de objeto en uno a través de una función reflect.Value, por lo que si queremos revertirlo, en realidad es posible y reflect.Valuenos proporciona una Intefaceforma de ayudarnos a hacer esto. Continúe con el ejemplo anterior:

	u1:=v.Interface().(User)
	fmt.Println(u1)
   

De esta manera, volvemos al Userobjeto original , que puede ser verificado por la salida impresa. La razón aquí es debido a la reducción en la reflexión de Go's, los sujetos se dividieron en cualquiera reflect.Valuey reflect.Type, mientras reflect.Valuesostienen simultáneamente un objeto reflect.Valuey reflect.Typeasí podemos ser reflect.Valueuna Interfaceforma de lograr la reducción. Ahora vemos cómo reflect.Valueobtener el correspondiente de uno reflect.Type.

	t1:=v.Type()
	fmt.Println(t1)
   

En el ejemplo anterior, mediante reflect.Valueel Typemétodo se puede utilizar para obtener el correspondiente reflect.Type.

Obtenga el tipo subyacente del tipo

¿Qué significa el tipo subyacente? De hecho, los principales tipos correspondientes son tipos básicos, interfaces, estructuras, punteros, etc., porque podemos typedeclarar muchos tipos nuevos a través de palabras clave. Por ejemplo, en el ejemplo anterior, uel tipo real del objeto es User, pero el subyacente correspondiente type es structeste tipo de estructura. Vamos a verificarlo.

fmt.Println(t.Kind())
   

Se Kindpuede obtener mediante métodos, lo cual es muy sencillo, por supuesto, también podemos utilizar métodos Valueobjeto Kind, son equivalentes.

Las notas de lectura "Go Language Practice" continuarán, escanee el código QR para seguir la cuentaflysnow_org oficial o el sitio web http://www.flysnow.org/ , y lea las notas de seguimiento por primera vez. Si lo encuentra útil, compártalo con su círculo de amigos, gracias por su apoyo.

Go language proporciona los siguientes tipos de nivel más bajo, como puede ver, todos son los más básicos.

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Ptr
	Slice
	String
	Struct
	UnsafePointer
)
   

Iterar sobre campos y métodos

A través de la reflexión, podemos obtener el campo de un tipo de estructura, y también el método de exportación de un tipo, de modo que podamos entender la estructura de un tipo en tiempo de ejecución, que es una función muy poderosa.

	for i:=0;i<t.NumField();i++ {
		fmt.Println(t.Field(i).Name)
	}

	for i:=0;i<t.NumMethod() ;i++  {
		fmt.Println(t.Method(i).Name)
	}
   

Este ejemplo imprime todos los nombres de campo de la estructura y el método de la estructura. NumFieldEl método obtiene cuántos campos hay en la estructura y luego Fieldpasa el índice a través del método, obtiene cada campo en un bucle y luego imprime sus nombres.

El mismo método es similar, así que no lo repetiré aquí.

Modificar el valor del campo

¿Qué pasa si queremos modificar dinámicamente el valor de un campo durante la operación? Una es que proporcionamos métodos o campos exportados de forma rutinaria para que modifiquemos, y la otra es utilizar la reflexión, que se presenta principalmente aquí.

func main() {
	x:=2
	v:=reflect.ValueOf(&x)
	v.Elem().SetInt(100)
	fmt.Println(x)
}
   

Lo anterior es un ejemplo de cómo modificar una variable mediante la reflexión.

Debido a que la reflect.ValueOffunción devuelve una copia del valor, la premisa es que pasamos la dirección de la variable a modificar. En segundo lugar, necesitamos llamar al Elemmétodo para encontrar el valor al que apunta este puntero. Finalmente, podemos usar el SetIntmétodo para modificar el valor.

Hay varios puntos importantes anteriores para garantizar que el valor se pueda modificar y Valuenos proporciona un CanSetmétodo para ayudarnos a determinar si el objeto se puede modificar.

Ahora podemos actualizar el valor de la variable, entonces, ¿cómo modificamos el valor del campo de estructura? Inténtalo tú mismo.

Método de llamada dinámica

No solo podemos llamar al método de estructura normalmente, sino que también podemos usar la reflexión. Para realizar una llamada de reflexión, primero debemos obtener el método que se necesita llamar y luego realizar una llamada de parámetro, como se muestra en el siguiente ejemplo:

func main() {
	u:=User{"张三",20}
	v:=reflect.ValueOf(u)

	mPrint:=v.MethodByName("Print")
	args:=[]reflect.Value{reflect.ValueOf("前缀")}
	fmt.Println(mPrint.Call(args))

}

type User struct{
	Name string
	Age int
}

func (u User) Print(prfix string){
	fmt.Printf("%s:Name is %s,Age is %d",prfix,u.Name,u.Age)
}
   

MethodByNameEl método nos permite obtener un objeto de método basado en un nombre de método, y luego construimos los parámetros requeridos por el método, y finalmente lo llamamos Callpara lograr el propósito de llamar dinámicamente al método.

Podemos utilizar el método obtenido IsValidpara juzgar si está disponible (existente).

El parámetro aquí es una Valuematriz de tipo, por lo que los parámetros requeridos deben ValueOfconvertirse a través de funciones.

Este es el final de la introducción básica de la reflexión. El próximo artículo presentará algunos usos avanzados, como obtener la etiqueta de un campo. De uso común, como convertir una cadena json en una estructura, se usa la etiqueta del campo.

Supongo que te gusta

Origin blog.csdn.net/qq_32907195/article/details/112463646
Recomendado
Clasificación