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

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.

主站蜘蛛池模板: 焦作市| 襄汾县| 丽水市| 友谊县| 双桥区| 儋州市| 鹤山市| 光山县| 永泰县| 瑞昌市| 福州市| 穆棱市| 兰州市| 舞钢市| 扎兰屯市| 屯留县| 凤翔县| 凯里市| 北安市| 宁陵县| 木兰县| 饶平县| 斗六市| 额济纳旗| 淅川县| 玉树县| 桂阳县| 叶城县| 玉环县| 高安市| 水富县| 布尔津县| 祁门县| 许昌县| 清涧县| 澜沧| 农安县| 丰都县| 邵武市| 固始县| 微山县|