走进Go语言 | 青训营笔记

120 阅读8分钟

简介

什么是Go语言

  1. 高性能、高并发
  2. 语法简单、学习曲线平缓
  3. 丰富的标准库
  4. 完善的工具链
  5. 静态链接
  6. 快速编译
  7. 跨平台
  8. 垃圾回收

哪些公司在使用Go语言?

在这里插入图片描述

字节跳动为什么全面拥抱Go语言

  1. 最初使用的Python,由于性能问题换成了Go
  2. C++不适合在线Web业务
  3. 早期团队非Java背景
  4. 性能比较好
  5. 部署简单、学习成本低
  6. 内部RPC和HTTP框架的推广

入门

开发环境-安装Golang

1.go.dev/ 2. studygolang.com/dl 3. goproxy.cn/

基础语法-hello world

package main
import(
	"fmt"
)
func main(){
	fmt.Println("hello world")

hello world 代码大概长这样子: 第一行 package main 代表这个文件属于 main 包的一部分,main 包也就是程序的入口包。
第三行导入了标准库里面的 FMT 包。这个包主要是用来往屏幕输入输出字符串、格式化字符串。
import 下面是 main 函数,main 函数的话里面调用了 fmt.Println 输出 helloworld要运行这个程序的话,我们就直接 go run heloworld.go。如果我们想编译成二进制的话,可以在 go build 来编译,编译完成之后直接 ./heloword 就可以运行在FMT包里面还有很多的函教来做不同的输入输出格式化工作。大家可以在编辑器里面把鼠标悬浮在你的代码上,就可以看到每一个函数的文档。
你也可以进入 pkg.go.dev,后面加你的包名比如 FMT 然后就能看到这个包的在线文档,可以从里面去挑选你需要的函数来使用。

变量

package main
import(
	"fmt"
	"math"
)
func main(){
var a="inital"
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)
fmt.Println(g)
const s string="constant"
const h=500000000
const i=3e20/h
fmt.Println(s,h,i,math.Sin(h),math.Sin(i))
}

下面我们来看第二个例子,关于变量类型。
go语言是一门强类型语言,每一个变量都有它自己的变量类型。常见的变量类型包括 字符串 整数 浮点型、布尔型等
go 语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。
在go语言里面,大部分运算符的使用和优先级都和 C 或者 C++ 类似,这里就不再概述。 下面讲述go语言的变量的声明,在go语言里变量的声明有两种方式,一种是过var name string=" "这种方式来声明变量,声明变量的时候,一般会自动去推导变量的类型。如果有需要,也可以显示写出变量类型。另一种声明变量的方式是使用变量 冒号 := 等于值。
下面来讲说常量。常量的话就是把 var 改成const,值在一提的是go语言里面的常量,它没有确定的类型,会根据使用的上下文来自动确定类型。

if-else

package main

func main() {
   // if - else
   if 7%2 == 0 {
      // 偶数
      println("7 is even")
   } else {
      // 奇数
      println("7 is odd")
   }

   // if - else if - else
   // num给其一个初始条件
   if num := 9; num < 0 { // 如果 num < 0
      println(num, "is negative") // 输出它是一个负数
   } else if num == 0 {
      println(num, "is zero") // 输出它是一个0
   } else {
      println(num, "is positive") // 输出它是一个正数
   }
}

循环

package main

func main() {
   // 死循环=while(true)
   for {
      println(1)
      break
   }

   // 打印0-9
   for i := 0; i < 10; i++ {
      println(i)
   }
}

/**
go没有while,没有do while,只有for循环
*/

switch

package main

import "time"

func main() {
   a := 2
   switch a {
   case 1:
      println("one")
   case 2:
      println("two")
   default:
      println("不知道")
   }

   t := time.Now()
   println(t)
   // 特殊用法,可以取代if - else
   switch {
   case t.Hour() < 12:
      println("早于中午")
   default:
      println("晚于中午")
   }
}

/**
switch自带一个break
*/

数组

package main

import "fmt"

func main() {
   var a [5]int
   a[0] = 100
   println(a[0], 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(twoD)

}

切片

package main

import "fmt"

func main() {
   // 用make创建切片,需要指定初始长度
   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

   // 新增,需要用一个切片变量接收,容量不够会扩容,返回一个新的slice
   s = append(s, "d")
   sNew := append(s, "e", "f")
   fmt.Println(sNew)

   // copy
   a := make([]string, len(sNew))
   copy(a, sNew)
   fmt.Println(a)

   // 切片操作
   fmt.Println(a[:])   // 所有
   fmt.Println(a[2:5]) // 区间[2,5)
   fmt.Println(s[:3])  // [0,3)
   fmt.Println(s[1:])  // 1到结尾

   // 简易定义
   good := []string{"g", "o", "o", "d"}
   fmt.Println(good)
   good = append(good, "!")
   fmt.Println(good)
   // 区别数组:   b := [5]int{1, 2, 3, 4, 5},是需要指定长度的
}

/**
切片是一个可变长数组,不用指定其长度。[]类型
*/

map

package main

import "fmt"

func main() {
   // key string, value int
   m := make(map[string]int)
   m["one"] = 1
   m["two"] = 2
   fmt.Println(m)
   fmt.Println(len(m))     //2
   fmt.Println(m["one"])   //1
   fmt.Println(m["two"])   //2
   fmt.Println(m["three"]) //0

   // ok 获取map中是否有这个key存在
   r, ok := m["three"]
   //fmt.Println(r)
   //fmt.Println(ok)
   fmt.Println(r, ok)

   // 删除key为one
   delete(m, "one")

   // 简易定义
   m2 := map[string]int{"one": 1, "two": 2}
   fmt.Println(m2)

   // 遍历map,同理可以遍历数组
   for key, value := range m {
      println(key, value) // key,value
   }
}

/**
map 是无序的
*/

rang遍历数组和map

package main

import "fmt"

func main() {
   arr := [3]int{}
   arr[0] = 1
   arr[1] = 2
   arr[2] = 3

   // index是数组下标,value对应的值
   for index, value := range arr {
      fmt.Println(index, value)
   }

   m := map[string]int{"one": 1, "two": 2}
   
   //key是map的key,value是map的value
   for key, value := range (m) {
      fmt.Println(key, value)
   }
}

函数

package main

func main() {
   println(add(1, 2))
   println(exists(map[string]int{"one": 1}, "two"))
}

// 函数名add,参数a,b均为int,返回值为int
func add(a, b int) int {
   return a + b
}

// 支持多值返回
func exists(m map[string]int, key string) (int, bool) {
   value, ok := m[key]
   return value, ok
}

指针

package main

func main() {
   n := 5
   add(n)
   println(n) // 5
   add2(&n)
   println(n) // 7
}

// 两个函数均没有返回值
func add(n int) {
   // 此时的n是add的局部变量,修改完后,当add函数执行完毕后,n消亡,不影响外部的变量值
   n += 2
}

func add2(n *int) {
   // 此时的n是一个指针,改动会改变原值
   *n += 2
}

/**
指针的主要用途,对传入的参数进行修改
*/

结构体-类 以及 方法

package main

import "fmt"

func main() {
   // 直接初始化时指定
   user := User{name: "chengyunlai", password: "root"}
   fmt.Println(user) // {chengyunlai root}
   // 修改名称
   user.name = "Cheng"
   fmt.Println(user) // {Cheng root}

   // 定义一个变量再指定属性
   user2 := User{}
   user2.name = "GoLang"
   fmt.Println(user2) //{GoLang }

   fmt.Println(checkPassword(&user, "123"))
   fmt.Println(user.checkPassword("123"))

}

type User struct {
   name     string
   password string
}

// 指针可以减少拷贝开销,也可以修改原值
func checkPassword(u *User, pass string) bool {
   return (*u).password == pass
}

// 结构体方法
func (u *User) resetPassword(password string) {
   u.password = password
}

func (u *User) resetUserName(userName string) {
   u.name = userName
}

func (u *User) checkPassword(pass string) bool {
   return (*u).password == pass
}

异常

package main

import (
   "errors"
   "fmt"
)

func main() {
   fmt.Println(isEquals("张三", "李四")) //false 不等
   fmt.Println(isEquals("张三", "张三")) //false 不等

   value, err := isEquals("张三", "李四")
   if err != nil {
      // 打印错误消息
      fmt.Println(err)
   } else {
      fmt.Println(value)
   }
}

// 错误是error类型,通过errors.xx 创建相应的错误
func isEquals(name, input string) (bool, error) {
   if name != input {
      return false, errors.New("不等")
   }
   // nil 表示 null
   return true, nil
}

字符串工具

package main

import (
   "fmt"
   "strings"
)

func main() {
   a := "hello"
   fmt.Println(strings.Contains(a, "ll"))                // true
   fmt.Println(strings.Count(a, "l"))                    // 2
   fmt.Println(strings.HasPrefix(a, "he"))               // true
   fmt.Println(strings.HasSuffix(a, "lo"))               // true
   fmt.Println(strings.Index(a, "ll"))                   // 2
   fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
   fmt.Println(strings.Repeat(a, 2))                     // hellohello
   //If n < 0, there is no limit on the number of replacements.所以1就是换一个,-1就是换全部
   fmt.Println(strings.Replace(a, "l", "L", 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.Println(len(a))                          // 5

}

格式化打印

package main

import "fmt"

// 字符串格式化
func main() {
   // 打印多个变量
   fmt.Println(1, 2)

   // 万能的%v占位符
   s := "hello"
   n := 123
   arr := [3]int{1, 2}
   fmt.Printf("s=%v\n", s)
   fmt.Printf("s=%v\n", n)
   fmt.Printf("s=%v\n", arr)
   // %+v详细
   // %#v更详细

}

json处理

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   user := User{Name: "Chengyunlai", Age: 24}
   fmt.Println(user) //{Chengyunlai 24}
   // 转json
   res, err := json.Marshal(user)
   fmt.Println(res)         //[123 34 78 97 109 101 34 58 34 67 104 101 110 103 121 117 110 108 97 105 34 44 34 65 103 101 34 58 50 52 125]
   fmt.Println(string(res)) //{"Name":"Chengyunlai","Age":24}
   fmt.Println(err)
   // 反序列化
   user2 := User{}
   json.Unmarshal(res, &user2)
   fmt.Println(user2) //{Chengyunlai 24}

}

// 1 要求结构体的变量首字母为大写
type User struct {
   Name string `json:"name"` // 当转json时指定key的名称
   Age  int    `json:"age"`
}

时间处理

package main

import (
   "fmt"
   "time"
)

func main() {
   now := time.Now()
   fmt.Println(now) //2023-05-12 17:32:12.0876215 +0800 CST m=+0.005319101

   // 构造时间
   t1 := time.Date(2023, 05, 12, 17, 32, 0, 0, time.UTC)
   t2 := time.Date(2023, 05, 12, 18, 32, 0, 0, time.UTC)
   fmt.Println(t1) //2023-05-12 17:32:00 +0000 UTC

   // 方法
   fmt.Println(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute())
   fmt.Println(t1.Format("2006-01-02 15:04:05")) //2023-05-12 17:32:00(无语这个格式。)
   diff := t2.Sub(t1)
   fmt.Println(diff)                           //1h0m0s
   fmt.Println(diff.Minutes(), diff.Seconds()) // 60 3600

   t3, err := time.Parse("2006-01-02 15:04:05", "2023-05-12 17:39:00")
   if err != nil {
      fmt.Println(err)
   }
   fmt.Println(t3)
   // 获取时间戳
   fmt.Println(now.Unix()) // 1683884463

}

数字字符串转数字

package main

import (
   "fmt"
   "strconv"
)

func main() {
   // 一个10进制字符串数字,转到X进制,精度是64位
   f, _ := strconv.ParseInt("111", 2, 64)
   fmt.Println(f) // 7

   n, _ := strconv.Atoi("123")
   fmt.Println(n) // 转数字
}

进程

package main

import (
   "fmt"
   "os"
   "os/exec"
)

func main() {
   // go run 这个程序 a b c d
   fmt.Println(os.Args) // [C:\Users\12579\AppData\Local\Temp\go-build3318116271\b001\exe\main.exe a b c d]

   fmt.Println(os.Getenv("PATH")) // 获取环境变量
   //fmt.Println(os.Setenv("AA","BB")) // 写入环境变量

   println("----")
   buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
   if err != nil {
      panic(err)
   }
   fmt.Println(string(buf))
}