Le langage Go peut utiliser des assertions de type pour effectuer des types d'interface. Dans Go, que vous convertissiez un type d'interface en un autre type d'interface ou que vous convertissiez une interface en un autre type de base, vous devez utiliser des assertions de type ; il existe deux types de syntaxe de conversion « variables converties : = variables d'interface. (type cible) » et "Variable convertie, ok := variable d'interface. (type cible)".
L'environnement d'exploitation de ce tutoriel : système Windows 7, GO version 1.18, ordinateur Dell G3.
Dans Golang, pour convertir un type d'interface en un autre type d'interface, ou pour convertir une interface en un autre type de base, vous devez utiliser des assertions de type.
Format de l'assertion de type
L'assertion de type est une opération utilisée sur les valeurs d'interface. Syntaxiquement, il semble que i.(T) soit appelé un type d'assertion, où i représente un type d'interface et T représente un type. Une assertion de type vérifie si le type dynamique de l'objet sur lequel elle opère correspond au type affirmé.
Le format de base de l'assertion de type est le suivant :
t := i.(T)
où i représente la variable d'interface, T représente le type cible converti et t représente la variable convertie.
Il y a deux possibilités ici. Premièrement, si le type affirmé T est un type concret, alors l'assertion de type vérifie si le type dynamique de i est le même que T . Si cette vérification réussit, le résultat de l'assertion de type est la valeur dynamique de i, qui est bien entendu de type T. En d’autres termes, une assertion de type pour un type concret obtient une valeur concrète de son opérande. Si la vérification échoue, l’opération suivante provoquera la panique. Par exemple :
var w io.Writer w = os.Stdout f := w.(*os.File) // 成功: f == os.Stdout c := w.(*bytes.Buffer) // 死机:接口保存*os.file,而不是*bytes.buffer
Deuxièmement, si à la place le type affirmé T est un type d'interface, alors l'assertion de type vérifie si le type dynamique de i satisfait T. Si cette vérification réussit, la valeur dynamique n'est pas récupérée ; le résultat est toujours une valeur d'interface avec les mêmes parties de type et de valeur, mais le résultat est de type T. En d’autres termes, une assertion de type sur un type d’interface modifie la façon dont le type est représenté et modifie l’ensemble de méthodes disponibles (généralement plus grand), mais elle protège les parties dynamiques de type et de valeur de la valeur d’interface.
Après la première assertion de type ci-dessous, w et rw détiennent os.Stdout afin qu'ils aient chacun un type dynamique *os.File, mais la variable w est un type io.Writer qui expose uniquement la méthode Write du fichier, mais le rw La variable expose uniquement sa méthode Read.
var w io.Writer w = os.Stdout rw := w.(io.ReadWriter) // 成功:*os.file具有读写功能 w = new(ByteCounter) rw = w.(io.ReadWriter) // 死机:*字节计数器没有读取方法
Si l'objet de l'opération d'assertion est une valeur d'interface nulle, alors l'assertion de type échouera quel que soit le type affirmé. Il n'est presque pas nécessaire d'affirmer un type d'interface moins restrictif (moins d'ensemble de méthodes) car il se comporte comme une opération d'affectation, à l'exception des valeurs d'interface nulles.
Si je n'implémente pas complètement la méthode de l'interface T, cette instruction déclenchera un crash. Déclencher un temps d'arrêt n'est pas très convivial, il existe donc une autre façon d'écrire l'instruction ci-dessus :
t,ok := i.(T)
De cette façon, si l'interface n'est pas implémentée, ok sera défini sur false et t sera défini sur une valeur 0 de type T . Dans une implémentation normale, ok c'est vrai. Ici, ok peut être considéré comme : le résultat du fait que l'interface i implémente le type T.
Convertir les interfaces vers d'autres interfaces
Un type qui implémente une certaine interface implémente également une autre interface À ce stade, vous pouvez convertir entre les deux interfaces.
Les oiseaux et les cochons ont des caractéristiques différentes. Les oiseaux peuvent voler, les cochons ne peuvent pas voler, mais les deux animaux peuvent marcher. Si vous utilisez des structures pour implémenter des oiseaux et des cochons, les méthodes Fly() et Walk() qui leur donnent leurs propres caractéristiques permettent aux oiseaux et aux cochons d'implémenter respectivement l'interface des animaux volants (Flyer) et l'interface des animaux qui marchent (Walker).
Une fois les instances d'oiseaux et de cochons créées, elles sont enregistrées dans une carte de type interface{}. Le type interface{} représente une interface vide, ce qui signifie que cette interface peut être enregistrée sous n'importe quel type. Effectuez une opération d'assertion sur la variable interface{} qui contient l'instance de bird ou pig. Si l'objet d'assertion est le type spécifié par l'assertion, une interface convertie en type d'objet d'assertion est renvoyée s'il ne s'agit pas du type d'assertion spécifié. , le deuxième paramètre de l'assertion renverra false.
Par exemple, le code suivant :
var obj interface = new(bird) f, isFlyer := obj.(Flyer)
Dans le code, new(bird) génère une instance d'oiseau de type *bird, et cette instance est enregistrée dans la variable obj de type interface{}. Utilisez l'assertion de type obj.(Flyer) pour convertir obj en interface Flyer. f est le type d'interface Flyer lorsque la conversion est réussie, isFlyer indique si la conversion est réussie et le type est bool.
Voici le code détaillé (code 1) :
package main import "fmt" // 定义飞行动物接口 type Flyer interface { Fly() } // 定义行走动物接口 type Walker interface { Walk() } // 定义鸟类 type bird struct { } // 实现飞行动物接口 func (b *bird) Fly() { fmt.Println("bird: fly") } // 为鸟添加Walk()方法, 实现行走动物接口 func (b *bird) Walk() { fmt.Println("bird: walk") } // 定义猪 type pig struct { } // 为猪添加Walk()方法, 实现行走动物接口 func (p *pig) Walk() { fmt.Println("pig: walk") } func main() { // 创建动物的名字到实例的映射 animals := map[string]interface{}{ "bird": new(bird), "pig": new(pig), } // 遍历映射 for name, obj := range animals { // 判断对象是否为飞行动物 f, isFlyer := obj.(Flyer) // 判断对象是否为行走动物 w, isWalker := obj.(Walker) fmt.Printf("name: %s isFlyer: %v isWalker: %v\n", name, isFlyer, isWalker) // 如果是飞行动物则调用飞行动物接口 if isFlyer { f.Fly() } // 如果是行走动物则调用行走动物接口 if isWalker { w.Walk() } } }
La description du code est la suivante :
La ligne 6 définit l'interface de l'animal volant.
La ligne 11 définit l'interface animal qui marche.
Les lignes 16 et 30 définissent respectivement les objets oiseau et cochon, et implémentent respectivement les interfaces animal volant et animal marchant.
La ligne 41 est une carte qui mappe les noms d'objets et les instances d'objets. Les instances sont des oiseaux et des cochons.
La ligne 47 commence à parcourir la carte, obj est le type d'interface interface{}.
第 50 行中,使用类型断言获得 f,类型为 Flyer 及 isFlyer 的断言成功的判定。
第 52 行中,使用类型断言获得 w,类型为 Walker 及 isWalker 的断言成功的判定。
第 57 和 62 行,根据飞行动物和行走动物两者是否断言成功,调用其接口。
代码输出如下:
将接口转换为其他类型
在代码 1 中,可以实现将接口转换为普通的指针类型。例如将 Walker 接口转换为 *pig 类型,请参考下面的代码:
p1 := new(pig) var a Walker = p1 p2 := a.(*pig) fmt.Printf("p1=%p p2=%p", p1, p2)
对代码的说明如下:
第 3 行,由于 pig 实现了 Walker 接口,因此可以被隐式转换为 Walker 接口类型保存于 a 中。
第 4 行,由于 a 中保存的本来就是 *pig 本体,因此可以转换为 *pig 类型。
第 6 行,对比发现,p1 和 p2 指针是相同的。
如果尝试将上面这段代码中的 Walker 类型的 a 转换为 *bird 类型,将会发出运行时错误,请参考下面的代码:
p1 := new(pig) var a Walker = p1 p2 := a.(*bird)
运行时报错:
panic: interface conversion: main.Walker is *main.pig, not *main.bird
报错意思是:接口转换时,main.Walker 接口的内部保存的是 *main.pig,而不是 *main.bird。
因此,接口在转换为其他类型时,接口内保存的实例对应的类型指针,必须是要转换的对应的类型指针。
总结
接口和其他类型的转换可以在Go语言中自由进行,前提是已经完全实现。
接口断言类似于流程控制中的 if。但大量类型断言出现时,应使用更为高效的类型分支 switch 特性。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!