Go 的优点
1 高并发支持
Go语言并行设计的牛逼之处就在于 goroutine 和 channel,基于这俩实现简单的并发编程
goroutine协程- 一个进程可以拥有多个线程,一个线程可以拥有多个协程
- 协程由程序控制(用户态),而不是由操作系统控制
- 轻量级,没有内核切换的开销大,上下文切换很快
关于协程的底层原理和设计可以看看 GMP
Channel管道- 一种协程间的异步通信方式
goroutine A和goroutine B可以通过Channel完成通信,遵循先进先出
- Don’t communicate by sharing memory, share memory by communicating
- 一种协程间的异步通信方式
2 丰富标准库
| 标准库 | 功能 |
|---|---|
| fmt | 格式化操作 |
| net | 网络库:Socket、HTTP、RPC... |
| html | 网页 |
| math | 数学 |
| strings | 字符串 |
| time | 时间 |
| ... | ... |
ps:没有有序map
3 完整工具链
内置了很多性能调优、测试的工具,比如CPU分析器pprof、Uber开源的用于生成火焰图的go-torch、流量拷贝工具goreplay等
4 快速编译
- 跨平台
- Go程序是通过自己的
runtime库实现与操作内核系统交互。
- Go程序是通过自己的
- 静态链接
- 在编译时会将依赖库一起编译进二进制文件
- 快速编译
- 使用了import的引用管理方式
- 没有模板的编译负担
- ?
5 垃圾回收
垃圾回收(GC)是在后台运行一个守护线程,它的作用是在监控各个对象的状态,识别并且丢弃不再使用的对象来释放和重用资源
关于GO GC的底层原理和设计可以看看 三色标记法
基础语法
1 Hello World
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World!")
}
2 var
声明:var name type,var 是关键字,name 是变量名,type 是变量类型
简短声明:name := val,name 是变量名,val 是表达式
// 声明一个
var a int
// 声明且初始化
var a int = 100
// 声明多个
var a, b int
// 声明多个不同类型
var (
a int
b string
c []float32
d func() bool
e struct {
x int
}
)
// 简短声明
a := 1
a, b := 6.0, "666"
// 静态变量
const a = 100 // 无须设置类型
匿名变量:不占用内存空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。
a, _ = Get2num() // 这个下划线就是匿名变量
3 if else
必须大括号
if a:=1; a == 1 {
a := 1
} else if a == 0 {
a := 2
} else {
a := 3
}
4 for
for {
// 死循环
}
for i := 1; i <= 10; i++{
}
for i <= 10 {
// 循环 10 次
}
5 switch
case只要执行了就不会再选择了- 条件可以随便写,也就是无需选择某一变量
a := "6"
switch a {
case "1":
fmt.Println("1")
case "2":
fmt.Println("2")
default:
fmt.Print("6")
}
switch { // 比 if else 嵌套更清晰
case getuid() > 6:
fmt.Println("1")
case getuid() < 6:
fmt.Println("2")
default:
fmt.Print("6")
}
6 array & slice
数组 array 的下标从 0 开始
var a [5][5]int
a[1][1] = 666
fmt.Println(a)
切片 slice
- 声明
// 直接定义一个不定长数组
var arr []int
// 使用 make 定义一个切片
var slice []int = make([]int, 8, 16) // 第三个参数为提前预留的大小
// 简化写法
slice := make([]int, 8)
- 初始化
arr := []int{1, 2, 3}
a := 1
b := 2
- 截取(用截取做删除操作)
// 截取 [a,b) 中的内容
brr := arr[a:b]
// 不写, 就是默认从第一个元素到最后一个元素
- 获取长度
len(arr) // 实际使用长度
cap(arr) // 加上预留的长度
- 增加元素
arr = append(arr, 1, 2, 3) // 可以添加多个元素
7 map
- 声明
cnt := make(map[string]int, 6) // map[key]val, 预留空间6, 可以不写
cnt := map[string]int { // 创建多个
"123": 666,
"555": 777,
"777": 888,
}
- 获取键值对
v := cnt["123"] // 获取 val
k, v := cnt["123"] // 获取 key val
8 range
用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
for _, v := range cnt { // 善用匿名变量
fmt.Println(v)
}
9 结构体函数
// 定义结构体
type T struct {
a int
b int
c string
}
// 结构体 T 的一个函数
func (u T) ADD() int {
return u.a + u.b
}
// 初始化 与 使用
x := T{1, 2, "666"}
var y T
fmt.Println(x.ADD(), y)
10 字符串处理
- 包
import (
"strings"
)
- 是否含有子串
strings.Contains(s, "substr")
- 子串出现的次数
strings.Count(s, "substr")
- 串是否以 pre 开始
strings.HasPrefix(s, "pre")
- 串是否以 suf 结束
strings.HasSuffix(s, "suf")
- 还有一些,后面写吧
11 JSON处理
-
结构体 -> json
- u 一个带内容结构体
u := &T{ 1, []int{1, 2, 3}, true, }- 结构体(u) -> json(uJson)
uJson, err := json.Marshal(u) // 转换 if err != nil { fmt.Println("错误") }- 输出
fmt.Println(string(uJson)) // 输出需要 string() -
json -> 结构体
- nu 一个空的结构体
nu := &T{}- json(uJson) -> 结构体(nu)
err2 := json.Unmarshal(uJson, nu) if err2 != nil { fmt.Println("错误") }- 输出
fmt.Println(nu)
12 时间处理
13 错误处理
- Go 直接提供一个错误类型 error
// 一个函数
func DIV(a int, b int) (int, error) {
if b == 0 {
return -1, errors.New("g")
}
return a / b, errors.New("")
}
// 使用
a, msg := DIV(10, 2)
if msg == errors.New("") {
fmt.Println(a, msg)
} else {
fmt.Println(a, msg)
}