这篇文章主要讲解了“Golang接口的定义与空接口及断言怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang接口的定义与空接口及断言怎么使用”吧!
在Go语言中接口(interface)是一种类型,一种抽象的类型。
接口(interface)定义了一个对象的行为规范, 只定义规范不实现 ,由具体的对象来实现规范的细节 。
实现接口的条件:
一个对象只要全部实现了接口中的方法 ,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。
下面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码
如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去
那我们能不能把它们当成“能叫的动物”来处理呢?
type Cat struct { Name string } func (c Cat) Say() string { return c.Name + ":喵喵喵" } type Dog struct { Name string } func (d Dog) Say() string { return d.Name + ": 汪汪汪" } func main() { c := Cat{Name: "小白猫"} // 小白猫:喵喵喵 fmt.Println(c.Say()) d := Dog{"阿黄"} fmt.Println(d.Say()) // 阿黄: 汪汪汪 } /* 小白猫:喵喵喵 阿黄: 汪汪汪 */
定义一个 Usber 接口让 Phone 和 Computer 结构体实现这个接口
//1.接口是一个规范 type Usber interface { getName() string } //2.如果接口里面有方法的话,必要要通过结构体或者通过自定义类型实现这个接口 type Phone struct { Name string } type Computer struct { Brand string } func (c *Computer) getName() string { return c.Brand } //3.手机要实现usb接口的话必须得实现usb接口中的所有方法 func (p *Phone) getName() string { return p.Name } func main() { p := &Phone{ Name: "华为手机", } c := &Computer{ Brand: "联想电脑", } var p1 Usber // golang中接口就是一个数据类型 p1 = p // 表示手机实现Usb接口 fmt.Println(p1.getName()) //接口使用场景,处理相同类型的数据 newName := transData(p) newName1 := transData(c) fmt.Println(newName, newName1) } func transData(usber Usber) string { name := usber.getName() return fmt.Sprintf("%s%s", name, "处理后") }
当我们要去处理同一数据类型的时候这个数据的时候,比如猫 狗是同一类数据类型。
像k8s的deployment,pod,configmap,secretd等等这些资源的时候,它都是k8s的一个资源,在获取列表的时候会对其做数据处理,比如要对其进行数据排序,那么只需要对这个接口进行排序就行了,不需要对每个资源都去写一遍排序的方法,那么这样不是很冗余吗?
Golang中空接口也可以直接当做类型来使用,可以表示任意类型 (泛型概念,最大的特点)
Golang 中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口。
空接口表示没有任何约束,因此任何类型变量都可以实现空接口。
空接口在实际项目中用的是非常多的,用空接口可以表示任意数据类型
//空接口作为函数的参数 func show(a interface{}) { fmt.Printf("值:%v 类型:%T\n", a, a) } func main() { show(20) // 值:20 类型:int show("你好golang") // 值:你好golang 类型:string slice := []int{1, 2, 34, 4} show(slice) // 值:[1 2 34 4] 类型:[]int }
printf println是可以接受任何参数的,func Printf(format string , a ...interface{})可以看到这里可以接受任何空接口类型,...类似于切片类型。
func test(a int, b ...interface{}) { for _, v := range b { fmt.Printf("%v,%T \n", v, v) } } func main() { test(1, "a", 22, []string{"1"}) } a,string 22,int [1],[]string
切片和map是同一类型的元素,有了空接口,在同一个切片同一个map中就可以将任何类型的数据放进去。
func main() { var slice = []interface{}{"张三", 20, true, 32.2} fmt.Println(slice) // [张三 20 true 32.2] }
func main() { // 空接口作为 map 值 var studentInfo = make(map[string]interface{}) studentInfo["name"] = "张三" studentInfo["age"] = 18 studentInfo["married"] = false fmt.Println(studentInfo) // [age:18 married:false name:张三] }
类型断言(从上往下转换,接口类型转化为具体类型)
一个接口的值(简称接口值)是由一个具体类型和具体类型的值两部分组成的。
这两部分分别称为接口的动态类型和动态值。(一个空接口,可以是结构体,指针,布尔各种类型。它其实是动态的,你传递什么都可以,这就叫做动态类型和动态值)
如果我们想要判断空接口中值的类型,那么这个时候就可以使用类型断言
其语法格式: x.(T)
x : 表示类型为 interface{}的变量
T : 表示断言 x 可能是的类型
断言返回两个值,一个是断言是否转化成果,一个是转化结果,注意空接口类型是空接口类型。
var str interface{} str = "hello" str = str + "sss" //这样写是会报错的,因为空接口类型不是字符串类型,需要断言转化才可以
type test1 struct { name string age int } func main() { var t interface{} //未断言前没有结构体的特征,需要断言转化为结构体指针 t = &test1{ name: "hh", age: 12, } v, ok := t.(*test1) //这里其实就是做了一个类型转化,这里的类型就变为来结构体指针类型 if ok { fmt.Printf("类型:%T 值:%#v\n", v, v) } else { fmt.Println("xxx") } } 类型:*main.test1 值:&main.test1{name:"hh", age:12}
转化为具体类型之后,那么具体类型的方法是都可以去调用的,空接口是不能访问属性和方法的。转化为具体的类型之后就可以访问其属性和方法。
值接收者和指针接收者(节省内存)
当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。
在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。
type Usb interface { Start() Stop() } type Phone struct { Name string } func (p Phone) Start() { fmt.Println(p.Name, "开始工作") } func (p Phone) Stop() { fmt.Println("phone 停止") } func main() { phone1 := Phone{ // 一:实例化值类型 Name: "小米手机", } var p1 Usb = phone1 //phone1 实现了 Usb 接口 phone1 是 Phone 类型 p1.Start() phone2 := &Phone{ // 二:实例化指针类型 Name: "苹果手机", } var p2 Usb = phone2 //phone2 实现了 Usb 接口 phone2 是 *Phone 类型 p2.Start() //苹果手机 开始工作 }
指针类型的接收者由一个结构体的指针组成
由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。
这种方式就十分接近于其他语言中面向对象中的 this 或者 self 。
例如我们为 Person 添加一个 SetAge 方法,来修改实例变量的年龄。
使用时机
注:并不是所有情况下都希望修改数据
需要修改接收者中的值
接收者是拷贝代价比较大的大对象
保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。
从使用场景上面来说,基本上都会使用指针,如果使用了第三方的包,第三方包的某些返回值它只是一个值类型,所以第三方类型返回什么类型我们就使用什么类型,针对第三方包。
感谢各位的阅读,以上就是“Golang接口的定义与空接口及断言怎么使用”的内容了,经过本文的学习后,相信大家对Golang接口的定义与空接口及断言怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。