学习指导
入门
安装
选择pkg,进行点击安装就好,其他方式会报错。
go常用指令介绍
go mod init 项目名称 // 初始化项目,类似npm init
go get -u 三方sdk地址 // 引入三方sdk
go mod tidy // 安装依赖,类似npm i
go run 文件.go // 启动代码,类似node
go build 文件.go // 生成二进制文件
初始化一个项目
go mod init 项目名称
mkdir index.go
index.go内容
package main
import "fmt"
func main() {
fmt.Println("hello go")
}
启动
go run index.go
go语法
Go 中数组赋值和函数传参都是值复制的。
对于固定语法,声明了元素,但是不需要使用它,可以用 _
代替,就不会报错了。_
是特殊标识符,用来忽略结果。
for index, _ := range "abcdefg" {}
指针
Go 中数组赋值和函数传参都是值复制的。
list := []int{1, 2, 3, 4, 5}
list1 := list
fmt.Printf("list : %p , %v\n", &list, list)
fmt.Printf("list1 : %p , %v\n", &list1, list1)
指针的声明与取值
a := 10
b := &a // &声明
fmt.Printf("b : %p , %v\n", b, *b) // b : 0xc0000120c8 , 10
*b = 20 // *取值
fmt.Printf("a : %p , %v\n", &a, a) // a : 0xc0000120c8 , 20
nil // 空指针
go对于引用类型(slice、map、channel)的变量,需要 声明 + 分配内存空间,需要用到new与make
var a *int // 声明
*a = 100 // 复制
// 会报错,因为没有指针没有内存空间
var a *int // 声明
a = new(int) // 分配内存空间
*a = 100 // 复制
// 等价于
a := new(int)
*a = 100
var b map[string]int // 声明指针
b = make(map[string]int, 10) // 指针赋值
b["sss"] = 1
new与make的区别
- 二者都是用来做内存分配的。
- make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
- 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
数组与切片
// 声明数组
list := [5]int{1,2,3,4,5}
// 声明切片
listSlice := []int{1,2,3,4,5}
listSlice1 := []int{6}
listSlice2 := make([]int, 5)
// 切片新增元素
listSlice = append(listSlice, 6)
listSlice = append(listSlice, listSlice1...)
区别:
- 数组长度固定,切片不固定
map
声明map
// make(map[key的类型]value的类型) 这是map
// make([]元素的类型) 这是切片
// make(chan 通道的类型) 这是通道
cMap := make(map[string]int, 10)
cMap["a"] = 1
cMap["b"] = 2
// 查
value, ok := cMap["c"]
for key, val := range cMap {
fmt.Println(key, val)
}
// 删除
delete(cMap, "b")
go并发goroutine
go fn1() // 执行并发
go fn2() // 执行并发
使用chan(通道)获取并发的值。
func getVal1(val int, accpet chan int) {
time.Sleep(1 * time.Second)
accpet <- val
}
func getVal2(val int, accpet chan int) {
time.Sleep(2 * time.Second)
accpet <- val
}
func main() {
fmt.Println("begin", time.Now().Second()) // 假设是1s
accpet := make(chan int)
go getVal1(11, accpet)
go getVal2(12, accpet)
a := <-accpet // 获取通道值的过程中,会阻塞主线程
fmt.Println(time.Now().Second()) // 执行到这就是2
b := <-accpet // 获取通道值的过程中,会阻塞主线程
fmt.Println(time.Now().Second()) // 到这就是3
fmt.Println(a, b)
}
遍历
string 遍历
for index, charUnicode := range "abcdefg" {}
// index为下标,charUnicode为字符串unicode
map 遍历
cMap := make(map[string]int)
cMap["a"] = 1
cMap["b"] = 2
for key, val := range cMap){}
类型定义和类型别名
type 自定义数据类型 数据类型
type myInt int // 类型定义
type myInt1 = int // 类型别名
结构体
type 类型名 struct {
字段名 字段类型
字段名 字段类型
}
type Person struct {
name string
city string
year, sex int8
}
var p1 person
p1.name = 'a'
p1.city = 'b'
p1.age = 20
p1.sex = 2
// 或者
var p2 struct {
name string
city string
year, sex int8
}
// 指针类型结构体
var p3 = new(Person)
p3.name = "asd" // go语法糖,等价于 (*p3).name,只存在于结构体指针
// 结构体初始化
p4 := Person {
name:"asd",
city:"ccc",
}
// 指针结构体初始化
p5 := &Person {
name:"asd"
}
构造函数、成员变量、成员方法
// 声明结构体
type Person struct {
name string
city string
}
// 声明构造函数
func NewPerson(name string, city string) *Person {
return &Person{
name: name,
city: city,
}
}
// 声明实例对应方法
func (p Person) GetName() string {
return p.name
}
func main() {
p := NewPerson("asd", "ccc")
fmt.Println(p.GetName())
}
select
select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。
select中的case语句必须是一个channel操作
select中的default子句总是可运行的。
如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。
如果没有可运行的case语句,且有default语句,那么就会执行default的动作。
如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行
func main() {
a, b, c := make(chan int), make(chan int), make(chan int)
go func() {
time.Sleep(1 * time.Second)
a <- 1
}()
go func() {
time.Sleep(1 * time.Second)
b <- 2
}()
go func() {
time.Sleep(1 * time.Second)
c <- 3
}()
select {
case <-a:
fmt.Println('a')
case <-b:
fmt.Println('b')
case <-c:
fmt.Println('c')
}
}
依赖安装慢的解决方法
go env -w GO111MODULE=on
g env -w GOPROXY="https://mirrors.aliyun.com/goproxy/,direct"
# 查看配置情况
go env