Home >Backend Development >Golang >How to convert go language interface type
Go language can use type assertions to perform interface types. In Go, whether you are converting one interface type to another interface type, or converting an interface to another basic type, you must use type assertions; there are two types of conversion syntax "converted variables: = interface variables. (target type)" and "Converted variable, ok := interface variable.(target type)".
The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.
In Golang, to convert one interface type to another interface type, or to convert an interface to another basic type, you must use Type assertion.
Format of type assertion
Type assertion is an operation used on interface values. Syntactically it looks like i.(T) is called an assertion type, where i represents an interface type and T represents a type. A type assertion checks whether the dynamic type of the object it operates on matches the asserted type.
The basic format of type assertion is as follows:
t := i.(T)
Where, i represents the interface variable, T represents the converted target type, and t represents the converted variable.
There are two possibilities here. First, if the asserted type T is a concrete type, then the type assertion checks whether the dynamic type of i is the same as T . If this check succeeds, the result of the type assertion is the dynamic value of i, which of course is of type T. In other words, a type assertion for a concrete type obtains a concrete value from its operand. If the check fails, the subsequent operation will throw a panic. For example:
var w io.Writer w = os.Stdout f := w.(*os.File) // 成功: f == os.Stdout c := w.(*bytes.Buffer) // 死机:接口保存*os.file,而不是*bytes.buffer
Second, if instead the asserted type T is an interface type, then the type assertion checks whether the dynamic type of i satisfies T. If this check succeeds, the dynamic value is not retrieved; the result is still an interface value with the same type and value parts, but the result has type T. In other words, a type assertion on an interface type changes the way the type is represented and changes the set of methods available (usually larger), but it protects the dynamic type and value parts of the interface value.
After the first type assertion below, both w and rw hold os.Stdout so they each have a dynamic type *os.File, but the variable w is an io.Writer type that is only exposed to the outside world. The Write method of the file is exposed, but the rw variable only exposes its Read method.
var w io.Writer w = os.Stdout rw := w.(io.ReadWriter) // 成功:*os.file具有读写功能 w = new(ByteCounter) rw = w.(io.ReadWriter) // 死机:*字节计数器没有读取方法
If the object of the assertion operation is a nil interface value, then the type assertion will fail regardless of the type being asserted. There is little need to assert on a less restrictive interface type (less set of methods) because it behaves like an assignment operation, except for nil interface values.
If i does not fully implement the method of T interface, this statement will trigger a crash. It is not very friendly to trigger downtime, so there is another way to write the above statement:
t,ok := i.(T)
In this way, if the interface is not implemented, ok will be set to false and t will be set to 0 of type T. value. In normal implementation, ok is true. Here ok can be thought of as: the result of whether interface i implements type T.
Convert the interface to other interfaces
#The type that implements a certain interface also implements another interface. At this time, the two interfaces can be conversion between.
Birds and pigs have different characteristics. Birds can fly, pigs cannot fly, but both animals can walk. If you use structures to implement birds and pigs, the Fly() and Walk() methods that give them their own characteristics allow the birds and pigs to implement the flying animal interface (Flyer) and walking animal interface (Walker) respectively.
After the instances of birds and pigs are created, they are saved into a map of interface{} type. The interface{} type represents an empty interface, which means that this interface can be saved as any type. Perform an assertion operation on the interface{} variable that holds the instance of bird or pig. If the assertion object is the type specified by the assertion, an interface converted to the assertion object type is returned; if it is not the specified assertion type, the second parameter of the assertion will return false.
For example, the following code:
var obj interface = new(bird) f, isFlyer := obj.(Flyer)
In the code, new(bird) generates a bird instance of type *bird, and this instance is saved in the obj variable of type interface{}. Use the obj.(Flyer) type assertion to convert obj to the Flyer interface. f is the Flyer interface type when the conversion is successful, isFlyer indicates whether the conversion is successful, and the type is bool.
The following is the detailed code (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() } } }
The code description is as follows:
Line 6 defines the interface of the flying animal.
Line 11 defines the walking animal interface.
Lines 16 and 30 define bird and pig objects respectively, and implement the flying animal and walking animal interfaces respectively.
Line 41 is a map that maps object names and object instances. The instances are birds and pigs.
Line 47 starts traversing the map, obj is the interface{} interface type.
第 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 特性。
The above is the detailed content of How to convert go language interface type. For more information, please follow other related articles on the PHP Chinese website!