Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the Go interface

2025-02-04 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article is about how to use the Go interface. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

Interface is an abstract type, which generalizes and abstracts the behavior of other types. from a grammatical point of view, an interface is a collection of method definitions. Many object-oriented languages have the concept of interface, but the Go language interface is unique in that it is implicitly implemented.

1. Interface

Declare an interface in Go using the interface keyword:

Type Shaper interface {Area () float64Perimeter () float64}

What would be the result if we directly used the fmt library for output?

Func main () {var s Shaperfmt.Println ("value of s is", s) fmt.Printf ("type of s is% T\ n", s)}

Output:

Value of s is type of s is

Here, the concept of interface is introduced. There are two types of interfaces. The static type of the interface is the interface itself, such as Shape in the above program. The interface does not have a static value, but points to a dynamic value.

Variables of the interface type can hold the value of the type that implements the interface. The value of this type becomes the dynamic value of the interface, and the type becomes the dynamic type of the interface.

Starting from the example above, we can see that the zero value and the interface type is nil. This is because, at this point, we have declared the variable s of type Shaper, but no value has been assigned. When we use the Println function in the fmt package with interface parameters, it points to the dynamic value of the interface, and the% T syntax in the Printf function refers to the dynamically typed interface. In fact, the interface static type is Shaper.

What happens when we use a type to implement the interface.

Type Rect struct {width float64height float64} func (r Rect) Area () float64 {return r.width * r.height} func (r Rect) Perimeter () float64 {return 2 * (r.width + r.height)} / / mainfunc main () {var s Shaperfmt.Println ("value of s is", s) fmt.Printf ("type of s is% T\ n", s) s = Rect {5.0,4.0} r: = Rect {5.0,4.0} fmt.Printf ("type of s is% T\ n") S) fmt.Printf ("value of s is% v\ n", s) fmt.Printf ("area of rect is% v\ n", s.Area ()) fmt.Println ("s = = r is", s = = r)}

Output:

Value of s is type of s is type of s is main.Rectvalue of s is {5 4} area of rect is 20s = = r is tru

You can see that at this time s becomes a dynamic type, the storage is main.Rect, and the value becomes {5pr 4}.

Sometimes, an interface of a dynamic type is also called a concrete type, because when we access an interface type, it returns the type of its underlying dynamic value, and its static type remains hidden.

We can call the Area method on s because the interface Shaper defines the Area method, and the specific type of s is Rect, which implements the Area method. This method will be called on the dynamic value saved by the interface.

In addition, we can see that we can compare s with r because both variables hold the same dynamic type (structure of Rect type) and dynamic value {54}.

We then use circles to implement the interface:

Type Circle struct {radius float64} func (c Circle) Area () float64 {return 3.14 * c.radius * c.radius} func (c Circle) Perimeter () float64 {return 2 * 3.14 * c.radius} / / mains = Circle {10} fmt.Printf ("type of s is% T\ n", s) fmt.Printf ("value of s is% v\ n", s) fmt.Printf ("area of rect is% v\ n", s.Area ())

Output at this time:

Type of s is main.Circlevalue of s is {10} area of rect is 314

Here you have a better understanding of the dynamic types that the interface holds. From a slicing point of view, it can be said that the interface works in a similar way, that is, dynamically saving references to the underlying types.

When we delete the implementation of Perimeter, we can see the following error result.

. / rect.go:34:4: cannot use Rect {.} (type Rect) as type Shaper in assignment:Rect does not implement Shaper (missing Perimeter method)

It should be obvious from the above error that in order to successfully implement the interface, you need to implement all the methods declared with the fully signed interface.

two。 Null interface

When an interface has no methods, it is called an empty interface. This is represented by interface {}. Because an empty interface has no methods, all types implicitly implement this interface.

One of the functions of an empty interface is that a function can receive many different types of parameters.

For example: the Println function of fmt.

Func Println (a... interface {}) (n int, err error) Println is a variable function that accepts arguments of type interface {}.

For example:

Type MyString stringfunc explain (I interface {}) {fmt.Printf ("type:% T, value:% v\ n", I, I)} / / mains: = MyString ("hello") explain (s) r: = Rect {1,2} explain (r)

Output:

Type: inter.MyString, value: hellotype: inter.Rect, value: {1 2}

You can see that the types and values of the empty interface are dynamic.

3. Multiple Interfac

In the following program, we create the Shape interface with the Area method and the Object interface with the Volume method. Because the structure type Cube implements these two methods, it implements both interfaces. Therefore, we can assign the value of the structure type Cube to a variable of type Shape or Object.

Type IShape interface {Area () float64} type Object interface {Volume () float64} type Cube struct {side float64} func (c Cube) Area () float64 {return 6 * c.side * c.side} func (c Cube) Volume () float64 {return c.side * c.side * c.side} / / mainc: = Cube {3} var s IShape = cvar o Object = cfmt.Println ("area is", s.Area ()) fmt.Println ("Volume is", o.Volume ())

There is no problem with this kind of invocation, calling methods of their respective dynamic types.

What if that's the case?

Fmt.Println ("area of s of interface type IShape is", s.Volume () fmt.Println ("volume of o of interface type Object is", o.Area ())

Output:

S.Volume undefined (type Shape has no field or method Volume) o.Area undefined (type Object has no field or method Area)

This program cannot be compiled because the static type of s is IShape and the static type of o is Object. Because IShape does not define a Volume method, and Object does not define an Area method, we get the error above.

To make it work, we need to extract the dynamic values of these interfaces in some way, which is a cube-type structure that implements these methods. This can be done using type assertions.

4. Type assertion

We can determine the underlying dynamic value of interface I through I. (Type). Go will check whether the dynamic type of I is the same as type and return possible dynamic values.

Var S1 IShape = Cube {3} C1: = S1. (Cube) fmt.Println ("area of s of interface type IShape is", c1.Volume ()) fmt.Println ("volume of o of interface type Object is", c1.Area ())

In this way, we can work normally.

If IShape does not store Cube types and Cube does not implement IShape, an error is reported:

Impossible type assertion:Cube does not implement IShape (missing Area method)

If IShape does not store the Cube type and Cube implements Shape, an error is reported:

Panic: interface conversion: inter.IShape is nil, not inter.Cub

Fortunately, there is another return value in the syntax:

Value, ok: = I. (Type)

In the above syntax, if I has a specific type type or a dynamic value of type, we can use the ok variable to check. If not, then ok will be false and value will be zero (nil) of Type.

In addition, type assertions can be used to check whether the dynamic type of the interface implements other interfaces, just as the dynamic type of the previous IShape is Cube, which implements the IShape and Object interfaces, as shown in the following example:

Vaule1, ok1: = S1. (Object) value2, ok2: = S1. (Skin) fmt.Printf ("the dynamic type value of IShape s is:% v, whether the dynamic type implements Object interface:% v\ n", vaule1, ok1) fmt.Printf ("IShape s dynamic type value is:% v, whether the dynamic type implements Skin interface:% v\ n", value2, ok2)

Output:

The dynamic type value of IShape s is: {3}, whether the dynamic type implements Object interface: the dynamic type value of trueIShape s is:, whether the dynamic type implements Skin interface: false

Type assertions are used not only to check whether an interface has a specific value of a given type, but also to convert a given variable of an interface type to a different interface type.

5. Type Switch

In the previous empty interface, we know that if we take an empty interface as a function argument, then the function can accept any type, so if I have a requirement: when the passed data type is a string, it is required to be all uppercase. Other types do not operate?

To meet such requirements, we can use Type Switch, that is, I. (type) + switch.

Func switchProcess (I interface {}) {switch I. (type) {case string: fmt.Println ("process string") case int: fmt.Println ("process int") default: fmt.Printf ("type is% T\ n", I)}}

Output:

Process intprocess string6. Embedded interface

In Go, one interface cannot implement or extend other interfaces, but we can create a new interface by merging two or more interfaces.

For example:

Here, two interfaces, Runner and Eater, are combined to form a new interface RunEater, which is Embedding interfaces.

Type Runner interface {run () string} type Eater interface {eat () string} type RunEater interface {RunnerEater} type Dog struct {age int} func (d Dog) run () string {return "run"} func (d Dog) eat () string {return "eat"} / / maind: = Dog {10} var re RunEater = dvar r Runner = dvar e Eater = dfmt.Printf ("RunnEater dynamic type:% T, value:% v\ n", re, re) fmt.Printf ("Runn dynamic type:% T, value:% v\ n", r R) fmt.Printf ("Eater dynamic type:% T, value:% v\ n", e, e)

Output:

RunnEater dynamic type: inter.Dog, value: {10} Runn dynamic type: inter.Dog, value: {10} Eater dynamic type: inter.Dog, value: {10} 7. Interface comparison

If the underlying dynamic value is nil, the two interfaces are always equal, which means that the two nil interfaces are always equal, so = = operation returns true.

Var a, b interface {} fmt.Println (a = = b) / / true

If these interfaces are not nil, then their dynamic types (types of specific values) should be the same, and specific values should be equal.

If the dynamic type of the interface is not comparable, such as slice, map, function, or if the specific value of the interface is a complex data structure that contains these incomparable values, such as slices or arrays, the = = or! = operation will result in run-time panic.

Thank you for reading! This is the end of the article on "how to use the Go interface". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report