Skip to content

1. golang接口

接口像是一个公司里面的领导,他会定义一些通用规范,只设计规范,而不实现规范

go语言的接口,是一种新的类型定义,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

  • 同一个结构体可以实现多个接口
  • 接口可以嵌套
  • 关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同方式进行处理的才需要定义接口。不要为了接口而定义接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。

语法格式和方法非常类似

1.1 接口的语法格式

  • 接口命名习惯以er结尾

  • 接口只有方法声明,没有实现,没有数据字段

  • 接口可以匿名嵌入其他接口,或嵌入到结构中

go
/* 定义接口*/

type interface_name interface {
    method_name1 [return_type]
    method_name2 [return_type]
    ....
}

/* 定义结构体 */
type struct_name struct {
    /* variables */
}

/* 实现接口方法*/
func (struc_name_variable struct_name) method_name1() [return_type]{
    /*方法实现*/
}
/* 定义接口*/

type interface_name interface {
    method_name1 [return_type]
    method_name2 [return_type]
    ....
}

/* 定义结构体 */
type struct_name struct {
    /* variables */
}

/* 实现接口方法*/
func (struc_name_variable struct_name) method_name1() [return_type]{
    /*方法实现*/
}
  • 例子
go
package main

import "fmt"

type USBer interface {
	read()
	write()
}
type Computer struct {
	name string
}

func (c Computer) read() {
	fmt.Printf("c.name: %v\n", c.name)
	fmt.Println("read...")
}

func (c Computer) write() {
	fmt.Printf("c.name: %v\n", c.name)
	fmt.Println("write...")
}

func main() {
	c := Computer{
		"Lenvo",
	}
	c.read()
	c.write()

}

//结果
c.name: Lenvo
read...
c.name: Lenvo
write...
package main

import "fmt"

type USBer interface {
	read()
	write()
}
type Computer struct {
	name string
}

func (c Computer) read() {
	fmt.Printf("c.name: %v\n", c.name)
	fmt.Println("read...")
}

func (c Computer) write() {
	fmt.Printf("c.name: %v\n", c.name)
	fmt.Println("write...")
}

func main() {
	c := Computer{
		"Lenvo",
	}
	c.read()
	c.write()

}

//结果
c.name: Lenvo
read...
c.name: Lenvo
write...

实现接口必须实现接口中的所有方法

接口实现

接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是由用户定义的类型实现,一个实现了这些方法的具体类型是这个接口类型的实例。

如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型的值。

1.2 值类型接收者和指针类型接收者

本质上和方法的值类型和指针类型接收者是一样的,值接收者是一个拷贝,是一个副本,而指针接收者,传递的是指针。

go
package main

import "fmt"

type Pet interface {
	eat(string) string
}
type Dog struct {
	name string
}

func (dog Dog) eat(name string) string {
	dog.name = "花花。。。"
	fmt.Printf("name: %v\n", name)
	return "吃的不错"
}
func main() {
	dog := Dog{
		"花花",
	}
	s := dog.eat("火鸡")
	fmt.Printf("s: %v\n", s)
	fmt.Printf("dog: %v\n", dog)

}

//结果
name: 火鸡
s: 吃的不错
dog: {花花}
package main

import "fmt"

type Pet interface {
	eat(string) string
}
type Dog struct {
	name string
}

func (dog Dog) eat(name string) string {
	dog.name = "花花。。。"
	fmt.Printf("name: %v\n", name)
	return "吃的不错"
}
func main() {
	dog := Dog{
		"花花",
	}
	s := dog.eat("火鸡")
	fmt.Printf("s: %v\n", s)
	fmt.Printf("dog: %v\n", dog)

}

//结果
name: 火鸡
s: 吃的不错
dog: {花花}
  • 指针类型
go
package main

import "fmt"

type Pet interface {
	eat(string) string
}
type Dog struct {
	name string
}

/*
	func (dog Dog) eat(name string) string {
		dog.name = "花花。。。"
		fmt.Printf("name: %v\n", name)
		return "吃的不错"
	}
*/
func (dog *Dog) eat(name string) string {
	dog.name = "花花。。。"
	fmt.Printf("name: %v\n", name)
	return "吃的不错"
}

func main() {
	dog := &Dog{
		"花花",
	}
	s := dog.eat("火鸡")
	fmt.Printf("s: %v\n", s)
	fmt.Printf("dog: %v\n", dog)

}
package main

import "fmt"

type Pet interface {
	eat(string) string
}
type Dog struct {
	name string
}

/*
	func (dog Dog) eat(name string) string {
		dog.name = "花花。。。"
		fmt.Printf("name: %v\n", name)
		return "吃的不错"
	}
*/
func (dog *Dog) eat(name string) string {
	dog.name = "花花。。。"
	fmt.Printf("name: %v\n", name)
	return "吃的不错"
}

func main() {
	dog := &Dog{
		"花花",
	}
	s := dog.eat("火鸡")
	fmt.Printf("s: %v\n", s)
	fmt.Printf("dog: %v\n", dog)

}

1.3 接口和类型的关系

1.一个类型可以实现多个接口

2.多个类型可以实现同一个接口(多态)

  • 一个类型可以实现多个接口
go
package main

import "fmt"

type Player interface {
	playMusic()
}
type Video interface {
	playVideo()
}
type Mobile struct {
}

func (m Mobile) playMusic() {
	fmt.Println("play music...")
}
func (m Mobile) playVideo() {
	fmt.Println("play video...")
}
func main() {
	m := Mobile{}
	m.playVideo()
	m.playMusic()
}
package main

import "fmt"

type Player interface {
	playMusic()
}
type Video interface {
	playVideo()
}
type Mobile struct {
}

func (m Mobile) playMusic() {
	fmt.Println("play music...")
}
func (m Mobile) playVideo() {
	fmt.Println("play video...")
}
func main() {
	m := Mobile{}
	m.playVideo()
	m.playMusic()
}
  • 多个类型可以实现同一个接口(多态)
go
package main

import "fmt"

type Pets interface {
	eat()
}
type Dogs struct {
}
type Cats struct {
}

func (dog Dogs) eat() {
	fmt.Println("dog eat...")
}
func (cat Cats) eat() {
	fmt.Println("cat eat...")
}
func main() {
	/*dog := Dogs{}
	cat := Cats{}
	dog.eat()
	cat.eat()*/
	var pet Pets
	pet = Dogs{}
	pet.eat()
	pet = Cats{}
	pet.eat()    
}
package main

import "fmt"

type Pets interface {
	eat()
}
type Dogs struct {
}
type Cats struct {
}

func (dog Dogs) eat() {
	fmt.Println("dog eat...")
}
func (cat Cats) eat() {
	fmt.Println("cat eat...")
}
func main() {
	/*dog := Dogs{}
	cat := Cats{}
	dog.eat()
	cat.eat()*/
	var pet Pets
	pet = Dogs{}
	pet.eat()
	pet = Cats{}
	pet.eat()    
}

https://www.bilibili.com/video/BV1zR4y1t7Wj?p=60&spm_id_from=pageDriver&vd_source=271cfb4bb43eae8c9b0543f4ae14ec31

1.4 接口嵌套

接口可以通过嵌套,创建新的接口。

go
package main

import "fmt"

type Flyer interface {
	fly()
}
type Swimmer interface {
	swim()
}

// 接口组合
type FlyFish interface {
	Flyer
	Swimmer
}
type Fish struct {
}

func (fish Fish) fly() {
	fmt.Println("fish fly...")
}
func (fish Fish) swim() {
	fmt.Println("fish swim...")
}

func main() {
	var ff FlyFish
	ff = Fish{}
	ff.swim()
	ff.fly()
}
package main

import "fmt"

type Flyer interface {
	fly()
}
type Swimmer interface {
	swim()
}

// 接口组合
type FlyFish interface {
	Flyer
	Swimmer
}
type Fish struct {
}

func (fish Fish) fly() {
	fmt.Println("fish fly...")
}
func (fish Fish) swim() {
	fmt.Println("fish swim...")
}

func main() {
	var ff FlyFish
	ff = Fish{}
	ff.swim()
	ff.fly()
}

1.5 接口实现ocp设计原则

而面向对象的可复用设计的第一块基石,便是所谓的“开-闭”原则(Open-Closed Principle,常缩写为OCP)。虽然go不是面向对象的语言,但是也可以模拟实现这个原则。即,对代码扩展是开放的,对代码已写好的修改是关闭的

go
package main

import "fmt"

type Pet9 interface {
	eat()
	sleep()
}
type Cat struct {
}
type Dog9 struct {
}

// dog实现Pet接口
func (dog Dog9) eat() {
	fmt.Println("dog eat...")
}
func (dog Dog9) sleep() {
	fmt.Println("dog sleep...")
}

// cat 实现Pet接口
func (cat Cat) eat() {
	fmt.Println("cat eat...")
}
func (cat Cat) sleep() {
	fmt.Println("cat sleep...")
}

type Persons struct {
}

// pet既可以传递cat ,既可以传递Dog
func (person Persons) care(pet Pet9) {
	pet.eat()
	pet.sleep()
}

func main() {
	dog := Dog9{}
	cat := Cat{}
	person := Persons{}
	person.care(dog)
	person.care(cat)
}
package main

import "fmt"

type Pet9 interface {
	eat()
	sleep()
}
type Cat struct {
}
type Dog9 struct {
}

// dog实现Pet接口
func (dog Dog9) eat() {
	fmt.Println("dog eat...")
}
func (dog Dog9) sleep() {
	fmt.Println("dog sleep...")
}

// cat 实现Pet接口
func (cat Cat) eat() {
	fmt.Println("cat eat...")
}
func (cat Cat) sleep() {
	fmt.Println("cat sleep...")
}

type Persons struct {
}

// pet既可以传递cat ,既可以传递Dog
func (person Persons) care(pet Pet9) {
	pet.eat()
	pet.sleep()
}

func main() {
	dog := Dog9{}
	cat := Cat{}
	person := Persons{}
	person.care(dog)
	person.care(cat)
}

1.6 模拟oop的属性和方法

golang没有面向对象的概念,也没有封装的概念,但是可以通过结构体struct和函数绑定来实现oop的属性和方法等特性。接收者receiver方法。

例如,定义一个Person类,有name和age属性,有eat/sleep/work方法。

go
package main

import "fmt"

type Person11 struct {
	name string
	age  int
}

func (per Person11) eat() {
	fmt.Println("eat...")
}

func (per Person11) sleep() {
	fmt.Println("sleep...")
}
func (per Person11) work() {
	fmt.Println("work...")
}

func main() {
	per := Person11{
		"tom",
		20,
	}
	fmt.Printf("per: %v\n", per)
	per.eat()
	per.sleep()
	per.work()
}
package main

import "fmt"

type Person11 struct {
	name string
	age  int
}

func (per Person11) eat() {
	fmt.Println("eat...")
}

func (per Person11) sleep() {
	fmt.Println("sleep...")
}
func (per Person11) work() {
	fmt.Println("work...")
}

func main() {
	per := Person11{
		"tom",
		20,
	}
	fmt.Printf("per: %v\n", per)
	per.eat()
	per.sleep()
	per.work()
}

2. 接口断言