golang基础笔记(11):泛型
泛型
在Go 1.18版本中,添加了对泛型的支持。泛型是一种独立于所使用的特定类型的编写代码的方法。使用泛型可以编写出适用于一组类型中的任何一种的函数和类型,便利了代码的编写。
泛型的作用
假设我们有一个调换int参数的函数,现在我们需要一个调换float参数的函数,没有泛型时,我们需要将相同的逻辑、不同的类型参数的函数重复多遍。
1234567func excInt(a, b int) (int, int) { return b, a}func excFloat(a, b float32) (float32, float32) { return b, a}
但那是有了泛型,就可以很方便的编写出适用所有元素类型的“普适版”的函数
123func exchange[T any](a, b T) (T, T) { return b, a}
泛型语法
泛型为Go语言添加了三个新的重要特性:
函数和类型的类型参数。
将接口类型定义为类型集,包括没有方法的类型。
类型推断,它允许在调用函数时在许多情况下省略类型参数。
这里我们着重讲 ...
golang基础笔记(10):反射
反射介绍
反射指的是再程序运行期间对程序本身进行访问和修改的能力。
Go程序在运行期间使用reflect包访问程序的反射信息,包括字段名称、类型信息、结构体信息等。
一个具体的例子是,空接口可以存储任意类型的变量,那我们如何知道这个空接口保存的数据是什么呢? 反射就是在运行时动态的获取一个变量的类型信息和值信息。
golang基础笔记(9):Error接口
Error接口
Go语言不支持其他语言使用try/catch方式捕获处理错误,而是将错误作为一种特殊的值来处理。
Go语言使用了一个名为 error 接口来表示错误类型
123type error interface { Error() string}
当一个函数或方法需要返回错误时,我们通常是把错误作为最后一个返回值。例如下面标准库 os 中打开文件的函数
123func Open(name string) (*File, error) { return OpenFile(name, O_RDONLY, 0)}
errors.New
创建错误的最简单的方式就用errors.New()函数来创建一个错误
123456func queryById(id int64) (*Info, error) { if id <= 0 { return nil, errors.New("无效的id") } //...}
它接收一个字符串参数返回包含该字符串的错误。
fmt.Error ...
golang基础笔记(8):接口
接口
在Go语言中接口是一种类型,一种抽象的类型。Go语言的接口有别于具体类型的概念,无论是基础数据类型,还是结构体,它类似于一种协议,而不是具体内容。
我简单的理解概括:
只要A实现了B接口里的所有方法,则代表A就是B接口类型的具体实现(不需要显示表示出A、B关系),继而可以使用多态的方式,通过B接口类型去使用A对应的方法。
接口定义
每个接口类型由一个或者多个方法签名组成
12345type 接口类型名 interface{ 方法名1( 参数列表1 ) 返回值列表1 方法名2( 参数列表2 ) 返回值列表2 …}
其中
接口类型名一般以er作结尾,体现出接口的具体含义
方法名首字母一般为大写
参数列表和返回值列表中的参数变量名可以省略
实现接口
前面提到,接口就是一种协议,只要实现了接口中的所有方法就是实现了这个接口。并不需要显式的表明谁实现了谁。举个例子
1234567891011type Sayer interface { Say()}type Cat struct{}//给Cat添加一个Say方法func (c ...
golang基础笔记(7):包
包与依赖管理
Go语言中支持模块化的开发理念,在Go语言中使用包(package)来支持代码模块化和代码复用。一个包是由一个或多个Go源码文件(.go结尾的文件)组成,是一种高级的代码复用方案,Go语言为我们提供了很多内置包,例如我们之前频繁使用的fmt包等。
包 package
定义包
一个包可以简单的理解为一个存放.go文件的文件夹,其中该文件夹内所有.go文件都要在非注释的第一行添加声明,声明该文件归属的包
1package 包名
**注意:**一个文件夹内直接包含的文件只能归属于一个包,同一个包的文件不能在多个文件夹之下。
包名为main的包是go语言程序的入口包,编译后会得到一个可执行文件,非包含main包源代码编译则不会的到可执行文件。
包的引入
通过import关键字可以引入另外一个包的内容
1import importname "path/to/package"
其中
importname:命名引入的包在此处的名字,通常都省略。默认值为引入包的包名
path/to/package:引入包的路径名称,必须使用双引号包裹起来
Go语言中禁止循环导入包
...
golang实用技巧(1):option模式封装构造函数
文章思路来源:【优雅封装Go结构体构造函数】 https://www.bilibili.com/video/BV1ky4y1d7eT/?share_source=copy_web&vd_source=09bd1be8229f31f9b1fe4359ac7315ac
问题发掘
由于go语言中的函数是不支持重载的,导致我们不能直接去实现一个不同实现的构造函数。
例如我想去实现多个构造函数以实现我们在构造一个结构体实例时有多参数可选,如下我这样做是不被Go语言允许的:
1234567891011121314151617type User struct { Name string Id int Age int}func NewUser(name string) *User { return &User{Name: name}}func NewUser(name string, id, age int) *User { return &User{ Name: name, Id: id ...
golang基础笔记(6):结构体
Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念,它通过结构体的内嵌再配合接口比一般面向对象具有更高的扩展性和灵活性。
结构体
Go语言中的结构体是一种自定义数据类型,它可以用来封装多个基本数据类型。结构体的英文名称叫struct,与C语言一样,也是通过struct来定义结构体。
Go语言通过结构体来实现面向对象。
定义
使用type和struct关键字来定义结构体,具体代码格式如下:
12345type 类型名 struct { 字段名 字段类型 字段名 字段类型 …}
举个例子
12345type person struct { name string city string age int8}
跟以往一样,相同类型字段名可以写在同一行
1234type person struct { name, city string age int8}
语言内置的基础数据类型是用来描述一个值的,而结构体是用来描述一组值的。比如一个人有名字、年龄和居住城市等,本质上是一种聚合型的数据类型。
实例化
当 ...
golang基础笔记(5):函数
函数
Go语言中支持函数、匿名函数和闭包。
函数在Go语言中可以作为变量、参数、返回值等等。
定义
123func 函数名([参数列表]) [返回值列表] { 函数体}
返回值
一个函数可以有0个或者多个返回值
123456789101112131415//简单的函数func sum(a, b int) int{ return a+b}//在返回值列表定义返回变量func sum(a, b int) (c int){ c = a+b return //这样做,在return处就只需要一个return即可}//多返回值,求商与余数func divi(a, b int) (int, int){ return a/b, a%b}
在调用有返回值的函数时,我们可以选择不接受它的返回值。
当我们一个函数返回值为silce时,nil可以看做是一个silce,直接返回nil即可,不需要返回一个[]int{}
123func nilFunc() []int{ re ...
golang基础笔记(4):Map
map
map是Go语言中提供的映射关系的容器类数据结构,其内部使用散列表(hash)实现。
map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。
构建map
var
1var m map[KeyType]ValueType
make()
1m := make(map[KeyType]ValueType,[cap])
cap为可选参数
使用字面值
map支持在声明的时候填充元素
1234m := map[KeyType]ValueType{ "Key1":value1, "Key2":value2,}
大括号内也可以为空
1m := map[string]int{}
通过使用空接口,可以在同一个map中存储不同类型的value
1234m := map[string]interface{}{ "name": "张三", //string "age" ...
golang基础笔记(3):数组、切片
数组
与大多数语言中的数组都类似,Go语言的数组也是从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化。但是实际上,Go中的数组并不常用,而常用为切片。
声明
1var 数组变量名 [元素数量]T
初始化
基础写法
123var testArray [3]int //数组会初始化为int类型的零值var numArray = [3]int{1, 2} //使用指定的初始值完成初始化var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
编译器判断长度
12var numArray = [...]int{1, 2}var cityArray = [...]string{"北京", "上海", "深圳"}
指定索引值
1r := [...] ...