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]
}

浙公网安备 33010602011771号