go语言修炼之八-type用法小结
今天回顾一下type关键字用法。在go语言里type关键字除了c、c++里别名定义的用法,还有更广泛的外延使用方式,同时也是使用类、接口等操作的关键技术。有必要小结一下。
type用法
1、别名
2、定义简单类型
3、定义复杂类型
复杂类型包括:
struct
interface
func
说明
一、别名:
1 2 3 4 5 | type MT = string var aaa MT aaa = "i am string" fmt.Printf(aaa) |
这里指定string的一个别名MT,也就是MT完全等价于string,var aaa MT 就等同于var aaa string。
这里需要注意的一点,别名方式需要使用符号 “=”,这样如果基础类型是含有方法的特殊对象,新定义的别名也自动具备基础类型所包含的所有方法。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package main import ( "fmt" ) type person struct { name string age int } func (e *person) show() { fmt.Println("name=", e.name) fmt.Println("age=", e.age) } func main() { aaa := person{"wen", 19} aaa.show() type MT = person bbb := MT{"hong", 21} bbb.show() } |
我们定义一个person的结构(也用的type),同时给他构造了一个方法show,在main里,我们使用别名,MT完全等同于person,也就具备了person的方法show。
二、定义简单类型
1 2 3 4 | type MT string var aaa MT aaa = "i am string" fmt.Println(aaa) |
很简单,不加符号“=”,就可用来定义新的类型,但不具备方法。也就是说,上一个例子如果改成type MT person,在后面调用bbb.show就会出错。因为这种写法只是定义新类型,不续承基础类型的方法。
三、定义复杂类型
type … struct,定义一个结构体,如果这个结构体还被赋予了方法,那就近似于是构造了一个类。如上文的person+show方法。
type … interface,定义一个接口,进一步再约定好接口具备的方法。
struct和interface之前的篇幅都已详细讲过。这里看看type … func。也是相当于定义一个类型,这个类型的基础类型是个函数(抽象)。
1 | type handler func(int) int |
形式为 type 新类型名 func(输入值) 返回值。函数类型很类似接口类型,完全的逻辑定义,上面定义的就是一个handler类型,为函数类型,同时约定好这种类型的函数必须具有一个int参数并且返回int的值。
这里要注意的是,type定义函数类型,func后面并没有写具体的函数名称。所以这里的基础类型函数可以理解成是一个函数的描述。仅仅描述清楚输入输出值就行。
换句话说,handler 这个类型定义好之后,在后面有handler类型的函数,就必须符合接受输入一个int,return一个int的逻辑结构。
一般用法,在定义函数类型之后,往往会有与类型对应的具体函数实现。比如
1 2 3 4 5 | type handler func(int) int func Tik(input int) int { return input * (input + 1) } |
我们定义了一个handler类型,下面有个tik函数,tik函数的输入值和返回值都是int
本质上与handler类型匹配。
再继续,再写一个功能函数,如下:
1 2 3 | func runtest(i int, f handler) int { return f(i) } |
这个函数有两个参数,handler 就是我们定义好的类型,同时实例化了一个变量f,
go语言里,函数也是可以作为参数传递给函数的,就是这样的用法。函数体内是
调用f函数,并传入参数i,return 的是f(i)的结果。
整体代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package main import ( "fmt" ) func Tik(input int) int { return input * (input + 1) } type handler func(int) int func runtest(i int, f handler) int { return f(i) } func main() { fmt.Println(runtest(3, Tik)) } |
运行结果如下:
这里面隐含了一个逻辑,那就是Tik函数,作为参数传递给runtest(),而runtest是只能接受handler 类型的传递的,所以在这一步,go语言编辑器做了类型转换,因为Tik与handler具备转换条件,符合要求。这一点与接口也很类似,某种标准匹配,就在实际赋值|调用时完成类型转换。
再来看看type func类型的灵活使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package main import ( "fmt" ) type person struct { name string age int } func (e *person) show() { fmt.Println("name=", e.name) fmt.Println("age=", e.age) } func Tik(input int) int { return input * (input + 1) } func Tik2(input int) int { return input + 100 } type handler func(int) int func runtest(i int, f handler) int { return f(i) } func main() { fmt.Println(runtest(3, Tik)) fmt.Println(runtest(5, Tik2)) } |
只要符合handler类型的约定,可以定义多种实现方案,再根据情况进行传值调用,结果如下:
此外也可以针对该handler类型再设定统一的方法。也就是类型+方法的套路,让后面的具体实现获得公用的一些方法。
尾声
小舟从此逝,江海寄余生…