go语言开发基础29 - 之go语言里的接口定义与使用

接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。

在Go语言中接口(interface)是一种类型,一种抽象的类型。

接口:接口可以调用类型里自定义的方法
        1.1、go里面的接口只需要一个变量含有接口类型中的所有方法,那么这个变量就实现了接口
        1.2、如果一个变量含有多个interface类型的方法,那么这个变量就实现了多个接口
        1.3、如果一个变量只含有了一个interface方法的部分方法,那么这个变量没有实现这个接口

一、接口的定义与使用

1.1、接口定义的语法

type 接口类型名 interface{
    方法名1( 参数列表1 ) 返回值列表1
    方法名2( 参数列表2 ) 返回值列表2
    …
}

  

1.接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。

2.方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

3.参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。

 

1.2、接口示例

一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。

并且一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。

我们来看一个接口示例:

package main

import "fmt"

type Test interface {       // 定义一个名字为Test的接口(接口定义通过interface关键字)
	 Print()      // Test接口里包含Print和Sleep两个方法
	 Sleep()
}

type Student struct {     // 定义Student结构体
	name string
	age int
	score int
}

type Person struct {    // 定义Person结构体
	name string
	age int
}

func (self Student) Print() {         // 给Student结构体实现Print和Sleep方法(实现了Test接口)
	fmt.Println("name:",self.name)
	fmt.Println("age:",self.age)
	fmt.Println("score:",self.score)
}
func (self Student) Sleep() {
	fmt.Println("Sleeping")
}

func (self Person) Print() {        // 给Person接口提实现Print和Sleep方法(实现了Test接口)
	fmt.Println("name:",self.name)
	fmt.Println("age:",self.age)
}
func (self Person) Sleep() {
	fmt.Println("Sleeping")
}

func main() {
	var t Test      // 定义Test类型(接口类型)变量t
	// t.Print()      // 接口没有赋值之前直接调用会panic,结果为:panic: runtime error: invalid memory address or nil pointer dereference
	var stu Student = Student {         // 定义Student类型的变量stu并初始化stu变量
		name: "stu1",
		age: 20,
		score: 200,
	}
	t = stu        // 将实现了接口里规定方法的变量stu赋值给接口变量t(接口变量t不可以赋值给实现接口里规定方法的stu变量,没实现方法的变量赋值给接口会报错)
	t.Print()      // 执行stu结构体的Print方法
	t.Sleep()     // 执行stu结构体的Sleep方法

	var per Person = Person {         // 初始化per结构体
		name: "per1",
		age: 21,
	}
	t = per      // 将per的值赋值给接口类型t
	t.Print()     // 执行per的print方法
	t.Sleep()    // 执行per变量的Sleep方法
}

  

多态:一类事物的多种形态,可以通过一个接口实现多种不同的形态,叫多态(main函数里的t就实现了多态)
 
1.3、空接口

1.空接口可以接收任何类型的变量,但是空接口不可以给别的类型赋值

2.空接口可以用作函数的参数

3.空接口可以用作map的value

package main

import "fmt"

func main() {
        // 1.空接口的使用方法一
        var a interface {}      // 定义一个空接口
	var b int      // 定义int类型
	a = b     // 空接口可以接收任何值,但是空接口不可以给别的类型赋值
	var c float32
	a = c
	fmt.Println(a)

        // 2.空接口使用方法二
        var m map[string]interface{}
        m = make(map[string]interface{},3)
        m["name"] = "Dream"
        m["age"] = 18
        m["score"] = 98.9
        fmt.Println(m)         // 结果:map[age:18 name:Dream score:98.9]
}

  

1.4、接口嵌套

package main

// 接口嵌套示例
import (
	"fmt"
)

// 定义Reader接口
type Reader interface {
	Read()
}

// 定义Writer接口
type Writer interface {
	Write()
}

// 定义ReadWriter接口
type ReadWriter interface { // ReadWriter接口里嵌套了Reader和Writer接口
	Reader
	Writer
}

// 定义结构体类型
type File struct {     // 定义file类型结构体
	Name string
}

// 给File类型结构体实现Read方法
func (self File) Read() { // Reader接口里的方法
	fmt.Printf("read %s\n", self.Name)
}

// 给File类型结构体实现Writer方法
func (self File) Write() { // Writer接口里的方法
	fmt.Printf("write %s\n", self.Name)
}

func Test(rw ReadWriter) {     // 定义test函数,接收一个ReadWriter类型的参数
	rw.Read()
	rw.Write()
}


func main() {
	// 接口嵌套
	var f File     // 定义一个file类型的变量
	f.Name = "srdzw.net"        // 给变量赋值
	Test(f)        // 执行test函数(传一个实现了ReadWriter接口类型的参数才可以)
}

  

 1.5、其他类型的切片与接口类型的切片之间赋值

空接口因为没有实现任何方法,所以支持任意类型的赋值操作,但是其他类型的切片和接口类型的切片不可以直接赋值(直接赋值会报错),需要通过循环一个一个的来实现赋值操作,具体示例如下:

package main

import "fmt"

func main() {
	var a []int = []int{22, 33, 44, 55}
	var b []interface{}
	// b = a      // 这里直接赋值会报错,需要循环进行赋值

	for _, v := range a {
		b = append(b, v)
	}
	fmt.Println(b)        // 结果为:[22 33 44 55]
}

  

 

  

 

posted @ 2020-07-07 18:39  欧-阳  阅读(501)  评论(0)    收藏  举报