官术网_书友最值得收藏!

Interfaces

After covering methods, we must cover interfaces, which make use of methods to produce efficient and scalable code in the Go language.

An interface can be very simply described as a Go type that hosts a collection of methods.

Here is a simple example:

type MyInterface interface{
GetName()string
GetAge()int
}

The preceding interface defines two methods—GetName() and GetAge().

Earlier, we attached two methods with the same signature to a type called Person:

type Person struct{
name string
age int
}
func (p Person) GetName()string{
return p.name
}
func (p Person) GetAge()int{
return p.age
}

In Go, an interface can be implemented by other types, like Go structs. When a Go type implements an interface, a value of the interface type can then hold that Go type data. We'll see what that means very shortly.

A very special feature in Go is the fact that for a type to implement or inherit an interface, the type only needs to implement the methods of said interface.

In other words, the Person struct type from the preceding piece of code implements the myInterface interface type. This is due to the fact that the Person type implements GetName() and GetAge(), which are the same methods that were defined by myInterface.

So, what does it mean when Person implements MyInterface?

It means that we can do something like this:

var myInterfaceValue MyInterface
var p = Person{}
p.name = "Jack"
p.age = 39
// some code
myInterfaceValue = p
myInterfaceValue.GetName() //returns: Jack
myInterfaceValue.GetAge() //returns: 39

We can also do this:

func main(){
p := Person{"Alice",26}
printNameAndAge(p)
}

func PrintNameAndAge(i MyInterface){
fmt.Println(i.GetName(),i.GetAge())
}

Interfaces are used quite a bit in APIs and in scalable software. They allow you to build software with flexible functionality. Here is a trivial example of how it helps you build flexible software.

Let's say we want to create a new person type that appends a title to the name:

type PersonWithTitle {
name string
title string
age int
}

func (p PersonWithTitle) GetName()string{
//This code returns <title> <space> <name>
return p.title + " " + p.name
}

func (p PersonWithTitle) GetAge() int{
return p.age
}

The preceding type also implements MyInterface, which means we can do this:

func main(){
pt := PersonWithTitle{"Alice","Dr.",26}
printNameAndAge(pt)
}

func PrintNameAndAge(i MyInterface){
fmt.Println(i.GetName(),i.GetAge())
}

The PrintNameAndAge() function signature will not need to change, since it relies on the interface instead of the concrete type. However, the behavior will differ a bit since we changed the concrete struct type from Person to PersonWithTitle. This ability allows you to write flexible APIs and packages that don't need to change whenever you need to add more concrete types to your code.

There are cases where you might want to get back the concrete type value from an interface value. Go includes a feature called type assertion that can be used for just that. Here is the most useful form of type assertion:

person, ok := myInterfaceValue.(Person)

The preceding code assumes that we are inside a function block. If myInterfaceValue does not hold a value of type Person, the preceding code will return an empty struct for the first return, and false for the second return. Therefore, ok will be false, whereas Person will be empty.

On the other hand, if myInterfaceValue holds a value of type Person, then ok will become true, and the Person variable will hold the data that's retrieved from myInterfaceValue.

Now, let's explore how to add logic to our code, by covering conditional statements and loops.

主站蜘蛛池模板: 湖州市| 攀枝花市| 应用必备| 吐鲁番市| 清新县| 阿克陶县| 郓城县| 桦川县| 若尔盖县| 湾仔区| 昌邑市| 淳化县| 萍乡市| 萨迦县| 博乐市| 巢湖市| 佛冈县| 渝中区| 卓资县| 苍南县| 尉犁县| 伊金霍洛旗| 盐边县| 屏山县| 永靖县| 大名县| 陆良县| 来宾市| 南汇区| 轮台县| 潮州市| 岢岚县| 宜良县| 桓台县| 灵武市| 华坪县| 海丰县| 明水县| 湟中县| 新密市| 噶尔县|