
自定义数据类型
在go语言中,自定义类型就是使用type关键字定义新的类型,它可以是基本类型的别名,也可以是结构体、接口、函数组成的新类型,自定义类型可以帮助我们更好的抽象和封装数据,让代码更加的简洁,易读易维护。
在 Go 语言中,使用 type 关键字可以定义一个新的类型,语法如下:
bash
type newType oldType
其中,NewType 是新类型的名称,OldType 可以是任何基本类型或现有类型的别名,通过这种方式可以创建一个新类型,使得这个新类型具有与原有类型不同的特性。
自定义数据类型是一种新的数据类型,与其基于的Go内置数据类型 是两种数据类型,无法用来进行 运算符计算 (算数运算符、逻辑运算符、关系运算符、位运算符等)。
less
type MyInt int
var a MyInt = 10
var b int = 10
if a==b {
fmt.Println("hello world")
}
程序报错
ini
invalid opeartion: a == b (mismatched types Myint and int)
如果想要参与运算,必须进行转换。
scss
if a==MyInt(b) {
fmt.Println("hello world")
}
不仅可以定义基本数据类型,也可以定义函数类型
go
type myFunc func(int) int
func sum10(num int) int {
fmt.Println(num*10)
}
func main() {
newFunc := myFunc(sum10)
}
定义成员方法
可以为自定义类型定义成员方法,下面基于 int
设置了 Code
类型(这是一个新类型,不是类型别名),在使用的时候也要通过 Code
类型进行声明,不过本质上它仍然是一个整型数字,你可以把具体的数值看做是 Code
类型的实例。
go
package main
import "fmt"
type Code int
const (
SuccessCode Code = 0
ValidCode Code = 7 // 校验失败的错误
ServiceErrCode Code = 8 // 服务错误
)
func (c Code) GetMsg() string {
return "成功"
}
func main() {
fmt.Println(SuccessCode.GetMsg())
}
同理,自定义函数类型也可以定义成员方法
go
type myFunc func(int) int
func (mf myfunc) sum(a,b int) int {
c := a + b
return mf(c)
}
自定义函数类型结合接口、结构体使用,完成一些复杂的逻辑
go
type sumable interface {
sum(int, int) int
}
// myFunc继承sumable接口
type myFunc func(int) int
func (f myFunc) sum (a, b int) int {
res := a + b
return f(res)
}
func sum10(num int) int {
return num * 10
}
func sum100(num int) int {
return num * 100
}
// icansum结构体继承sumable接口
type icansum struct {
name string
res int
}
func (ics *icansum) sum(a, b int) int {
ics.res = a + b
return ics.res
}
// handler只要是继承了sumable接口的任何变量都行,我只需要你提供sum函数就好
func handlerSum(handler sumable, a, b int) int {
res := handler.sum(a, b)
fmt.Println(res)
return res
}
func main() {
newFunc1 := myFunc(sum10)
newFunc2 := myFunc(sum100)
handlerSum(newFunc1, 1, 1) // 20
handlerSum(newFunc2, 1, 1) // 200
ics := &icansum{"I can sum", 0}
handlerSum(ics, 1, 1) // 2
}
上面可以看出sum10 和 sum10(1) 之间的区别,前者是类型为 func(int) int 的变量,后者是函数调用。其次,newFunc1 := myFunc(sum10) 的意思是将 sum10 这个变量的类型转换成 myFunc 类型并赋值给 newFunc1,newFunc1 其实就是套了一个类型叫 myFunc 的马甲的 sum10 变量。那么对于第43行 handlerSum(newFunc1, 1, 1),接受了一个 newFunc1 这个函数变量传递进来,并调用了其 sum 函数即 newFunc1.sum(1, 1),该 sum 函数的定义是先进行 res:=a+b 的加法操作,然后调用 f(res) 即 newFunc1(res) 来返回。最终,newFunc1是什么?不就是被转换成了 myFunc 类型的 sum10 嘛,本质上就是一个函数变量,那么执行 newFunc1() 其实等同于执行 sum10()。所以运算过程是先进行了 a + b 的加法,然后针对这个加法的结果进行不同的干预,你可以自定义任何一个函数(比如本例中的 sum10、sum100),只要能套上 myFunc 这个马甲(可将该变量类型转换成 myFunc ),就能对 a + b 的结果进行自定义的干预。
类型别名
等于是给基础类型换一个别名。
go
type intAlias = int
类型别名和自定义类型的区别
go
type AliasInt = int
type MyInt int
- 不能绑定方法
scss
//自定义类型可以定义成员方法
func (m MyInt) MyIntMethod() {
}
// AliasIntMethod 类型别名 不可以绑定方法
func (m AliasInt) AliasIntMethod() {
}
//别名绑定方法会报错 cannot define new methods on non-local type
- 打印类型还是原始类型
java
var MyIntNum MyInt = 0
var AliasIntNum AliasInt = 0
//自定义类型不是原类型
fmt.Printf("%v, %T \n", MyIntNum, MyIntNum) //0 ,main.MyInt
//别名打印出来是原类型
fmt.Printf("%v %T \n", AliasIntNum, AliasIntNum)//0 ,int
- 和原始类型比较,类型别名不用转换
csharp
var age int = 0
//别名比较不用转换类型
fmt.Println(AliasIntNum == age)
//必须转换之后才能和原始类型比较
//invalid operation: MyIntNum == age (mismatched types MyInt and int)
fmt.Println(int(MyIntNum) == age)
总结
- 自定义数据类型是一种新的数据类型,与其基于的Go内置数据类型 是两种数据类型,无法用来进行 运算符计算 (算数运算符、逻辑运算符、关系运算符、位运算符等)
- 类型别名 是其基于的Go内置数据类型的一种别名,二者是同一种数据类型,可以用来进行运算符计算