Go基础 | 青训营笔记

140 阅读5分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第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语言通过首字母的大小写来控制访问权限。无论是方法,变量,常量或是自定义的变量类型,如果首字母大写,则可以被外部包访问,反之则不可以

变量类型

  • 强类型语言
  1. 字符串
  2. 整数
  3. 布尔型
  4. 浮点型
  • 常量 关键字constconst 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

  • 类似pythonif没有括号,但是语句要被大括号包裹
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")
}

数组

  • 创建
  1. 指定大小 var a [5]int
  2. 制定元素 b := [5]int{1, 2, 3, 4, 5}
  • 长度 len(a)
  • 输出
  1. 全部 fmt.Println(b)
  • 二维数组 var twoD [2][3]int

切片

  • 类似集合,可变数组
  • 创建
  1. 指定大小 s := make([]string, 3)
  2. 指定元素,good := []string{"g", "o", "o", "d"}
  • 输出
  1. 截取 fmt.Println(b[2:5])[2,5)左闭右开,5为取不到的位置,最大为数组长度;
  2. 后面部分 fmt.Println(b[2:])
  3. 前面部分 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

  • 指定内容
  1. m2 := map[string]int{"one": 1, "two": 2}
  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
}

函数

  • 特点
  1. 参数类型后置
  2. 可以返回多个值,规范中,第一个值为真实结果,第二个值为正确/错误信息
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)
  1. t2与t的时间差
  2. 输出格式 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"))