这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
GO-学习笔记
前提
- 字节前期
python
,有性能瓶颈和依赖问题
,后期用go
,开源RPC/HTTP
框架 - 没有
;
,作为语句结束 - 绑定控制台
sudo ln -s /usr/local/Cellar/go/go1.18.1/bin/go /usr/local/bin/go18
程序入口
package main
func main() {}
编译和运行
go run main.go
运行go build main.go
编译- Go语言通过首字母的大小写来控制访问权限。无论是方法,变量,常量或是自定义的变量类型,如果首字母大写,则可以被外部包访问,反之则不可以
变量类型
- 强类型语言
- 字符串
- 整数
- 布尔型
- 浮点型
- 常量 关键字
const
,const s string = "constant"
声明
- 自动推断
var a = "initial"
- 指定类型
var b, c int = 1, 2
f := float32(e)
字符串操作
基本操作
- 一个中文对应
3个
字符长度
// 是否包含子串
fmt.Println(strings.Contains(a, "ll")) // true
// 某个子串出现的次数,lll 只包含一个ll;llll 包含两个ll
fmt.Println(strings.Count(a, "ll")) // 2
// 前缀
fmt.Println(strings.HasPrefix(a, "he")) // true
// 后缀
fmt.Println(strings.HasSuffix(a, "llo")) // true
// 第一次出现该子串的下标
fmt.Println(strings.Index(a, "ll")) // 2
// 拼接字符串数组
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
// 重复字符串
fmt.Println(strings.Repeat(a, 2)) // hellohello
// 修改字符串某个子串 n < 0 全部替换;n > 0 替换n个
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
// 分割字符串
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
// 小写
fmt.Println(strings.ToLower(a)) // hello
// 大写
fmt.Println(strings.ToUpper(a)) // HELLO
字符串格式化
// 内容
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}
// 浮点数
fmt.Printf("%.2f\n", f) // 3.14
字符串与数字转换
- 字符串转换成数字
// 10为进制
n, _ := strconv.ParseInt("111", 10, 64)
// 输出为10进制,2进制也会转换为10进制
fmt.Println(n) // 111
// 快速转换
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
if-else
- 类似
python
,if
没有括号,但是语句要被大括号包裹
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
循环,判断语句无括号 - 继续循环
continue
- 死循环
for {
fmt.Println("loop")
break
}
- 经典的
for
循环
for j := 7; j < 9; j++ {
fmt.Println(j)
}
- 经典的
while
循环
for i <= 3 {
fmt.Println(i)
i = i + 1
}
swich-case
- 经典
swich-case
,不需要break
,只会处理一种情况
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")
}
数组
- 创建
- 指定大小
var a [5]int
- 制定元素
b := [5]int{1, 2, 3, 4, 5}
- 长度
len(a)
- 输出
- 全部
fmt.Println(b)
- 二维数组
var twoD [2][3]int
切片
- 类似集合,可变数组
- 创建
- 指定大小
s := make([]string, 3)
- 指定元素,
good := []string{"g", "o", "o", "d"}
- 输出
- 截取
fmt.Println(b[2:5])
,[2,5)
左闭右开,5为取不到的位置,最大为数组长度;- 后面部分
fmt.Println(b[2:])
- 前面部分
fmt.Println(b[:2])
- 复制切片,不能为基本数据类型
c := make([]string, len(s))
copy(c, s)
- 添加元素
list = append(list, "31")
底层存储
长度+容量+指针
,扩容后,需要返回新的slice
map
- 创建
m := make(map[string]int)
[key]value
- 指定内容
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
- 删除
delete(m, "one")
- 获取值
m["one"]
- 判断是否存在
if _, ok := m4["key3"]; !ok {
fmt.Println("key3 is null")
}
range遍历
- 遍历切片
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
- 遍历map
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
函数
- 特点
- 参数类型后置
- 可以返回多个值,规范中,第一个值为真实结果,第二个值为
正确/错误
信息
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
- 相同类型可以省略类型
func add2(a, b int) int {
return a + b
}
指针
- go中参数默认是值传递,真正改变参数需要传入地址
- 函数
func add2ptr(n *int) {
*n += 2
}
- 使用
add2ptr(&n)
结构体
type user struct {
name string
password string
}
- 创建
u := user{name: "zhangsan", password: "mima"}
- 修改不了改结构体的值
func changeName(u user) user {
u.name = "daw"
return u
}
- 修改结构体的值
func changeNamePoint(u *user) user {
u.name = "daw"
return *u
}
结构体方法
- 普通传参,无法修改值
func (u user) changeName() {
u.name = "daw"
u.password = "mima123"
}
- 指针方法,可以修改值
func (u *user) changeNamePoint() {
u.name = "daw"
u.password = "mima12333"
}
错误处理
- 错误函数
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
- 处理,先进行错误处理
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
- 简化处理
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
JSON操作
- 定义一个结构体,属性首字母大写,小写不能被解析
type userInfo struct {
Name string
// 输出json 为小写字段
Age int `json:"age"`
Hobby []string
}
- 序列化
buf, err := json.Marshal(a)
- 打印
// 直接打印为编码
fmt.Println(buf) // [123 34 78 97...]
// 字符串打印
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
- 序列化为
json
格式的形式输出,buf, err = json.MarshalIndent(a, "", "\t")
输出同样需要
fmt.Println(string(buf))
- 反序列化
var b userInfo
err = json.Unmarshal(buf, &b)
时间处理
- 当前时间
now := time.Now()
fmt.Println(now)
- 构建时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
- 获取某个时间位
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
- t按照
2006-01-02 15:04:05
格式,构建时间字符串
fmt.Println(t.Format("2006-01-02 15:04:05"))
// 格式化,转换成Time类型 YYYY-MM-DD hh-mm-ss
t3, err := time.Parse("2006-01-02 15-04-05", "2022-03-27 01:25:36")
- 时间差
diff := t2.Sub(t)
- t2与t的时间差
- 输出格式
1h5m0s
- 输出格式
// 毫秒
fmt.Println(t3.UnixMilli())
// 秒
fmt.Println(now.Unix()) // 1648738080
// 分钟
fmt.Println(diff.Minutes())
// 毫秒
fmt.Println(diff.Milliseconds())
// 秒
fmt.Println(diff.Seconds())
环境变量
- 执行命令行
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
// 输出
fmt.Println(string(buf))
- 启动时的命令行参数
fmt.Println(os.Args)
- 获取环境变量
fmt.Println(os.Getenv("PATH"))
- 设置环境变量
fmt.Println(os.Setenv("key", "value"))