目录
1、为什么interface{}函数可以保存任何类型的数据
这个需要从接口的本质说起,理解了本质就知道为什么了。
在go语言当中,interface是一种类型,同时也是一种抽象,一种结构。 内部是一组函数的集合。如果一个结构体实现了这个接口,也就是说 一个结构体的所有的方法当中,函数的名称、入参和出参与interface接口内部方法相同,签名相同。那么这个结构体就实现了这个接口库。
实现了之后,对象结构体的实例就可以当做变量传递给接口变量,接口变量就可以调用结构体的方法,来实现结构体自己的方法逻辑。
案例:
package main
import "fmt"
type Messager interface {
Send()
}
type Msg struct {
Content string
}
func (s *Msg) Send() {
fmt.Printf("dear,%s", s.Content)
}
func NewMsg(content string) *Msg {
return &Msg{
Content: content,
}
}
func main() {
msg := NewMsg("how are you doing today")
var msger Messager
msger = msg
msger.Send()
// >>> dear,how are you doing today
}
示例代码当中,接口提Msg 实现了Messager 的接口,接口Messager 一共就只有一个 Send 的方法。所以 Msg 的实例对象就可以给 Messager 实例进行通过值的方式去传递。赋值给Messager 实例。
假设,有一个接口,这个接口 里面没有任何方法,就长像下面这样:
type Demo interface {
}
就是说,这个接口没有方法,所有的对象不需要满足接口方法签名就已经实现了它,所以 任何对象都可以 赋值给它。
案例:
package main
import (
"fmt"
)
type Super interface {
}
type Person struct {
Name string
}
func (p *Person) Eat() {
fmt.Printf("%s is eating", p.Name)
}
type Animal struct {
Name string
}
func (a *Animal) Run() {
fmt.Printf("%s is running", a.Name)
}
func main() {
var su1 Super
var su2 Super
pepple := &Person{"老王"}
animal := &Animal{"老虎"}
su1 = pepple
res := su1.(*Person)
fmt.Printf("su 中保存的是:%v\n", res)
su2 = animal
info := su2.(*Animal)
fmt.Printf("su 中保存的是:%v\n", info)
}
'''
>>>
su 中保存的是:&{老王}
su 中保存的是:&{老虎}
'''
我们看Super 接口可以保存不同类型的结构,不仅可以保存Pepple,还可以保存Animal. 就是这个原因。任何类型都可以保存。
2、interface 类型的数据如何转化为其他类型的数据
比如下面代码就会报错
package main
import "fmt"
func Add(a, b interface{}) int {
return a + b
}
func main() {
res := Add(3, 8)
fmt.Println(res)
}
.\main.go:7:9: invalid operation: operator + not defined on a (variable of type interface{})
经常会遇到类似的场景。原因其实是这样,因为虽然interface可以保存任何类型数据,但是 还是interface 类型,你需要转化为原有数据类型才能进行其他操作。
如何做呢?
只需要通过类型断言的方法就可以获取到接口保存的值。
完整代码如下
package main
import "fmt"
func Add(a, b interface{}) int {
num1 := a.(int)
num2 := b.(int)
return num1 + num2
}
func main() {
res := Add(3, 8)
fmt.Println(res)
}
''' output
>>>
11
'''
3、是不是所有的参数都能定义为interface类型?
其实通过空接口保存数据,从效率层面来说是比较慢的,如果参数类型确定,肯定是对应的类型比较合适,所以见多一些为了拓展性和兼容性,全部都是interface类型的参数,你怎么看?
4、什么情况下 需要抽象interface接口
如果需求不会设计很多类场景,功能相同,但是逻辑不通,比较单一,那么结构体方法就够了。
但是是如果涉及到很多不同的业务逻辑,比如同样是发消息,有发短息,发微信,邮件,企业微信登,这样的场景 就可以抽象通用接口。然后用不同的结构体去实现自己不同的逻辑。