Go interface接口
本文最后更新于:9 天前
1 接口的介绍
1.1 现实生活中的接口
比如手机电脑相机,都是可以通过接口来进行连接的,我们不需要关注卡槽的大小,因为所有的usb接口都是按照统一的标准来设计的
1.2 Golang的接口
在Golang中接口(interface)
是一种类型,一种抽象的类型,接口是一组函数method的结合,Golang中的接口不能包含任何变量,可以认为它是一种定义接口的规范。
1.3 Goalng 接口的定义
在Golang中接口中的所有方法都没有方法体,接口定义了一个对象的行为规范,只是定义规范不实现,接口体现了程序设计的多态和高内聚低耦合的思想
Gloang中的接口也是一种数据类型,不需要显示实现,只需要一个变量含有接口类型的所有方法,那么这个变量就是实现了这个接口
Golang中每个接口由数个方法组成,接口的定义格式如下:
type 接口名字 interface {
方法名字1(参数列表1) 返回值列表1
方法名字2(参数列表2) 返回值列表2
...
}
- 接口名字: 使用type 关键字将接口定义为自定义的类型名, Go语言的接口在命名的时候,一般会在单词后面添加er,如写操作的接口叫做Writer,有字符串功能的接口叫Stinger等,接口名字最好可以见名知意
- 方法名字: 当方法名字首字母大写且接口类型首字母大写的时候,可以被接口所在的包之外的代码访问
- 参数列表,返回值列表: 这个是可以省略的,跟函数的是一样的。
1.4 接口的使用
代码演示
package main
import "fmt"
type Usber interface {
start()
stop()
}
type iphone struct {
name string
}
type camera struct {
name string
}
//iphone 结构体实现 Usber接口的俩个方法 一个start 一个stop
func (i iphone) start() {
fmt.Printf("%v 插入usb 成功\n", i.name)
}
func (i iphone) stop() {
fmt.Printf("%v 拔出usb 成功\n", i.name)
}
//camera 结构体实现 Usber接口的俩个方法 一个start 一个stop
func (c camera) start() {
fmt.Printf("%v 插入usb 成功\n", c.name)
}
func (c camera) stop() {
fmt.Printf("%v 拔出usb 成功\n", c.name)
}
func main() {
var i1 = iphone{
name: "xiaomi",
}
var c1 = camera{
name: "canon",
}
var u1 Usber
u1 = i1
u1.start()
u1.stop()
var u2 Usber
u2 = c1
u2.start()
u2.stop()
}
/*
xiaomi 插入usb 成功
xiaomi 拔出usb 成功
canon 插入usb 成功
canon 拔出usb 成功
*/
通过电脑空结构体实现调用接口方法
package main
import "fmt"
type Usber1 interface {
start()
stop()
}
type computer struct {
}
type iphone struct {
name string
}
type camera struct {
name string
}
func (com computer) worker(usb Usber1) {
usb.start()
usb.stop()
}
//iphone 结构体实现 Usber接口的俩个方法 一个start 一个stop
func (i iphone) start() {
fmt.Printf("%v 插入电脑usb 成功\n", i.name)
}
func (i iphone) stop() {
fmt.Printf("%v 拔出电脑usb 成功\n", i.name)
}
//camera 结构体实现 Usber接口的俩个方法 一个start 一个stop
func (c camera) start() {
fmt.Printf("%v 插入电脑usb 成功\n", c.name)
}
func (c camera) stop() {
fmt.Printf("%v 拔出电脑usb 成功\n", c.name)
}
func main() {
var i1 = iphone{
name: "ihpone12",
}
var c1 = camera{
name: "sony 50D",
}
var com1 computer
var inter1 Usber1 = i1
var inter2 Usber1 = c1
com1.worker(inter1)
com1.worker(inter2)
}
/*
ihpone12 插入电脑usb 成功
ihpone12 拔出电脑usb 成功
sony 50D 插入电脑usb 成功
sony 50D 拔出电脑usb 成功
*/
2 空接口介绍
golang中的空接口,可以通过接口方式定义,也可以直接当做类型来使用,可以表示任意数据类型
2.1 通过接口的方式定义
type Aer interface{} //表示一个空接口
var str = "hello"
var A1 Aer
A1 := str
fmt.Printf("值:%v 类型: %T",A1,A1) //值:hello 类型: string
2.2 直接通过类型来定义
var a interface{}
a = 20
fmt.Printf("值:%v 类型: %T",a,a)
a = "你好"
fmt.Printf("值:%v 类型: %T",a,a)
a = true
fmt.Printf("值:%v 类型: %T",a,a)
3 空接口的使用
3.1 空接口作为函数的使用
func show(a interface{}) {
fmt.Printf("值:%v 类型: %T", a, a)
}
3.2 map的值实现空接口
这样我们map类型的值,就可以是接收任意值(不像以前必须是定义死的,比如string)
var UserInfo = make(map[string]interface{})
UserInfo["name"] = "bds"
UserInfo["married"] = false
UserInfo["age"] = 18
3.3 切片实现空接口
切片同理也可以接收任意类型
var slice = []interface{}{"bds",20,true}
4 类型断言
一个接口的值(接口值) 是由一个具体类型和具体类型的值俩部分组成,这俩个部分分别称为接口的动态类型和动态值
如果我们想要判断空接口中值的类型到底是什么类型 ,这个时候我们就要使用类型断言
x(T)
- x: 表示类型为interface{}的变量
- T:表示断言x 可能是的类型
该语法返回俩个值,第一个参数是x转化为T类型后的变量,第二值是一个布尔值 ,返回true表示断言成功,否则失败
package main
import "fmt"
//第一种方法通过i.(T)实现
func MyPrint(i interface{}) {
if _, ok := i.(string); ok {
fmt.Printf("%v是%T\n", i, i)
} else if _, ok := i.(int); ok {
fmt.Printf("%v是%T\n", i, i)
} else if _, ok := i.(bool); ok {
fmt.Printf("%v是%T\n", i, i)
} else {
fmt.Println("断言失败")
}
}
//第二种方法通过i.(type) 只能结合switch 使用
func MyPrint2(i interface{}) {
switch i.(type) {
case int:
fmt.Printf("%v是%T\n", i, i)
case string:
fmt.Printf("%v是%T\n", i, i)
case bool:
fmt.Printf("%v是%T\n", i, i)
default:
fmt.Println("对不起,我不认识")
}
}
func main() {
var a string = "bds"
var b int = 10
var c bool = true
MyPrint(a)
MyPrint(b)
MyPrint(c)
var d = 12.23
MyPrint2(a)
MyPrint2(b)
MyPrint2(c)
MyPrint2(d)
}
/*
bds是string
10是int
true是bool
bds是string
10是int
true是bool
对不起,我不认识
*/
上面我们通过电脑调用接口方法我们可以来通过断言判断, 比如是如果手机结构体 值调用start 方法。
func (com computer) worker(usb Usber1) {
if _, ok := usb.(iphone); ok {
usb.start()
} else {
usb.stop()
}
}
5 结构体 值和指针 接收者的区别
5.1 值接收者
实例化后的结构体 值类型
和指针类型
都可以赋值给 接口变量
package main
import (
"fmt"
)
type Usber3 interface {
start()
stop()
}
type iphone1 struct {
name string
}
//值类型接收传入参数
func (i iphone1) start() {
fmt.Printf("%v start\n", i.name)
}
func (i iphone1) stop() {
fmt.Printf("%v stop", i.name)
}
func main() {
var tel1 = iphone1{
name: "xiaomi",
}
var u1 Usber3 = tel1
u1.start()
//定义指针变量传入
var tel2 = &iphone1{
name: "oneplus",
}
var u2 Usber3 = tel2
u2.start()
}
5.2 指针接收者
只能接收指针类型的
package main
import (
"fmt"
)
type Usber3 interface {
start()
stop()
}
type iphone1 struct {
name string
}
//值类型接收传入参数
func (i iphone1) start() {
fmt.Printf("%v start\n", i.name)
}
//这里改成指针类型接收传入参数,发现tel1 值类型的传入编译报错 。
func (i *iphone1) stop() {
fmt.Printf("%v stop", i.name)
}
func main() {
//var tel1 = iphone1{
// name: "xiaomi",
//}
//var u1 Usber3 = tel1
//u1.start() //报错: iphone1 does not implement Usber3 (stop method has pointer receiver)
//定义指针变量传入 这个依然正常。不会报错
var tel2 = &iphone1{
name: "oneplus",
}
var u2 Usber3 = tel2
u2.start()
u2.stop() //正常调用stop 方法
}
5.3 实现一个组合接收者类型
package main
import "fmt"
type Animaler interface {
GetName() string
SetName(string)
}
type Dog struct {
Name string
}
func (d Dog) GetName() string {
return d.Name
}
func (d *Dog) SetName(n string) {
d.Name = n
}
func main() {
d1 := &Dog{
Name: "兰博基尼狗",
}
var a1 Animaler = d1
fmt.Println(a1.GetName())
a1.SetName("玛莎拉蒂狗")
fmt.Println(a1.GetName())
}
/*
兰博基尼狗
玛莎拉蒂狗
*/
6 一个结构体实现多个接口
package main
import (
"fmt"
)
type zoo1 interface {
getname()
}
type zoo2 interface {
setname(string)
}
type Cat struct {
name string
}
func (c Cat) getname() {
fmt.Println(c.name)
}
func (c *Cat) setname(n string) {
c.name = n
}
func main() {
var c = &Cat{
name: "小花猫",
}
var z1 = c
z1.getname()
z1.setname("小红猫")
z1.getname()
}
7 接口的嵌套
package main
import "fmt"
type blue interface {
getMode()
}
type fuyin interface {
getColor()
}
//直接嵌套上面俩个接口
type kq interface {
blue
fuyin
}
type qin struct {
name string
mode string
color string
}
func (q qin) getMode() {
fmt.Println(q.mode)
}
func (q qin) getColor() {
fmt.Println(q.color)
}
func main() {
var q1 = qin{
name: "honner",
mode: "blues",
color: "red",
}
var k1 kq = q1
k1.getMode()
k1.getColor()
}
8 空接口针对 切片 结构体类型的取值
上面空接口会返回动态类型和动态值,这个时候取值是失败的,所以要通过断言的方式判断值到底是什么类型。然后针对类型的使用方法 进行取值
package main
import "fmt"
type Addr struct {
address string
iphone string
}
func main() {
var user1 = make(map[string]interface{})
user1["name"] = "bds"
user1["age"] = 18
user1["hobby"] = []string{"games", "睡觉"}
//切片类型
if hobbyValue, ok := user1["hobby"].([]string); ok {
fmt.Println(hobbyValue[1]) //睡觉
}
//切片类型
user1["sw"] = make([]string, 3)
swValue, _ := user1["sw"].([]string)
swValue[0] = "180"
swValue[1] = "120"
//结构体类型
fmt.Println(user1["sw"]) //[180 120 ]
var addr1 = Addr{
address: "bj",
iphone: "13310011",
}
user1["addr"] = addr1
addrValue, _ := user1["addr"].(Addr)
fmt.Println(addrValue.iphone) //13310011
fmt.Println(addrValue.address) //bj
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!