
文章目录1. 接口2. 隐式实现3. 类型断言4. 空接口5. 接口和 nil 值6. 嵌套接口7. 小结本系列文章Java 转 go 学习 - 项目管理Java 转 go 学习 - 基本语法Java 转 go 学习 - 类型转换Java 转 go 学习 - 流程控制结构Java 转 go 学习 - 数组和切片Java 转 go 学习 - mapJava 转 go 学习 - 函数1Java 转 go 学习 - 函数2Java 转 go 学习 - 结构体上一篇文章我们学习了结构体这一篇文章就来看下 Go 中的接口。1. 接口Go 不是面向对象编程语言不像 Java没有类和继承的概念但是和 Java 一样Go 里面也有接口通过接口同样可以实现很多面向对象的特性下面是基本语法。type接口名interface{方法名1(参数)返回值 方法名2(参数)返回值}下面举个例子其实除了语法和 Java 不一样其他大体结构是一样的。typePersoninterface{sayHello()string}2. 隐式实现Go 和 Java 对接口的实现不同Java 如果要实现一个接口得先创建一个 class然后需要显式声明implements Interface实现接口重写里面的方法也是面像对象编程的特点。但是 Go 语言不需要只要一个类型实现了接口中定义的所有方法它就自动实现了该接口这里的实现可以是同包也可以是实现其他包的接口下面举个例子packagemainimportfmt// 1. 定义接口typeAnimalinterface{Speak()string}// 2. 定义结构体typeCatstruct{}typeDogstruct{}// 3. Cat 实现 Speak 方法func(c Cat)Speak()string{returnMeow}// 4. Dog 实现 Speak 方法func(d Dog)Speak()string{returnWoof}// 5. 使用接口作为参数funcMakeSound(s Animal){fmt.Println(s.Speak())}funcmain(){cat:Cat{}dog:Dog{}// 调用具体实现MakeSound(cat)// MeowMakeSound(dog)// Woof}3. 类型断言假设一个接口有多个实现类我们可以通过var.(T)去断言测试var这个接口变量是不是T实现类的可以通过返回值中的第二个 bool 参数去判断是否断言成功下面来看下例子还是上面的几个接口。functest2(){varanimal AnimalCat{}// animal 是不是 Cat 类型的if_,ok:animal.(Cat);ok{fmt.Println(animal type is: Cat)}// animal 是不是 Dog 类型的if_,ok:animal.(Dog);ok{fmt.Println(animal type is: Dog)}// animal type is: Cat}除了这种if-else的写法也可以用switch来判断。functest3(){varanimal AnimalCat{}// t 是转换之后的结构体switcht:animal.(type){caseCat:fmt.Printf(animal type is: Cat, %v\n,t)caseDog:fmt.Printf(animal type is: Dog, %v\n,t)}// animal type is: Cat, {}}4. 空接口如果一个接口没有任何方法也就是interface{}Go 1.18 也可以写成any这种情况就是空接口因为 Go 中的接口是隐式实现所以任何结构体都自动实现了空接口。空接口就类似 Java 的 Object可以存任何类型的值比较常用的如[]interface{}可以存混合类型类似 Java 的ListObject。fmt.Println(v ...interface{})打印不确定类型的参数。解析未知结构的 JSON 时通常用map[string]interface{}。同样的当我们用了空接口之后如果要判断接口值需要用断言。functest4(){variinterface{}Hello// 方式 1: 断言成具体类型, 如果断言失败会 panics:i.(string)fmt.Println(s)// Hello// s : i.(int) - panic: interface conversion: interface {} is string, not int// 方式 2: 安全断言, 接收断言返回值并判断ifs,ok:i.(string);ok{fmt.Printf(字符串: %s\n,s)}else{fmt.Println(不是字符串)}// 字符串: Hello// 方式 3: type switch 处理多种可能switcht:i.(type){casestring:fmt.Println(字符串: ,t)caseint:fmt.Println(整数,t)default:fmt.Println(未知类型)}// 字符串: Hello}5. 接口和 nil 值首先接口本质是一个二元组动态类型动态值当两个部分都为 nil 的时候接口才等于 nil只要其中一个不是 nil接口就不等于 nil。functest5(){vars Animalnilfmt.Println(snil)// truevarp*Catnilsp fmt.Println(snil)// false// panic: value method main.Cat.Speak called using nil *Cat pointer// s.Speak()}下面来看下步骤var s Animal nil声明了一个接口变量此时是一个纯的空接口动态类型和动态值都是 nil。var p *Cat nil; s p声明了一个动态类型*Cat赋值给空接口但是这个指针后面指向的动态值是nil。这个阶段后接口的 动态类型是*Cat动态值是 nil因此判断s nil返回 false。最后调用s.Speak()触发空指针 panic因为动态值是nil。如果想要避免这种情况在方法里面进行下 nil 判断就行。func(c*Cat)Speak(){ifcnil{fmt.Println(Meow from nil cat!)return}fmt.Println(Meow! My name is,c.Name)}6. 嵌套接口嵌套接口意思就是 Go 中接口可以嵌入其他接口意味者一个接口可以继承现有接口的所有方法然后添加自己的方法。typeNewInterfaceinterface{ExistingInterface// 嵌入现有接口NewMethod()// 添加新方法}上面的 NewInterface 就是继承了ExistingInterface的所有方法同时加上自己的方法NewMethod所以如果要实现 NewInterface 接口必须实现 ExistingInterface 的所有方法 加上 NewMethod。这种写法本质上就是将各个接口组合在一起。下面就来看一个例子首先我们定义两个小接口。// 1. 定义两个小接口typeFlyerinterface{Fly()}typeSwimmerinterface{Swim()}下面在定义一个大接口组合两个小接口。typeFlyingSwimmerinterface{Flyer Swimmer}接下来定义两个结构体一个实现FlyingSwimmer一个只实现Flyer。// 3. duck 实现大接口typeDuckstruct{}func(d*Duck)Fly(){fmt.Println(duck can fly)}func(d*Duck)Swim(){fmt.Println(duck can swim)}// 4. Eagle 只实现 Fly 接口typeEaglestruct{}func(e*Eagle)Fly(){fmt.Println(eagle can fly)}然后再定义一个函数参数是 FlyAndSwim 接口。funcFlyAndSwim(f FlyingSwimmer){f.Swim()f.Fly()}最后测试如下。functest6(){// eagle : Eagle{}// FlyAndSwim(eagle) // 报错 Type does not implement FlyingSwimmer as some methods are missingduck:Duck{}FlyAndSwim(duck)// duck can swim// duck can fly}可以看到由于 eagle 只实现了 Fly 方法也就是说 eagle 只实现了 Flyer没有实现 FlyingSwimmer所以传入 FlyAndSwim 会报错Type does not implement FlyingSwimmer as some methods are missing而 duck 两个方法都实现了所以能够正常调用。那下面我们再加一个函数这个函数接收Flyer接口调用Fly方法。funcFlyPrint(f Flyer){f.Fly()}然后测试。functest6(){// eagle : Eagle{}// FlyAndSwim(eagle) // 报错 Type does not implement FlyingSwimmer as some methods are missing:duck:Duck{}FlyPrint(duck)// duck can fly}可以看到实现了FlyAndSwim接口的结构体可以传入FlyPrint中也就是大接口可以作为参数传入小接口因为实现了大接口一定实现了小接口而实现小接口不一定实现大接口。7. 小结好了到这里接口部分就先结束下面再来看下并发编程的部分。如有错误欢迎指出