Go语言接口
定义接口
接口又称为动态数据类型,在进行接口使用的的时候,会将接口对位置的动态类型改为所指向的类型,会将动态值改成所指向类型的结构体
//**接口名**为Phone,接口内有speak与read方法即方法名
type Phone interface {
speak()
read()
}
接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。
方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
接口可以让我们将不同的类型绑定到一组公共的方法上,从而实现多态和灵活的设计。
Go 语言中的接口是隐式实现的,也就是说,如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口。因此,我们可以通过将接口作为参数来实现对不同类型的调用,从而实现多态。
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
接口类型变量
接口类型变量能够存储所有实现了该接口的实例。 例如上面的示例中,Sayer类型的变量能够存储dog和cat类型的变量
func main() {
var x Sayer // 声明一个Sayer类型的变量x
a := cat{} // 实例化一个cat
b := dog{} // 实例化一个dog
x = a // 可以把cat实例直接赋值给x
x.say() // 喵喵喵
x = b // 可以把dog实例直接赋值给x
x.say() // 汪汪汪
}
实现接口两种方式的区别
值接受者
使用值接收者,可以将值、指针传进去,但是没有办法修改接受者本身的属性,类似于交换两个值时的值传递
//定义接口
type Phone interface {
speak()
read()
}
//定义结构体类型,作为接受者
type IPhone struct {
name string
}
//对特定的结构体进行接口的实现
func (a IPhone) speak() {
fmt.Println("我叫sir,您好!")
}
指针接收者
使用指针接收者,必须传地址,可以修改指向对象的属性
//定义接口
type Phone interface {
speak()
read()
}
//定义结构体类型,作为接受者
type IPhone struct {
name string
}
//对特定的结构体进行接口的实现
func (a *IPhone) speak() {
fmt.Println("我叫sir,您好!")
}
类型与接口的关系
一个类型实现多个接口
一个类型可以同时实现多个接口,而接口间彼此独立,不知道对方的实现。 例如,狗可以叫,也可以动。我们就分别定义Sayer接口和Mover接口,如下: Mover接口
// Sayer 接口
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
move()
}
多个类型实现同一接口
Go语言中不同的类型还可以实现同一接口 首先我们定义一个Mover接口,它要求必须由一个move方法。
// Mover 接口
type Mover interface {
move()
}
空接口
没有任何方法的接口就是空接口,实际上每个类型都实现了空接口,所以空接口类型可以接受任何类型的数据
//定义一个空接口
type phone interface{}
//空接口作为参数,传进来任意类型参数判断其类型与打印其值
func showmpType(q interface{}) {
fmt.Printf("type:%T,value:%v\n", q, q)
}
类型断言
根据变量不同的类型进行不同的操作
方式一:
有两个返回值,如果断言成功第一个返回值为该变量对应的数据,否则返回该类型的空值,第二个参数是一个布尔值,如果断言成功则返回的是一个true,否则返回false
func judgeType1(q interface{}) {
temp, ok := q.(string)
if ok {
fmt.Println("类型转换成功!", temp)
} else {
fmt.Println("类型转换失败!", temp)
}
}
方式二:
使用switch...case...语句,如果断言成功则到指定分支
func judgeType2(q interface{}) {
switch i := q.(type) {
case string:
fmt.Println("这是一个字符串!", i)
case int:
fmt.Println("这是一个整数!", i)
case bool:
fmt.Println("这是一个布尔类型!", i)
default:
fmt.Println("未知类型", i)
}
}
接口使用较为灵活,可以在实现的接口内进行本类型对象的操作,在接口外部进行接口方法调用,实现相同的代码段有不同的效果,多态的思想也尤为重要