这是我参与「第五届青训营 」笔记创作活动的第1天
主要内容
Go语言介绍
Go语言的优势:
- 高性能、高并发
- 语法简单
- 标准库丰富
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
Go语言开发环境配置
我推荐使用GoLand进行开发,比较容易上手,对于go的sdk版本也很好下载
Go语言基础语法
变量及常量
变量声明方式
var a = "initial" // 自动推断类型
var a string = "initial" // 显式说明类型
a := "initial" // 自动推断类型
Go语言中没有隐式类型转换,我们在使用时都需要用显式类型转换,例如:
var e float64
f := float32(e)
常量声明方式
const s string = "constant"
const h = 5000000
const i = 3e20 / h
条件语句
if-else
if 7 % 2 == 0 {
fmt.Printf("7 is even")
} else {
fmt.Printf("7 is odd")
}
其实和C、CPP相比就是少了个()
switch
switch a {
case 1:
fmt.Printf("a = 1")
case 2:
fmt.Printf("a = 2")
case 3:
fallthrough
default:
fmt.Printf("other")
}
这里需要注意的是,Go语言中不需要加break,如果我们需要执行两个分支的话,需要加关键字fallthrough
select
这个课程中没有,可以大概讲一下
c := make(chan int, 1)
c <- 1
select {
case <-c:
fmt.Printf("random 01")
case <-c:
fmt.Printf("random 02")
}
- select的特性之一是会随机选择满足条件的几个分支之一
- 这段代码的意思就是先往chan里写入1,然后select多路复用,发现<-c都满足条件,所以会随机选择一个分支执行
循环语句
Go里面没有while循环,只有for循环
// 死循环
for {
fmt.Printf("1")
}
// 实现while
i := 0
for i < 4 {
fmt.Printf(i)
i++
}
// 正常使用
for i := 0; i < 4; i++ {
fmt.Printf(i)
}
数组
声明
var a [3]int
以上声明了一个大小为3的int数组
访问
有两种方式:
- for循环
for i := 0; i < 3; i++ {
fmt.Printf(a[i])
}
- for-range
for index, value := range a {
fmt.Printf(index, value)
}
注意这里的index是指下标,value即对应数组下标的值
切片
声明
a := make([]int, 3)
以上声明了一个len为3的int切片
good := string[]{"g", "o", "o", "d"}
以上声明了一个len为4的切片,并且内容也声明了
使用
append函数的使用,我们可以将一个元素push到切片的末尾
a := []int{1, 2, 3}
a = append(a, 4)
// a --> [1, 2, 3, 4]
注意扩容无须人为干涉,Go会自己实现扩容
map
和cpp里面的map使用类似
声明
a := make(map[string]int, 3)
以上声明了一个大小为3,key为键,int为值的map
访问
for key, value := range a {
fmt.Printf(key, value)
}
然后如果需要访问某一个key的value的话,有以下两种方式
value := a[key]
value, ok := a[key]
ok代表map中是否有这个key
函数
在Go语言中,函数是一等公民,这意味着可以将它看作变量,并且它可以作为参数传递、返回及赋值
// 函数作为返回值
func makeGreeter() func() string {
return func() string {
return "hello jonson"
}
}
// 函数作为参数
func visit(numbers []int, callback func(int)) {
for _, n := range numbers {
callback(n)
}
}
Go中函数还具有多返回值的特点,多返回值最常用于返回error错误信息,从而被调用者捕获。
func dlv(a int, b int) (int, error) {
if b == 0 {
return 0, errors.New("b<0")
}
return a/b, nil
}
func main() {
if _, err := dlv(4, 2); err != nil {
fmt.Println("err:",err)
}
}
指针
声明
var a *int
以上声明了一个指向int的指针,其他类型类似
结构体
声明
type User struct {
UserId string
UserName string
Password string
}
以上声明了一个User的结构体,其中有三个string字段,分别是UserId,UserName,Password
赋值
var d user
d.UserName="Yuuki"
a := {UserName:"Yuuki"}
b := {"123", "Yuuki", "12983"} // 这里是按顺序赋值的
结构体方法
类似于类函数
func (u user) hello() {
fmt.Println("hello world")
}
上面表示的是绑定了user的方法,调用时需要用到user实例
错误处理
Go里面有很多函数都会有多个返回值,其中有一个就是error类型返回值,这样的话,我们能自己处理err,比如说在上述map中获取key的value时返回的ok,虽然他不是err,但是也算是一个错误吧(我认为)。实际上,例如http的listen之类的函数都会有error返回值
字符串函数
Json的处理
两个重要的函数json.Marshal json.Unmarshal,具体使用参考课程
时间的处理
数字解析
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
ParseFloat、ParseInt第二个参数为解析的进制
进程信息
// go run example/20-env/main.go a b c d
fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1
os.Args代表命令行参数,os.Getenv获取环境变量,os.Setnv设置环境值的值,exec.Command开一个子进程执行任务
个人总结
- 通过这次课程我快速地学会了golang的基础语法以及回忆了一些之前学过的golang底层的实现,但是这次课程也有很多比较重要的东西没有讲,比如说chan,select等等,这些都是需要我在课后去学习的。
- 三个实例对我前面的基础语法也算是有个小总结,并且其中用到了许多共享库,这些都是之前学习时所欠缺的,尤其是第三个实例->代理,一开始如果直接看代码的话可能会有些找不到重点,所以就需要回忆出课程中所放的图片,有三个阶段(上课是说的四个,我认为是三个?),每一步都有它存在的必要性,然后根据那个图,慢慢的实现就可以了