golang快速入门:类型系统

自定义数据类型

在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
  1. 不能绑定方法
scss 复制代码
//自定义类型可以定义成员方法
func (m MyInt) MyIntMethod() {

}

// AliasIntMethod 类型别名 不可以绑定方法
func (m AliasInt) AliasIntMethod() {

}
//别名绑定方法会报错 cannot define new methods on non-local type
  1. 打印类型还是原始类型
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 
  1. 和原始类型比较,类型别名不用转换
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内置数据类型的一种别名,二者是同一种数据类型,可以用来进行运算符计算
相关推荐
苇柠1 小时前
Spring框架基础(1)
java·后端·spring
xiucai_cs1 小时前
布隆过滤器原理与Spring Boot实战
java·spring boot·后端·布隆过滤器
向阳花自开1 小时前
Spring Boot 常用注解速查表
java·spring boot·后端
程序视点1 小时前
如何高效率使用 Cursor ?
前端·后端·cursor
岁忧2 小时前
(LeetCode 面试经典 150 题) 82. 删除排序链表中的重复元素 II (链表)
java·c++·leetcode·链表·面试·go
sp422 小时前
设计一个 Java 本地缓存系统
后端
东阳马生架构2 小时前
Dubbo源码—5.SPI机制和线程模型
后端
用户7785371836962 小时前
踩坑记录:Claude Code Router 配置 Gemini Balance API
后端
疯狂的程序猴3 小时前
移动端网页调试实战,网络请求延迟与超时问题全链路排查指南
后端
_杨瀚博3 小时前
Springboot构建包使用BOOT-INF中的class覆盖依赖包中的class
后端