Go语言基础 | 青训营笔记

69 阅读7分钟

这是我参与「第五届青训营 」笔记创作活动的第1天

本堂课重点内容

  • Go语言的特点
  • Go语言基础语法
  • 实战案例

详细内容介绍

Go语言的特点

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

Go语言开发环境的搭建

  1. 安装golang

    golang官网: go.dev/

    其它下载地址:golangstudy.com.dl, goproxy.cn

  2. 安装vscode或goland

Go基础语法

1. hello world
import "fmt"

func main() {
    fmt.Println("Hello World!")
}

可使用命令go build main.go编译生成可执行文件。也可以直接使用go run main.go命令运行

2.变量
var a = "hello" 	//声明了一个 string 类型变量a, 值为"hello",编译器自动推导它的类型为string
var b, c int = 2, 3	//声明了两个int型变量,值默认为0
var d = true		//bool型
var e float64		//浮点型
f := float32(e) 	//省略var关键字,使用 := 声明变量

const s string = "constant"	//声明了一个string常量
const h = 50000
const i
  • go语言的变量类型有int int16 int32 int64 float32 float64 bool string等
  • 用var关键字声明变量,const关键字声明常量
  • 给出变量的初始化值,可省略变量类型,由编译器自动推导类型
  • 常量数值可以没有类型,被使用时会自适应类型
3 if-else

Go语言的if-else语句与C语言类似,但条件不需要小括号,大括号不可以换行

var maxv int
if a > b { 	//大括号不可换行
    maxv = a
} else {
    maxv = b
}
4 循环

Go语言只有for循环,没有while和do while循环。

与C语言一样,可以使用continue继续循环,使用break退出循环。

//死循环
for {	//相当于while(true)
    fmt.Println("loop")
}

//while循环
i := 0
for i <= 10 {
    i++
}

// 计算1 + 2 + 3 + ... + 100
s := 0
for i := 1; i <= 100; i++ {
    s += i
}
fmt.Println(s)
5 switch

go语言不需要在每个case最后写break

switch a {
case 1:
    fmt.Println("a=1")
case 2:
    fmt.Prineln("a=2")
default:
    fmt.Println("a!=1 or 2")
}

可以不指定swtich的变量,在每个case的后面写一个条件语句,第一个条件成立的case会被执行。

t = time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("It's before noon")
default:
    fmt.Println("It's after noon")
}
6 数组
//声明数组
var a [5]int
b := [5]int{1, 2, 3, 4, 5}

//二维数组
var twoD [3][3]int

注意不同长度的数组是不同类型的数据。

7 切片

切片(slice)表示一个可变长的的拥有相同类型元素的序列,类型通常写成[]T

s := make([]string, 3) //用make初始化slice,初始长度为3
s[0] = "a"
s[1] = "b"
s[2] = "c"

s = append(s, "d") //向slice后增加一个元素
s = append(s, "d", "e", "f") //增加多个元素

append(s, "d"),如果s还有空间,会直接在s后增加一个元素,如果容量不够,会再开一个新的容量更大slice,因此调用时必须用s = append(s, "d")

8 map

map是散列表的引用,类型是map[K]V,K和V是字典的键和值的类型

可以用make函数来创建一个map: ages := make(map[string]int)

m := make(map[string]int)
m["one"] = 1
m["two"] = 2

r, ok := m["unknown"] //如果map中有键"unknown"则ok返回true,否则ok返回false

delete(m, "one") 	//从map中删除一个键值对

键的类型必须是可以用==比较的类型

9 range

可以用for和range实现类型python的循环语句,用于遍历数组、slice、map等

nums := []int{2, 3, 4}
for i, num := range nums { // i是下标,num是值,可以用 _ 忽略下标或值
    fmt.Println(i, num)
}

m = map[string]int{"one":1, "two":2}
for k, v := range m { //k和v分别是键和值
    fmt.Printf("m[%v] = %v\n", k, v)
}
10 函数

go语言定义函数的格式为

func 函数名(参数) 返回值类型 {
	return 返回值
}

go语言的函数可以有多个返回值

func add(a int, b int) int {
    return a + b
}

func exists(m map[string]string, k string) (v string, ok bool ) {//此函数有两个返回值
    v, ok := m[k]
    return v, ok //返回两个值
} 
11 指针

go语言的指针与C语言类似。

func add2(n int) {
    n += 2
}
func add2ptr(n *int) { // *int为int类型的指针
    *n += 2
}
func main() {
    n := 5
    add2(n)
    fmt.Println(n)	// 5
    add2ptr(n)
    fmt.Println(n)	//7
}

Go语言函数参数是按值传递,函数接收的的参数是一个副本,对副本的赋值不会影响原变量。要在函数中改变原变量的值就要使用指针。

12 结构体

定义一个结构体类型

type User struct {
    Name 		string
    Password 	string
}

使用结构体

a := User{Name:"zhangsan", Password:"123456"}
b := User{"lisi", "123"}
fmt.Println(b.Name, b.Password) //用点访问结构体的字段

结构体指针

ptr := &User{Name:"wang5", "aaa"}
fmt.Println(ptr.Name) //指针也可以用点访问结构体的字段
13 结构体方法

定义结构体方法

type User struct {
    Name		string
    Password	string
}

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

func (u *User) resetPassword(password string) {
    u.password = password
}

在func关键字后面加个(t T)(t *T)即可将函数绑定为结构体方法,结构体变量和指针可以用点运算符调用方法。

14 错误处理

go语言的错误处理策略是,函数调用发生错误时返回一个附加的err作为错误值,习惯上将错误作为最后一个结果返回。

func divide(a int, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("can't divide zero")	//发生错误时,返回一个error
	}
	return a / b, nil
}

func main() {
    a := 10
    b := 2
    c, err := divide(a, b)
    if err != nil { //调用divide时发生了错误
        fmt.Println(err) //打印错误信息
        return
    }
}
15 字符串操作

strings包中有一些字符串操作函数

a := "hello"
//是否包含子串
strings.Contains(a, "ll")                // true
//子串出现次数
strings.Count(a, "l")                    // 2
//是否以特定字符串开头
strings.HasPrefix(a, "he")              // true
//是否以特定字符串结尾
strings.HasSuffix(a, "llo")             // true
//特定子串第一次出现的位置
strings.Index(a, "ll")                   // 2
//连接多个字符串
strings.Join([]string{"he", "llo"}, "-") // he-llo
//重复字符串
strings.Repeat(a, 2)                     // hellohello
//替换子串
strings.Replace(a, "e", "E", -1)         // hEllo
//分割字符串
strings.Split("a-b-c", "-")              // [a b c]
//转换为小写
strings.ToLower(a)                       // hello
//转换为大写
strings.ToUpper(a)                      // HELLO
//获取字符串长度(字节数,不是字符数)
fmt.Println(len(a))                                   // 5
b := "你好"
fmt.Println(len(b)) // 6
16 字符串格式化

可以使用fmt.Printf()函数格式化输出字符串,与C语言的printf()函数类似。可以用%v格式化任务数据类型。用%+v%#v输出变量的详细信息。

fmt.Printf()格式化输出

fmt.Errorf()格式化输出错误

fmt.Fprintf()格式化输出到特定writer

fmt.Sprintf()格式化并返回string

17 JSON处理

json.Marshal()将结构体转化成json,用json.Unmarshal()将json转化为结构体。

定义结构体,可以用json注解表示该字段在json中的名字

type Human struct {
    Name  string `json:"name"`
	Age   int `json:"age"`
}

json.Marshal将结构体转化为json,返回值类型是[]byte

a := Human{"Lisi", 22}
buf, err := json.Marshal(a)
if err != nil { //转化发生错误
    panic(err)
}
fmt.Println(string(buf))//转化为json字符串输出

可以使用json.MarshalIndent(a, "", "\t")获得具有缩进,更可读的json字符串。

json.Unmarshal[]bytejson解析为结构体

var b Human
err = json.Unmarshal(buf, &b)
if err != nil {
    pannic(err)
}
18 时间处理

time.Now()获取当前时间,返回值为类型为Time,表示当前时间

time.Date(2023, 1, 20, 22, 30, 30, 30, time.UTC)将指定时间指定为Time类型

t.Format("2006-01-02 15:04:05")格式化时间,将Time类型变量转化为字符串,用"2006-01-02 15:04:05"这个特定时间表示格式。

t.Sub(t1)计算时间t和时间t1的差

time.Parse("2006-01-02 15:04:05", "2023-01-20 22:30:30")将字符串解析为Time类型,第一个参数是格式。

19 数字解析

strconv包提供了一些用于转化数字和字符串的函数

strconv.Parseint("111", 10, 64)将字符串转化为int类型,第二个参数为进制数,第三个参数为返回值位数,返回值类型为(int64, error)

strconv.ParseFloat("3.14", 64)解析浮点数,返回(Float64, error)

strconv.Atoi("123")string转int,返回(int, error)

20 进程信息

os.Args获取命令行参数

os.Getenv("PATH")获取环境变量

exec.Command("grep", "127.0.0.1", "/etc/hosts")在终端执行命令

引用参考