1.接口的介绍与定义
1.定义
- 接口定义了一个对象的行为规范
- A:只定义规范,不实现
- B:具体的对象需要实现规范的细节
2.表现形式
- 1.type 接口名字 interface
- 2.接口里面是一组方法签名的集合
type Animal interface {
Talk()
Eat()
Run()
}
3.实现
- 1.一个对象只要包含接口中的方法,那么就实现了这个接口
- 2.接口类型的变量可以保存具体类型的实例
4.实例
- 1.一个公司需要计算所有职员的薪水
- 2.每个职员的薪水计算方式不同
package main
import "fmt"
// 定义一个员工的接口,接口中定义CalcSalary方法
type Employer interface {
CalcSalary() float64
}
// 函数:实现所有员工薪水的统计
func calcAll(e []Employer) float64 {
var cost float64
for _, v := range e {
cost += v.CalcSalary()
}
return cost
}
type Programmer struct {
name string
base float64
extra float64
}
// 为Programmer对象添加接口Employer中定义的CalcSalary方法
// Programmer对象实现了Employer接口
func (p *Programmer) CalcSalary() float64 {
return p.base
}
// 构造一个程序员
func NewProgrammer(name string, base float64, extra float64) *Programmer {
return &Programmer{
name: name,
base: base,
extra: extra,
}
}
type Seller struct {
name string
base float64
extra float64
}
func (s *Seller) CalcSalary() float64 {
return s.base + s.Sales * s.ratio
}
func NewSeller(name string, base, Sales, ratio float64) *Seller {
return &Seller{
name: name,
base: base,
Sales: Sales,
ratio: ratio,
}
}
func main() {
p1 := NewProgrammer("小李", 12000, 0)
p2 := NewProgrammer("小王", 8000, 0)
p3 := NewProgrammer("小胡", 8500, 0)
s1 := NewSeller("张倩", 4500, 12000, 0.06)
s2 := NewSeller("王艳", 4500, 8000, 0.04)
s3 := NewSeller("李梅", 4500, 5600, 0.03)
var employerList []Employer
employerList = append(employerList, p1)
employerList = append(employerList, p2)
employerList = append(employerList, p3)
employerList = append(employerList, s1)
employerList = append(employerList, s2)
employerList = append(employerList, s3)
cost := calcAll(employerList)
fmt.Println(cost)
}
5.接口类型的变量
- 1.
Var a Animal
- 2.那么
a能够存储所有实现Animal接口的实例
package main
import "fmt"
type Animal interface {
Eat()
}
type Dog struct {
Name string
}
// 值类型实现Dog对象方法 ------> 引用类型实现 fun(d *Dog)
func (d Dog) Eat() {
fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}
type Cat struct {
Name string
}
func (c Cat) Eat() {
fmt.Printf("小猫%s正在吃鱼\n", c.Name)
}
func main() {
var a Animal
var dog Dog
var cat Cat
a = dog
a.Eat()
a = cat
a.Eat()
}
2.空接口和类型断言
1.空接口
- 1.空接口没有定义任何方法
- 2.所以任何类型都实现了空接口
var a interface{}
var b []byte
a = b
fmt.Println(a) // []
var c map[string]int
a = c
fmt.Println(a) // map[]
var d rune
a = d
fmt.Println(a) // 0
package main
import "fmt"
func describe(a interface{}) {
fmt.Printf("%T %v\n", a, a)
}
type Stu struct {
Name string
Age int
}
func main() {
inta := 65
describe(inta) // int 65
var stu = Stu{
Name: "小亮",
Age: 23,
}
describe(stu) // main.Stu {小亮 23}
}
2.类型断言
- 1.如何获取
接口类型里面存储的具体的值呢:a.(T)
func describe(a interface{}) {
v, ok := a.(int)
if ok {
fmt.Println(v)
} else {
fmt.Printf("%T %v\n", a, a)
}
}
// 两次调用a.(type)
func describe(a interface{}) {
switch a.(type) {
case string:
fmt.Printf("a is string, value:%v\n", a.(string))
case int:
fmt.Printf("a is int, value:%v\n", a.(int))
case map[string]int:
fmt.Printf("a is map, value:%v\n", a.(map[string]int))
default:
fmt.Println("不支持的类型")
}
}
// 优化写法(推荐)
func describe(a interface{}) {
switch v := a.(type) {
case string:
fmt.Printf("a is string, value:%v\n", v)
case int:
fmt.Printf("a is int, value:%v\n", v)
case map[string]int:
fmt.Printf("a is map, value:%v\n", v)
default:
fmt.Println("不支持的类型")
}
}
- 3.既然所有类型都实现了空接口,那我们是否可以使用接口类型做判断,大胆尝试
package main
import "fmt"
func describe(a interface{}) {
// 使用接口类型取值(可以取到)
fmt.Println(a.(interface{}))
}
func main() {
inta := 65
describe(inta) // 65
type Stu struct {
Name string
Age int
}
var stu = Stu{
Name: "小亮",
Age: 23,
}
describe(stu) // {小亮 23}
var m map[string]int
describe(m) // map[]
}
package main
import "fmt"
type Animal interface {
Eat()
}
type Dog struct {
}
func (d Dog) Eat() {
fmt.Println("小狗正在啃骨头")
}
type Cat struct {
}
func (c *Cat) Eat() {
fmt.Println("小猫正在吃鱼")
}
func main() {
var dog Dog
var cat Cat
describe(dog)
describe(cat)
}
func describe(a Animal) {
switch v := a.(type) {
case Dog:
fmt.Printf("a is dog, value: %v\n", v) // a is dog, value: {}
case Cat:
fmt.Printf("a is cat, value: %v\n", v) // a is cat, value: {}
default:
fmt.Println("不支持的类型")
}
}
3.指针接收和值接收区别
1.值类型
package main
import "fmt"
type Animal interface {
Eat()
}
type Dog struct {
Name string
}
// 值类型实现Dog对象方法 ------> 引用类型实现 fun(d *Dog)
func (d Dog) Eat() {
fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}
func main() {
var a Animal
// Dog值类型实现了Eat方法,所以可以直接调用
dog := Dog{Name: "小花"}
a = dog
a.Eat()
// Dog引用类型没有实现Eat方法,为什么也可以调用Eat方法
dog1 := &Dog{Name: "小黄"}
a = dog1
a.Eat() // 首先从接口里面取出来是一个&Dog地址,然后将地址取值*Dog,找到对应的Eat接口方法,然后i调用
}
// 小狗小花正在啃骨头
// 小狗小黄正在啃骨头
2.指针类型
package main
import "fmt"
type Animal interface {
Eat()
}
type Dog struct {
Name string
}
func (d *Dog) Eat() {
fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}
func main() {
var a Animal
//dog := Dog{Name: "小花"}
/*
假设a里面存储的是一个值类型的Dog,那么调用a.Eat的时候,由于指针类型实现了这个接口,
则要先取a存储Dog的地址,获取到&Dog后,才可以调用
总结:如果一个变量存储在接口类型的变量中之后,那么不能获取这个变量的地址
//a = dog // 报错,值类型的Dog没有实现Animal接口类型中的Eat方法
//a.Eat()
*/
dog1 := &Dog{Name: "小黄"}
a = dog1
a.Eat()
}
4.同一个类型(结构体)可以实现多个接口
- 一个合格的程序员,可以使用
gin|django|express|spring等框架进行开发
package main
import "fmt"
type Java interface {
Spring()
}
type Python interface {
Django()
}
type Node interface {
Express()
}
type Go interface {
Gin()
}
type Person struct {
}
func (p *Person) Spring() {
fmt.Println("我会用java语言的spring框架写网站")
}
func (p *Person) Express() {
fmt.Println("我会用node语言的express框架写网站")
}
func (p *Person) Django() {
fmt.Println("我会用python语言的django框架写网站")
}
func (p *Person) Gin() {
fmt.Println("我会用Go语言的gin框架写网站")
}
func main() {
var java Java // nil
var python Python // nil
var g Go // nil
var node Node nil
var p Person
java = &p
java.Spring()
python = &p
python.Django()
g = &p
g.Gin()
node = &p
node.Express()
}
5.接口嵌套
package main
import "fmt"
type Java interface {
Spring()
}
type Python interface {
Django()
}
type Node interface {
Express()
}
type Go interface {
Gin()
}
type SeniorEngineer interface { // 高级工程师
Java
Python
Node
Go
}
type MidLevelEngineer interface { // 中级工程师
Go
Java
}
type JuniorEngineer interface { // 初级工程师
Python
}
type Person struct {
}
func (p *Person) Spring() {
fmt.Println("我会用java语言的spring框架写网站")
}
func (p *Person) Express() {
fmt.Println("我会用node语言的express框架写网站")
}
func (p *Person) Django() {
fmt.Println("我会用python语言的django框架写网站")
}
func (p *Person) Gin() {
fmt.Println("我会用Go语言的gin框架写网站")
}
func main() {
fmt.Println("-------------------高级工程师-------------------")
var p Person
var sen SeniorEngineer
sen = &p
sen.Express()
sen.Gin()
sen.Django()
sen.Spring()
fmt.Println("-------------------中级工程师-------------------")
var mid MidLevelEngineer
mid = &p
mid.Spring()
mid.Gin()
fmt.Println("-------------------初级工程师-------------------")
var jun JuniorEngineer
jun = &p
jun.Django()
}
/*
-------------------高级工程师-------------------
我会用node语言的express框架写网站
我会用Go语言的gin框架写网站
我会用python语言的django框架写网站
我会用java语言的spring框架写网站
-------------------中级工程师-------------------
我会用java语言的spring框架写网站
我会用Go语言的gin框架写网站
-------------------初级工程师-------------------
我会用python语言的django框架写网站
*/
6.多态
1.表现形式
![]()
package main
import "fmt"
type Code string
type Programmer interface {
WriteHelloWorld() Code
}
type GoProgrammer struct {
}
func (p GoProgrammer) WriteHelloWorld() Code {
return "fmt.Println(\"Hello World!\")"
}
type JavaProgrammer struct {
}
func (p JavaProgrammer) WriteHelloWorld() Code {
return "System.out.Println(\"Hello World!\")"
}
// 统一入口
func writeFirstProgram(p Programmer) {
// Programmer是一个interface对象,所以其实例只能是指针类型
fmt.Printf("%T %v\n", p, p.WriteHelloWorld())
}
func main() {
writeFirstProgram(new(GoProgrammer))
writeFirstProgram(new(JavaProgrammer))
}
7.注意
interface类型对应的实例只能是指针类型
![]()