GO接口定义与实现

如果你看它像只鸭子,那么它就是一只鸭子,这就是duck typeing的概念。如果你是个小朋友你可能会把它当作小黄鸭,如果你是个吃货可能会把它当作是别的什么东西。这个概念是有点抽像的。

先上段代码看看go的接口定义与实现:

GreenDuck.go

package duck

type GreenDuck struct {

}

func (duck GreenDuck)GetInfo()string  {
	return "this is a Green duck ."
}

YellowDuck.go

package duck

type YellowDuck struct {

}
func (duck YellowDuck)GetInfo() string {
	return "this is a yellow duck ."
}

DoDuck.go

package main

import (
	"fmt"
	"go_study/007_struct_interface/duck"
)

type Duck interface {
	GetInfo() string
}

func get(duck Duck) string  {
	return duck.GetInfo()
}

func main() {
	var greenDuck duck.GreenDuck
	fmt.Println(get(greenDuck))
	var yellowDuck duck.YellowDuck
	fmt.Println(get(yellowDuck))
}

执行DoDuck.go的结果是:

this is a Green duck .
this is a yellow duck .

结果分析:
func get(duck Duck) string {
return duck.GetInfo()
}

get函数接收的是一个实现了Duck interface的实现,而实现这个interface的struct我写了两个GreenDuck与YellowDuck,但是在这两个struct中并未显示声明是实现了Duck interface,好像只是不约而同的一个定义了GetInfo一个实现了GetInfo,没有强制的关联。 如果你有个chook interface也定义了GetInfo函数,那么GreenDucg与YellowDuck依然适用。
这正是应了文章开头所说的,你觉得它像只鸭子它就是只鸭子。

顺便说一下构造函数
和别的语言不太一样,GO没有构造函数,但是同样的灵活,先改造一下上面的代码吧

YellowDuck.go 把yellowDuck的值放在YellowDuck struck的肚子里,成为结构体的一部分,这样就可以在创建时分配相应的内存空间,并为其赋值。看下面的代码:

	package duck
	
	type YellowDuck struct {
		Content string
	}
	func (duck YellowDuck)GetInfo() string {
		return duck.Content
	}

DoDuck.go

package main

import (
	"fmt"
	"go_study/007_struct_interface/duck"
)

type Duck interface {
	GetInfo() string
}

func getDuck(duck Duck) string  {
	return duck.GetInfo()
}

func main() {
	yellowDuck := duck.YellowDuck{"this is a yellow duck ."}
	fmt.Println(getDuck(yellowDuck))
}

可以看出虽然GO没有构造函数,但是在创建时可以随意为内存空间赋值,非常的灵活,如果你想对一些构造加一些业务限制的话,你可以创建一个Create函数 , 见下面代码:
YellowDuck.go

package duck

import (
	"errors"
	"strings"
)

type YellowDuck struct {
	Content string
	age int
}

func CreateYellowDuck(content string,age int) (yellowDuck YellowDuck,err error) {
	if strings.Trim(content," ") == ""{
		err = errors.New("the content can not empty .")
		return
	}

	if age <= 0 {
		err = errors.New("the age can not <= 0 .")
		return
	}

	yellowDuck = YellowDuck{content,age}
	return
}
func (duck YellowDuck)GetInfo() string {
	return duck.Content
}

DoDuck.go

package main

import (
	"fmt"
	"go_study/007_struct_interface/duck"
)

type Duck interface {
	GetInfo() string
}

func getDuck(duck Duck) string  {
	return duck.GetInfo()
}

func main() {
	greenDuck,err := duck.CreateYellowDuck("this is a green duck .",12)
	if err != nil {
		fmt.Println(err.Error())
	}else{
		fmt.Println(getDuck(greenDuck))
	}
}

你也可以把
func CreateYellowDuck(content string,age int) (yellowDuck YellowDuck,err error)
写成
func (duck YellowDuck) CreateYellowDuck(content string,age int) (yellowDuck YellowDuck,err error)

区别仅仅是用包名引用还是用struct引用,对于函数式编程来说没什么区别

接口的值类型:
依旧是先看段代码

green/duck.go

package green

import (
	"strconv"
)

type Duck struct {
	Color string
	Weight float64
	GreenValue string
}

func (duck *Duck)GetInfo()string  {
	return duck.Color+" , "+strconv.FormatFloat(duck.Weight,'E',-1,64)
}

yellow/duck.go

package yellow

import (
	"strconv"
)

type Duck struct {
	Color string
	Weight float64
	YellowValue string
}

func (duck Duck)GetInfo()string {
	return duck.Color + " , " + strconv.FormatFloat(duck.Weight, 'E', -1, 64)
}

DoDuck.go

package main

import (
	"fmt"
	"go_study/007_struct_interface/green"
	"go_study/007_struct_interface/yellow"
)

type Duck interface {
	GetInfo() string
}

func getDuck(duck Duck) string  {
	return duck.GetInfo()
}

func main() {
	var duck Duck
	duck = &green.Duck{"green",5.3,"value2.1"}
	fmt.Printf("type -> %T , v->%v\n",duck,duck)
	inpect(duck)

	duck = yellow.Duck{"yellow",3.2,"value2.2"}
	fmt.Printf("type -> %T , v->%v\n",duck,duck)
	inpect(duck)
	
}

func inpect(duck Duck)  {
	switch v := duck.(type) {
	case yellow.Duck:
		fmt.Println(v.YellowValue)
	case *green.Duck:
		fmt.Println(v.GreenValue)

	}
}

找区别:
yellow/duck.go与green/duck.go的区别
green的GetInfo()实现是指针
func (duck *Duck)GetInfo()string
yellow的GetInfo实现是
func (duck Duck)GetInfo()string

green的接口变量获取是

duck = &green.Duck{"green",5.3,"value2.1"}

yellow的接口变量获取是

duck = yellow.Duck{"yellow",3.2,"value2.2"}

green duck的结构体是

type Duck struct {
	Color string
	Weight float64
	GreenValue string
}

yellow duck的结构体是

type Duck struct {
	Color string
	Weight float64
	YellowValue string
}

看功能,可以做到:
1、不同的结构体但是都有GetInfo方法,都被认为是Duck
2、可以查看不同duck实现的类型及内容
3、可以判断不同类型的duck来做不同的事情
4、接口变量不只是个指针,它肚子里还有类型和内容
在这里插入图片描述
5、同样的接口实现,可以支持传指针或是传值 如:func (duck *Duck)GetInfo()string 与 func (duck Duck)GetInfo()string
在这里插入图片描述

另外golang接口也是可以继承的,比较简单这里就不做描述了

猜你喜欢

转载自blog.csdn.net/wangqiang9x/article/details/88414706