【原创】go语言学习(十六)接口

目录

  • 接口介绍与定义
  • 空接口和类型断言
  • 指针接收和值接收区别
  • 接口嵌套

接口介绍与定义

1、 接口定义了一个对象的行为规范

A. 只定义规范,不实现
B. 具体的对象需要实现规范的细节

2、Go中接口定义

A. type 接口名字 interface
B. 接口里面是一组方法签名的集合

type Animal interface {
    Talk()
    Eat() int
    Run()
}

  

3、Go中接口的实现

A. 一个对象只要包含接口中的方法,那么就实现了这个接口
B. 接口类型的变量可以保存具体类型的实例

type Animal interface {
    Talk()
    Eat() int
    Run()
}

  

4、接口实例

A. 一个公司需要计算所有职员的薪水
B. 每个职员的薪水计算方式不同

package main

import (
	"fmt"
)

type Employer interface {
	CalcSalary() float32
}

type Programer struct {
	name  string
	base  float32
	extra float32
}

func NewProgramer(name string, base float32, extra float32) Programer {
	return Programer{
		name:  name,
		base:  base,
		extra: extra,
	}
}

func (p Programer) CalcSalary() float32 {
	return p.base
}

type Sale struct {
	name  string
	base  float32
	extra float32
}

func NewSale(name string, base, extra float32) Sale {
	return Sale{
		name:  name,
		base:  base,
		extra: extra,
	}
}

func (p Sale) CalcSalary() float32 {
	return p.base + p.extra*p.base*0.5
}

func calcALL(e []Employer) float32 {
	var cost float32
	for _, v := range e {
		cost = cost + v.CalcSalary()
	}

	return cost
}

func main() {
	p1 := NewProgramer("搬砖1", 1500.0, 0)
	p2 := NewProgramer("搬砖2", 1500.0, 0)
	p3 := NewProgramer("搬砖3", 1500.0, 0)

	s1 := NewSale("销售1", 800.0, 2.5)
	s2 := NewSale("销售2", 800.0, 2.5)
	s3 := NewSale("销售3", 800.0, 2.5)

	var employList []Employer
	employList = append(employList, p1)
	employList = append(employList, p2)
	employList = append(employList, p3)

	employList = append(employList, s1)
	employList = append(employList, s2)
	employList = append(employList, s3)

	cost := calcALL(employList)
	fmt.Printf("这个月的人力成本:%f\n", cost)

}

  

5、接口类型变量

A. var a Animal
B. 那么a能够存储所有实现Animal接口的对象实例

package main

import "fmt"

type Animal interface {
	Talk()
	Eat()
	Name() string
}

type Dog struct {
}

func (d Dog) Talk() {
	fmt.Println("汪汪汪")
}

func (d Dog) Eat() {
	fmt.Println("我在吃骨头")
}

func (d Dog) Name() string {
	fmt.Println("我的名字叫旺财")
	return "旺财"
}

type Pig struct {
}

func (d Pig) Talk() {
	fmt.Println("坑坑坑")
}

func (d Pig) Eat() {
	fmt.Println("我在吃草")
}

func (d Pig) Name() string {
	fmt.Println("我的名字叫八戒")
	return "八戒"
}

func testInterface1() {
	var d Dog
	var a Animal
	a = d

	a.Eat()
	a.Talk()
	a.Name()

	var pig Pig
	a = pig
	a.Eat()
	a.Talk()
	a.Name()
}

func just(a Animal) {
	// d, ok := a.(Dog)
	// p, ok := a.(Pig)
	switch v := a.(type) {
	case Dog:
		fmt.Printf("v is dog, %v\n", v)
	case Pig:
		fmt.Printf("v is dog, %v\n", v)
	default:
		fmt.Printf("not support")
	}
}

func testInterface2() {
	var d Dog
	just(d)
}

func main() {
	//testInterface1()
	testInterface2()
}

  

空接口和类型断言

1、空接口

A. 空接口没有定义任何方法
B. 所以任何类型都实现了空接口

interface {
}

  

package main

import "fmt"

func describe(a interface{}) {
	fmt.Printf("%T %v\n", a, a)
}

func testInterface() {
	var a interface{}
	var b int = 100
	a = b

	fmt.Printf("%T %v\n", a, a)

	var c string = "hello"
	a = c
	fmt.Printf("%T %v\n", a, a)

	var d map[string]int = make(map[string]int, 100)
	d["abc"] = 1000
	d["eke"] = 30

	a = d
	fmt.Printf("%T %v\n", a, a)
}

type Student struct {
	Name string
	Sex  int
}

func main() {

	a := 65
	describe(a)

	str := "hello"
	describe(str)

	var stu Student = Student{
		Name: "user01",
		Sex:  1,
	}

	describe(stu)
}

  

 

2、类型断言

A. 如何获取接口类型里面存储的具体的值呢?

B.类型断言的坑

C.如何解决,引入 ok判断机制! v, ok := i.(T)

D.type switch。

E.type switch另外一种写法,解决转两次的问题

package main

import "fmt"

// 类型断言
func test(a interface{}) {
	s, ok := a.(int)
	if ok {
		fmt.Println(s)
		return
	}
	str, ok := a.(string)
	if ok {
		fmt.Println(str)
		return
	}

	f, ok := a.(float32)
	if ok {
		fmt.Println(f)
		return
	}

	fmt.Println("can not define the type of a")

}

func testInterface1() {
	var a int = 100
	test(a)

	var b string = "hello"
	test(b)
}

// case优雅实现(二次转换)
func testSwitch(a interface{}) {
	switch a.(type) {
	case string:
		fmt.Printf("a is string, value: %v", a.(string))
	case int:
		fmt.Printf("a is int, value: %v", a.(int))
	case int32:
		fmt.Printf("a is not, value: %v", a.(int32))
	default:
		fmt.Println("no support type")
	}
}

func testInterface2() {
	var a int = 100
	testSwitch(a)

	var b string = "hellow"
	testSwitch(b)
}

// case优雅实现(一次转换)
func testSwitch2(a interface{}) {
	switch v := a.(type) {
	case string:
		fmt.Printf("a is string, value: %v", v)
	case int:
		fmt.Printf("a is int, value: %v", v)
	case int32:
		fmt.Printf("a is not, value: %v", v)
	default:
		fmt.Println("no support type")
	}
}

func testInterface3() {
	var a int = 100
	testSwitch2(a)

	var b string = "hellow"
	testSwitch2(b)
}

func main() {
	testInterface1()
	testInterface2()
	testInterface3()
}

  

指针接收和值接收区别

1、指针接收

package main

import "fmt"

type Animal interface {
	Talk()
	Eat()
	Name() string
}

type Dog struct {
}

func (d *Dog) Talk() {
	fmt.Println("汪汪汪")
}

func (d *Dog) Eat() {
	fmt.Println("我在吃骨头")
}

func (d *Dog) Name() string {
	fmt.Println("我的名字叫旺财")
}

func main() {
	var a Animal
	// 值
	// a存的是一个值类型的Dog,那么调用a.Eat(). &Dog ->Eat()
	// 如果一个变量存储在接口类型的变量中之后,那么不能获取这个变量的地址
	//var d Dog
	//a = d
	//a.Eat()
	//
	//fmt.Printf("%T %v\n", a, a)

	// 指针
	var d1 *Dog = &Dog{}
	a = d1
	// *(&Dog).Eat()
	a.Eat()
	fmt.Printf("*Dog %T %v\n", d1, d1)
}

  

接口嵌套

1、 实现多接口,同一个类型可以实现多个接口

2、 接口嵌套,和结构体嵌套类似

package main

import "fmt"

type Animal interface {
	Talk()
	Eat()
	Name() string
}

type PuruDongwu interface {
	TaiSheng()
}

type Dog struct {
}

func (d Dog) Talk() {
	fmt.Println("汪汪汪")
}

func (d Dog) Eat() {
	fmt.Println("我在吃骨头")
}

func (d Dog) Name() string {
	fmt.Println("我的名字叫旺财")
	return "旺财"
}

func (d Dog) TaiSheng() {
	fmt.Println("狗是胎生的")
}

func main() {
	var d Dog
	var a Animal

	fmt.Printf("%v %T %p", a, a, a)

	if a == nil {
		fmt.Println("a is nil")
	}

	a = d
	a.Eat()

	var b PuruDongwu
	b = d
	b.TaiSheng()
}

  

posted @ 2019-11-07 19:52  shuyang  阅读(67)  评论(0编辑  收藏