目录
点击展开
Go语言基础
认识
Go(又称Golang) 由Google开发,于2009年首次公开发布。它旨在提供简洁、高效、可靠的软件开发解决方案。
Golang是一种静态强类型、编译型语言
支持最强大的并发、内存管理、垃圾回收机制等
下载安装
官网: https://go.dev/(英) 可访问 中国镜像站 https://golang.google.cn/
安装教程参考:https://learn.microsoft.com/zh-cn/azure/developer/go/configure-visual-studio-code
以上步骤操作完重新打开VSCode就可以使用了
Go语言声明
- var(声明变量)
变量意为 可变的东西,就是赋值完还能继续赋值改变这个值
Go语言的变量声明格式为:var 变量名 变量类型 = 值
变量作用域package main func main() { var a int = 10 // 声明一个整型变量a并赋值为10 var b int // 声明一个整型变量b,未赋值,默认值为0 var c = 20 // 为声明类型,go会根据值自动推断类型 // 短声明(语法糖 := 与上面意思一致) d := "短声明d" // 短声明一个d变量,赋值为字符串类型 // 一行声明个多,相同类型或不同类型的变量 var aa,bb,cc int = 11,"22",33 // 批量声明 var ( e int = 1 f = 2 ) }
package main import ( "fmt" ) // 全局变量m var m = 100 func main() { n := 10 m := 200 // 此处声明局部变量m fmt.Println(m, n) }
- const(声明常量)
相对于变量,常量是恒定不变的值,多用于定义程序运行期间不会改变的那些值。只是把var换成了const,常量在定义的时候必须赋值。
const pi = 3.1415
const e = 2.7182 // 批量声明 const ( pi = 3.1415 e = 2.7182 ) // 使用iota 关键字进行递增计数 // iota 在const关键字出现时将被重置为 0 const ( n1 = iota //0 n2 //1 n3 //2 n4 //3 ) ```
- type(声明类型)
- func(声明函数)
关键字
关键字是 Go 语言中预先保留的单词,在程序中有特殊含义,不能用来定义变量或常量名字。
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
数据类型
Go 语言中数据类型分为:基本数据类型和复合数据类型
- 基本数据类型 整型、浮点型、布尔型、字符串
- 复合数据类型 数组、切片、结构体、函数、map、通道(channel)、接口等
基本数据类型
整型
整型的类型有很多中。我们可以根据具体的情况来进行定义
有符号整型 :int8,int16,int32,int64
无符号整型 : uint8, uint16, uint32, uint64
提示!
- 有符号(Signed) → 能赋值正能负数,但正数范围小。
- 无符号(Unsigned) → 只能赋值正数,但能存更大的正数。
如果我们直接写int
也是可以的,它在不同的电脑操作系统中,int
的大小是不一样的
32位操作系统:int -> int32 64位操作系统:int -> int64
![[../../../assets/images/2025/Pasted image 20250819113643.png]]
var num8 uint8 = 128
var num16 uint16 = 32768
var num32 uint32 = math.MaxUint32
var num64 uint64 = math.MaxUint64
浮点型
浮点型表示存储的数据是实数,如3.145
32位操作系统:float32 64位操作系统:float64
var num1 float32 = math.MaxFloat32
var num2 float64 = math.MaxFloat64
提示: 我们知道浮点数能表示的数值很大,但是浮点数的精度却没有那么大:
- float32 的精度只能提供大约 6 个十进制数(表示小数点后 6 位)的精度。
- float64 的精度能提供大约 15 个十进制数(表示小数点后 15 位)的精度。
布尔值
Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true
(真)和false
(假)两个值。
var d bool = true
f := false
注意 布尔类型变量的默认值为false。
Go 语言中不允许将整型强制转换为布尔型.
布尔型无法参与数值运算,也无法与其他类型进行转换。
字符串
字符串的值为双引号(“)中的内容
s1 := "hello"
s2 := "你好"
复合数据类型
数组
是同一种数据类型的固定长度的序列。
- 数组定义:
var a [len]int
,比如:var a [5]int
,一旦定义,长度不能变。- 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1\
- 数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。
// 数组初始化
var arr1 = [3]int{1, 2, 3}
fmt.Println(arr1) // [1, 2, 3]
// 短声明
arr2 := [3]int{4, 5, 6}
fmt.Println(arr2) // [4, 5, 6]
// 部分初始化,为初始化为0值
arr3 := [5]int{1, 2}
fmt.Println(arr3) // [1, 2, 0, 0, 0]
// 通过指定索引,方便对数组某几个元素赋值
arr4 := [5]int{0: 1, 3: 4}
fmt.Println(arr4) // [1, 0, 0, 4, 0]
// 根据初始化的值,指定长度
arr5 := [...]int{1, 2, 3}
fmt.Println(arr5) // [1, 2, 3]
// 多维数组
var arr6 = [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println(arr6) // [[1 2 3] [4 5 6]]
切片
切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
切片是一个引用类型,它的内部结构包含指针、长度和容量。切片一般用于快速地操作一块数据集合。
格式:
var name []T
- name:表示变量名
- T:表示切片中的元素类型
切片的定义方式与数组的定义方式的区别在于,数组在初始化的时候我们将一个具体大小给他设定了,而切片没有定义大小。
使用内置
len()
函数求长度 使用内置cap()
函数求容量
func main() {
var a []string //声明一个字符串切片
var b = []int{} //声明一个整型切片并初始化
var c = []bool{false, true} //声明一个布尔切片并初始化
// 使用内置 make([]T, len, cap) 定义切片
numList := make([]int, 3, 5)
fmt.Println(numList) // [0 0 0]
fmt.Println(len(numList)) // 3
fmt.Println(cap(numList)) // 5
// 通过数组进行切片截取
a := [5]int{1, 2, 3, 4, 5}
// 切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片(通过索引截取)
// 格式:数组变量[起始位置:结束位置]
// 切片中不包含结束位置的元素
s := a[1:3]
fmt.Println(s) // [2 3]
/*
a[2:] // 等同于 a[2:len(a)]
a[:3] // 等同于 a[0:3]
a[:] // 等同于 a[0:len(a)]
*/
// 创建多维切片
nameList := [][]string{
{"1", "张三"},
{"2", "李四"},
{"3", "王二"},
{"4", "麻子"},
}
fmt.Println(nameList) // [[1 张三] [2 李四] [3 王二] [4 麻子]]
}
用append内置函数操作切片(切片追加)
package main
import (
"fmt"
)
func main() {
var a = []int{1, 2, 3}
fmt.Printf("slice a : %v\n", a) // [1 2 3]
var b = []int{4, 5, 6}
fmt.Printf("slice b : %v\n", b) // [4 5 6]
c := append(a, b...)
fmt.Printf("slice c : %v\n", c) // [1 2 3 4 5 6]
d := append(c, 7)
fmt.Printf("slice d : %v\n", d) // [1 2 3 4 5 6 7]
e := append(d, 8, 9, 10)
fmt.Printf("slice e : %v\n", e) // [1 2 3 4 5 6 7 8 9 10]
}
超出原 slice.cap 限制,就会重新分配底层数组,即便原数组并未填满, 通常以 2 倍容量重新分配底层数组。
指针
指针也是一种类型,也可以创建变量,称之为指针变量。指针变量的类型为 *Type
,该指针指向一个 Type 类型的变量。指针变量最大的特点就是存储的某个实际变量的内存地址,通过记录某个变量的地址,从而间接的操作该变量。
![[../../../assets/images/2025/Pasted image 20250826104221.png]]
指针声明获取格式
- var 变量名 *类型 = new(类型)
- 填入值:*变量名 = 值
- 获取指针:&变量名
- 获取值:*变量名
package main
import (
"fmt"
)
func main() {
var num int = 10
p := &num // 将地址值指针赋值给p变量
fmt.Println(p) // 输出地址值指针 0x14000010230
fmt.Println(*p) // 通过指针访问值 // 10
fmt.Println(&num) // 0x14000010230
fmt.Println(num) // 10
// 修改指针指向的值
*p = 20
fmt.Println(num) // 20
// new 先创建指针分配好内存,再给指针写入值
var p1 *int = new(int)
*p1 = 30
fmt.Println(*p1) // 30
}
只需要记住两个符号:&
(取地址)和*
(根据地址取值)。
总结: 取地址操作符&和取值操作符*
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
- 对变量进行取地址(&)操作,可以获得这个变量的指针变量。 >2. 指针变量的值是指针地址。 >3. 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
package main
import "fmt"
func main() {
var p *string
fmt.Println(p)
fmt.Printf("p的值是%s/n", p)
if p != nil {
fmt.Println("非空")
} else {
fmt.Println("空值")
}
}
Map
map
是一种无序的基于key-value的数据结构,Go语言中的map是引用类型。它类似于其他编程语言中的哈希表或字典,提供了快速的插入、删除和查找操作
map中的数据是无序排列
map中的key只能是string|int
类型
package main
import (
"fmt"
)
func main() {
// 定义方式
// make方式 格式:name := make(map[KeyType]ValueType) 或者 make(map[KeyType]ValueType, [cap])
// KeyType:表示键的类型。 ValueType:表示键对应的值的类型。 cap表示容量
make1 := make(map[string]string)
fmt.Printf(make1) // map[]
// 通过字面量
var userInfo1 map[string]string = map[string]string{
"username": "zhangsan",
"password": "123456",
}
// 通过短声明
userInfo2 := map[string]string{
"username": "zhangsan",
"password": "123456",
}
fmt.Printf(userInfo2) // map[username:zhangsan password:123456]
userList := map[int]string{
1: '张三',
2: '李四',
3: '王二',
}
// 添加元素到map
userList[4] = "麻子"
fmt.Println(userList) // map[1:张三 2:李四 3:王二 4:麻子]
// 更新map
userList[4] = "mazi"
fmt.Println(userList) // map[1:张三 2:李四 3:王二 4:mazi]
// 获取元素
fmt.Println(userList[4]) // mazi
// 删除元素
delete(userList, 4)
fmt.Println(userList) // map[1:张三 2:李四 3:王二]
//判断键值是否存在 value,ok := map[key]
u3, ok := userList[3]
fmt.Println(ok) // true
fmt.Println(u3) // 张三
u4, ok := userList[4]
fmt.Println(ok) // false
fmt.Println(u4) //
// 循环map
for key, value := range m1 {
/*
%s、%d都是占位符,%s是用于插入字符串类型,%d用于插入整数类型的值
*/
fmt.Printf("key: %s, value: %d\n", key, value)
}
}
结构体
理解
- Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。
- Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。
简单理解就是go语言中的类成为结构体,用type
和struct
关键字进行实现
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
/*
1.类型名:标识自定义结构体的名称,在同一个包内不能重复。
2.字段名:表示结构体字段名。结构体中的字段名必须唯一。
3.字段类型:表示结构体字段的具体类型。
*/
内置函数
new
new是一个内置的函数,用于分配内存
*函数签名:func new(Type) Type
- Type表示类型,new函数只接受一个参数,这个参数是一个类型
- *Type表示类型指针,new函数返回一个指向该类型内存地址的指针。
func main() {
var a *int
a = new(int)
*a = 10
fmt.Println(*a) // 10
}
make
make也是用于内存分配的,区别于new,它只用于**切片(slice)、map以及通道(channel)**的内存创建,它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
函数签名:func make(t Type, size …IntegerType) Type
func main() {
var b map[string]int
b = make(map[string]int, 10)
b["测试"] = 100
fmt.Println(b) // map[测试:100]
}
new与make的区别
- 二者都是用来做内存分配的。
- make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
- 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
常用库解析
fmt
用于格式化输出文本
- %v:通用类型占位符。可以表示任意值的类型。
- %d:10进制整数
- %f:浮点数
- %s:字符串
- %t:布尔值
- %c:字符(Unicode码点)
- %p:指针地址
- %e/%E:科学计数法
- %b:二进制整数
- %o:八进制整数
- %x/%X:十六进制整数
- %U:Unicode格式,表示为U+十六进制数
- %T:打印值的类型
模块
模块是Go管理依赖项的方式。
模块是一组被发布、有版本号并一起分发的软件包。块可以直接从版本控制存储库或模块代理服务器下载。
有关模块的系列教程,请参阅https://golang.google.cn/doc/tutorial/create-module
默认情况下,go
命令可能会从 https://proxy.golang.org 下载模块。它可能会使用位于 https://sum.golang.org 的校验码数据库来验证模块。这两个服务均由谷歌的 Go 团队运营。这些服务的隐私政策分别可在 https://proxy.golang.org/privacy 和 https://sum.golang.org/privacy 找到。