Explorez le concept de réflexion dans le langage de programmation Go, en explorant ses puissantes capacités d'analyse et de manipulation dynamiques du code.
Le langage de programmation Go est largement connu pour son expressivité. Il s'agit d'un langage fortement typé, mais qui donne néanmoins aux applications la possibilité de manipuler et d'inspecter dynamiquement des objets, notamment des variables, des fonctions et des types, au moment de l'exécution.
La réflexion est le mécanisme que Go utilise pour réaliser cette capacité. Qu'est-ce alors que la réflexion et comment pouvez-vous l'appliquer dans vos applications Go ?
Qu’est-ce que la réflexion?
La réflexion est la capacité d'un programme à examiner ses variables et sa structure et à les manipuler lors de l'exécution.
Reflection in Go est un mécanisme fourni par le langage pour la manipulation dynamique de types et d'objets. Vous devrez peut-être examiner des objets, les mettre à jour, appeler leurs méthodes ou même effectuer des opérations natives pour leurs types sans connaître leurs types au moment de la compilation. La réflexion rend tout cela possible.
Divers forfaits en Go, notamment codage ce qui vous permet de travailler avec JSON, et fmt, s'appuient fortement sur la réflexion sous le capot pour accomplir leurs tâches.
Comprendre le package Reflect dans Go
Apprendre le Golang peut être difficile en raison de sa sémantique et de la robuste bibliothèque de packages et de méthodes qui facilitent le développement de logiciels efficaces.
Le refléter package est l’un de ces nombreux packages. Il comprend toutes les méthodes dont vous avez besoin pour implémenter la réflexion dans les applications Go.
Pour commencer avec le refléter package, vous pouvez simplement l’importer comme ceci :
import"reflect"
Le package définit deux types principaux qui posent les bases de la réflexion dans Go: refléter. Taper et refléter. Valeur.
UN Taper est simplement un type Go. refléter. Taper est une interface composée de diverses méthodes permettant d'identifier différents types et d'examiner leurs composants.
La fonction pour vérifier le type de n'importe quel objet dans Go, refléter. Type de, accepte n'importe quelle valeur (un interface{}) comme seul argument et renvoie un refléter. Taper valeur qui représente le type dynamique de l’objet.
Le code ci-dessous montre l'utilisation de refléter. Type de:
x := "3.142"
y := 3.142
z := 3
typeOfX := reflect.TypeOf(x)
typeOfY := reflect.TypeOf(y)
typeOfZ := reflect.TypeOf(z)
fmt.Println(typeOfX, typeOfY, typeOfZ) // string float64 int
Le deuxième type dans le refléter emballer, refléter. Valeur peut contenir une valeur de n’importe quel type. Le refléter. Valeur de la fonction accepte n'importe quel interface{} et renvoie la valeur dynamique de l’interface.
Voici un exemple montrant comment utiliser refléter. Valeur de pour inspecter les valeurs ci-dessus :
valueOfX := reflect.ValueOf(x)
valueOfY := reflect.ValueOf(y)
valueOfZ := reflect.ValueOf(z)
fmt.Println(valueOfX, valueOfY, valueOfZ) // 3.142 3.142 3
Pour inspecter les types et les types de valeurs, vous pouvez utiliser l'outil Gentil et Taper méthode comme celle-ci :
typeOfX2 := valueOfX.Type()
kindOfX := valueOfX.Kind()
fmt.Println(typeOfX2, kindOfX) // string string
Bien que le résultat des deux appels de fonction soit le même, ils sont distincts. typeDeX2 c'est fondamentalement la même chose que typeDeX parce qu'ils sont tous les deux dynamiques refléter. Taper des valeurs, mais genreDeX est une constante dont la valeur est le type spécifique de X, chaîne.
C'est pourquoi il existe un nombre fini de types tels que int, chaîne, flotter, tableau, etc., mais un nombre infini de types car il peut y avoir plusieurs types définis par l'utilisateur.
Un interface{} et un refléter. Valeur fonctionne presque de la même manière, ils peuvent contenir des valeurs de n'importe quel type.
La différence entre eux réside dans la façon dont un vide interface{} n'expose jamais les opérations et méthodes natives de la valeur qu'elle détient. Ainsi, la plupart du temps, vous devez connaître le type dynamique de la valeur et utiliser l'assertion de type pour y accéder (c'est-à-dire je.(chaîne), x.(int), etc.) avant de pouvoir effectuer des opérations avec celui-ci.
En revanche, un refléter. Valeur dispose de méthodes que vous pouvez utiliser pour examiner son contenu et ses propriétés, quel que soit son type. La section suivante examine ces deux types de manière pratique et montre comment ils sont utiles dans les programmes.
Mise en œuvre des programmes Reflection in Go
La réflexion est très large et peut être utilisée à tout moment dans un programme. Vous trouverez ci-dessous quelques exemples pratiques illustrant l’utilisation de la réflexion dans les programmes :
-
Vérifier l'égalité profonde: Le refléter le paquet fournit le ProfondÉgal fonction pour vérifier en profondeur l'égalité des valeurs de deux objets. Par exemple, deux structures sont profondément égales si tous leurs champs correspondants ont les mêmes types et valeurs. Voici un exemple de code :
// deep equality of two arrays
arr1 := [...]int{1, 2, 3}
arr2 := [...]int{1, 2, 3}
fmt.Println(reflect.DeepEqual(arr1, arr2)) // true -
Copier des tranches et des tableaux: Vous pouvez également utiliser l'API de réflexion Go pour copier le contenu d'une tranche ou d'un tableau dans un autre. Voici comment:
slice1 := []int{1, 2, 3}
slice2 := []int{4, 5, 6}
reflect.Copy(reflect.ValueOf(slice1), reflect.ValueOf(slice2))
fmt.Println(slice1) // [4 5 6] -
Définir des fonctions génériques: Des langages comme TypeScript fournir un type générique, n'importe lequel, que vous pouvez utiliser pour contenir des variables de n’importe quel type. Bien que Go ne soit pas livré avec un type générique intégré, vous pouvez utiliser la réflexion pour définir des fonctions génériques. Par exemple:
// print the type of any value
funcprintType(x reflect.Value) {
fmt.Println("Value type:", x.Type())
} -
Accéder aux balises struct: Les balises sont utilisées pour ajouter des métadonnées aux champs de structure Go, et de nombreuses bibliothèques les utilisent pour déterminer et manipuler le comportement de chaque champ. Vous ne pouvez accéder qu'aux balises struct avec réflexion. L'exemple de code suivant illustre ceci :
type User struct {
Name string`json:"name" required:"true"`
}user := User{"John"}
field, ok := reflect.TypeOf(user).Elem().FieldByName("Name")if !ok {
fmt.Println("Field not found")
}// print all tags, and value of "required"
fmt.Println(field.Tag, field.Tag.Get("required"))
// json:"name" required:"true" true -
Réflexion sur les interfaces: Il est également possible de vérifier si une valeur implémente une interface. Cela peut être utile lorsque vous devez effectuer une couche supplémentaire de validations en fonction des exigences et des objectifs de votre application. Le code ci-dessous montre comment la réflexion vous aide à inspecter les interfaces et à déterminer leurs propriétés :
var i interface{} = 3.142
typeOfI := reflect.TypeOf(i)
stringerInterfaceType := reflect.TypeOf(new(fmt.Stringer))// check if i implements the stringer interface
impl := typeOfI.Implements(stringerInterfaceType.Elem())
fmt.Println(impl) // false
Les exemples ci-dessus illustrent comment vous pouvez utiliser la réflexion dans vos programmes Go réels. Le refléter Le package est très robuste et vous pouvez en apprendre davantage sur ses capacités dans le site officiel Allez réfléchir Documentation.
Quand utiliser la réflexion et les pratiques recommandées
Il peut y avoir plusieurs scénarios dans lesquels la réflexion peut sembler idéale, mais il est important de noter que la réflexion a ses propres compromis et peut affecter négativement un programme lorsqu'elle n'est pas utilisée de manière appropriée.
Voici quelques éléments à noter concernant la réflexion :
- Vous ne devez utiliser la réflexion que lorsque vous ne parvenez pas à prédéterminer le type d'un objet dans votre programme.
- La réflexion peut réduire les performances de votre application. Vous devez donc éviter de l'utiliser pour des opérations critiques en termes de performances.
- La réflexion peut également affecter la lisibilité de votre code, vous devez donc éviter de le jeter partout.
- Avec la réflexion, les erreurs ne sont pas capturées au moment de la compilation, vous risquez donc d'exposer votre application à davantage d'erreurs d'exécution.
Utiliser la réflexion si nécessaire
Reflection est disponible dans de nombreux langages, notamment C# et JavaScript, et Go parvient à implémenter parfaitement l'API. Un avantage majeur de la réflexion dans Go est que vous pouvez résoudre des problèmes avec moins de code lorsque vous exploitez les capacités de la bibliothèque.
Cependant, la sécurité des types est cruciale pour garantir un code fiable, et la vitesse est un autre facteur important pour une expérience utilisateur fluide. C'est pourquoi vous ne devriez utiliser la réflexion qu'après avoir pesé vos options. Et visez à garder votre code lisible et optimal.