简介
什么是Go语言(Go的特点)
Google产品,一门通用型计算机编程语言
-
高性能、高并发
- 媲美C++、Java性能
- 使用标准库或任意基于标准库的第三方库,即可开发高并发的应用程序
-
语法简单、学习曲线平缓
- 语法风格类似于C语言,并在其基础上进行简化
-
丰富的标准库
-
完善的工具链
-
静态链接
- Go中所有的的编译结果默认都是静态链接的,只需要拷贝编译后唯一的可执行文件,不需要附加任何东西就能部署运行
- 在线上的容器环境下运行,镜像的体积可以控制的非常小,部署非常方便快捷
-
快速编译
-
跨平台
-
垃圾回收
- 无需考虑内存的分配释放
- 只需专注于业务逻辑
入门
开发环境
-
安装Go语言
镜像:
https://goproxy..cn/
-
配置Go的集成开发环境
VS code / Goland
基础语法
关键字
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
运算符
-
算术运算符
+ 加 - 减 * 乘 / 除 % 取余 -
关系运算符
== 判断是否相等 ≠ 判断是否不相等 判断左边是否大于右边 < 判断右边是否大于左边 ≥ 判断左边是否大于等于右边 ≤ 判断左边是否小于等于右边 -
逻辑运算符
&& and ! not -
位运算符
& 与 异或,二进位相异结果为1 << 向左移位 >> 向右移位 -
赋值运算符
= += -= *= /= %= << = 左移后赋值 >> = 右移后赋值 &= 按位与后赋值 = ^= 按位异或后赋值
下划线
- 在
import中,表示仅引用该包中的某个函数 - 在函数中,表示忽略这个变量
- 在函数中,也可表示为占位符
hello world
package main // 程序入口文件
import (
"fmt"
)// 导入标准库的format包,用于输入输出字符串,格式化字符串
func main() {
fmt.Println("hello world")
}
如果运行这个程序
go run 01-hello/main.go
编译这个程序
go build 01-hello/main.go 输入 ./main 就可以运行
变量
常见的变量:字符串、整数、浮点型、布尔型
- 变量适用于存储数据,go中每一个变量都有自己的类型
- Go语言中字符串是内置类型,可以直接通过加号去拼接
- go中的变量必须经过声明后才能使用,同作用域内不支持重复声明
- 3种变量声明方式,用关键字
var - 常量的声明方式
常量
- 常量相对于变量,是不变的值
- 常量用
const关键字声明,且常量在定义的时候必须赋值 iota是go中的常量计数器,只能在常量的表达式中使用
package main
import (
"fmt"
"math"
)
func main() {
var a = "initial" // 声明变量,一般会自动推导类型。类型为string,初始值为"initial"
var b, c int = 1, 2 // 也可显示写出变量类型
var d = true
var e float64
f := float32(e) // 声明变量
g := a + "foo" // 字符串可以通过+拼接
fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
fmt.Println(g) // initialapple
const s string = "constant" // 声明常量,不可修改,go中的常量没有确定的类型,通过上下文自动确定类型
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}
if-else
- 写法与C++类似,不同的是if后面没有括号
if 条件 {不能直接写语句在同一行
package main
import "fmt"
func main() {
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
}
循环
- 只有唯一的for循环
for {...}代表一个死循环- continue 继续循环,break跳出循环
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println("loop")
break
}// 无限循环,break跳出循环
for j := 7; j < 9; j++ {
fmt.Println(j)
}// 有限循环,j的作用域只在for循环中
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
}
switch分支
- switch后面不需要括号
- 在switch内部不需要通过break跳出分支,运行其中一个case之后会自动跳出分支
package main
import (
"fmt"
"time"
)
func main() {
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
}
数组array
- 是一个具有编号,且长度固定的元素序列
- 数组通过下标进行访问,下标从0开始,最后一个下标是len-1
- 2种数组声明方式
- 数组是值类型,赋值和传参数回复制整个数组,而不是指针,所以改变拷贝的值,不会改变自身的值
package main
import "fmt"
func main() {
var a [5]int // 声明数组,长度为5,初始值为0
a[4] = 100
fmt.Println("get:", a[2])//读取数组元素下标2的元素,下标从0开始
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}
切片slice
- 不同于数组,是一个可变长度的数组,可以任意时刻更改长度
- 用make创建一个切片
- 用append追加元素
- 用copy拷贝数组
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]
}
map
- 哈希/字典
- 使用最频繁的数据结构
- 用make创建一个空map,需要两个类型(key和value的类型)
- 通过
map[key]=value写入kv对 - 通过
map[key]读取kv对 - 通过
delete(map,key)删除kv对 - go中的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"] // ok用于判断key是否存在
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)
}
range
- 对于一个slice或是map,可以使用range进行快速遍历
- 对于数组,返回两个值(索引,对应位置的值)
- 对于map,返回两个值(key,value)
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
for k := range m {
fmt.Println("key", k) // key a; key b
}
}
函数
- 不需要申明原型
- 可以不定变参
- 可以返回多个值
指针
- 主要用于对传入的参数进行修改
- go中的指针不能偏移和运算
- 每个变量都有一个地址,
&变量表示对变量进行 取地址 的操作
结构体
- go中没有 类 的概念
- 带类型的字段的集合
- 可以通过
type和struct关键字定义结构体 - 只有当结构体实例化的时候,才会分配内存
- 结构体本身也是一种类型,可以使用
var关键字申明结构体类型
错误处理
字符串操作
- Contains 判断一个字符串是否包含另一个字符串
- Count 字符串计数
- Index 查找某个字符串的位置
- Join 连接多个字符串
- Repeat 重复多个字符串
- len 获取字符串的长度
字符串格式化
fmt.Println(, , , )打印多个变量并且换行fmt.Printf("s=%v\n",s)//{1 2}%v打印任意类型变量fmt.Printf("s=%+v\n",s)//{x:1 y:2}%+v打印更加详细的结果fmt.Printf("s=%#v\n",s)//main.point{x:1 y:2}%#v打印任意类型变量fmt.Printf("%.2f\n", f)打印保留两位数的浮点数
JSON处理
- 对已有的结构体,只需要保证结构体的每行字段的第一个字母是大写
- 这个结构体就能通过
json.Marsha进行数列化 - 数列化之后会变成buf数组,打印时要加上
string(buf)才能打印
时间处理
time.Now()快速获取当前时间
数字解析
- 包:
strconv ParseFloatParseInt解析字符串Atoi快速将十进制字符串转化为十进制数字Itoa将十进制数字转化为十进制字符串
进程信息
os.Args获取进程在执行的命令行参数os.Getenv/os.Setenv获取/写入环境变量exec.Command快速启动程序,并获取其输入输出