【原创】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()
}

浙公网安备 33010602011771号