如果你看它像只鸭子,那么它就是一只鸭子,这就是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接口也是可以继承的,比较简单这里就不做描述了
|
请发表评论