这是我参与「第三届青训营 -后端场」笔记创作活动的的第一篇笔记。
一、简介
1.1 什么是Go语言
1.高性能、高并发
Go语言有和C++,Java媲美的性能,并且原生支持高并发
2.语法简单、学习曲线平缓 语法风格基于C语言进行大幅度的简化, 上手简单,学习期短
下面是一个简单的高并发Http服务器:
package main
import {
"net/http"
}
func main() {
http.Handle("/",http.FileServer(http.Dir(".")))
http.ListenAndServe(":8080", nil)
}
3.丰富的标准库
有大量功能丰富,质量完善的标准库,降低学习成本。标准库有很高的稳定性和兼容性。
4.完善的工具链
Go 语言自带 编译、代码格式化、错误检查、帮助文档、包管理、代码补充提示、单元测试框架等工具链
5.静态链接
Go 语言的编译结果默认都是静态链接的,编译出的可执行文件不需要附件任何东西即可部署运行,部署方便快捷,镜像体积小。
6.快速编译
编译速度远超C++
7.跨平台
能在Linux、Windows、MacOS等系统运行,能用来开发Android、iOS的软件,还能在路由器、树莓派等设备运行。有方便的交叉编译特性,在笔记本上编写的 Go 语言可执行文件可以直接在路由器上运行而无需配置交叉编译环境。
8.垃圾回收
自带垃圾回收功能,与Java一样。写代码时无需考虑内存的分配和释放。
1.2 为什么全面拥抱Go语言
- 最初使用Python,由于性能问题换成了Go
- C++不太适合在线 web 业务
- 早期团队非Java背景
- 性能比较好
- 部署简单、学习成本低
- 内部RPC和HTTP框架的推广
二、入门
2.1 变量
go语言是一门强类型语言,每一个变量都有它自己的变量类型。
常见的变量类型包括 字符串 整数 浮点型、布尔型等。
go 语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。
在go语言里面,大部分运算符的使用和优先级都和 C 或者 C++ 类似,这里就不再概述。
下面讲述go语言里面的变量的声明,在go语言里面变量的声明有两种方式,一种是通过var name string = "" 这种方式来声明变量,声明变量的时候,一般会自动去推导变量的类型。如果有需要,你也可以显示写出变量类型。
常量的是把 var 改成const.
go语言里面的常量没有确定的类型,会根据使用的上下文来自动确定类型。
2.2 分支与循环
package main
import "fmt"
func main() {
var a=2
switch {
case a<2:
fmt.Println("a<2")
default:
fmt.Println("a>=2")
}
}
if else后的表达式不需要小括号,但必须要跟着一个花括号 if { } 像上面这样的格式 只有for循环,没有while do while
golang的swithch可以不加表达式而直接像if else的使用方式一样
golang中的switch不需要break,执行完一个分支就会自动break
2.3 数组与切片
go的数组定义方式是var 数组名[]数组元素类型,数组的读写与c语言等是一致的,下标都是从0开始
切片是一个动态的数组,可以用make来创建,用append来对数组进行拼接,但是append需要把值重新赋值给原切片,也可以直接用:=来创建
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
}
对于一个数组,可以很方便地取特定索引的值或者往特定索引取存储值,然后也能够直接去打印一个数组。不过,在真实业务代码里面,我们很少直接使用数组,因为它长度是固定的,我们用的更多的是切片。
2.4 map
map在其他编程语言里面,被叫做哈希或者字典。 map 是实际使用过程中最频繁用到的数据结构。
我们可以用 make 来创建一个空 map ,这里会需要两个类型,第一个是 key 的类型,这里是 string;另一个是 value 的类型,这里是 int 。 我们可以从里面去存储或者取出键值对。可以用 delete 从里面删除键值对。
golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unknow"]) // 0
r, ok := m["unknow"]
fmt.Println(r, ok) // 0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
2.5 range
对于一个 slice 或者一个 map 的话,我们可以用 range 来快速遍历,这样代码能够更加简洁。
range 遍历的时候,对于数组会返回两个值,第一个是索引,第二个是对应位置的值。如果我们不需要索引的话,我们可以用下划线来忽略。
2.6 函数
Golang 和其他很多语言不一样的是,变量类型是后置的。
Golang 里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。
2.7 结构体
结构体是带类型的字段的集合。我们可以用结构体的名称去初始化一个结构体变量,构造的时候需要传入每个字段的初始值。也可以用这种键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。
结构体支持指针,这样能够实现对于结构体的修改,也可以在某些情况下避免一些大结构体的拷贝开销。
2.8 字符串
Go 语言在标准库 strings 包里面有很多常用的字符串工具函数,比如 contains 判断一个字符串里面是否有包含另一个字符串, count 字符串计数, index 查找某个字符串的位置, join 连接多个字符串, repeat 重复多个字符串, replace 替换字符串,需要时可以查询文档来使用。
package main
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f) // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14
}
可以直接%v可以打印元素类型,可以用%+v进一步打印,也可以用%#v进行更近一步的打印,也可以用%f等具体的格式化符
2.9 时间库
在 go 语言里面最常用的就是time.now()来获取当前时间,你也可以用time.date去构造一个带时区的时间,构造完的时间可以用.Year()等方法获取这个时间点的 年、月、日、时、分、秒等信息。可以用.sub()去对两个时间进行减法,得到一个时间段,时间段又可以去得到它有多少小时,多少分钟、多少秒。
在和某些系统交互的时候,我们经常会用到时间戳。可以用 .UNIX 来获取时间戳。
可以用time.Format或者time.Parse去格式化一个时间。