1月15日Day1 Go语言基础语法|青训营笔记

114 阅读8分钟

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

Go 语言上手-基础语言

什么是 Go 语言|Go 语言的特点

  1. 高性能、高并发
  2. 语法简单,学习曲线平缓。Go语言类似于C语言,但进行了诸多语法简化,如去掉了while循环,只保留了for循环。
  3. 有丰富的标准库。进行一些基本的开发不需要调用第三方的库,安全性更高。
  4. 有完善的工具链
  5. 静态链接
  6. 快速编译,C++er的福音。
  7. 跨平台性
  8. 和JVM一样的垃圾回收的功能,无需考虑内存的分配和释放,专注于业务逻辑。

Go 语言入门

Go 语言的开发环境

1.  下载GOlang。
    1)浏览器输入 go.dev 打开 Golang 官网,点击 download 按照提示就可以安装Golang
    2)可以尝试使用 Golang 中国的镜像 https://studygolang.com/dl 。
    3)如果访问 github的速度非常慢的话,你可以配置 gomod proxy,按照提示打开 https://goproxy.cn/
2.  使用VScode或者其他IDE编辑器
    1)安装 vsCode,直接从官网下载安装即可,安装完成之后,需要在左边扩展里面搜索 Go 插件然后安装
    2) Goland 是由 JetBrains 公司开发的一个新的商业 IDE。Goland 是一个收费软件,我们可以直接从官网下载。在校学生可以申请免费的教育许可证。
    3)使用 gitpods.IO 的在线编程环境来试用 golang,只需要浏览器打开 https://gitpod.io/#github.com/wangkechun/go-bv-example。
    用github账号登录即可试用。
3.  配置环境变量

Go 语言基础语法

体验 Go 的第一个程序:Hello World!

package main

import "fmt"

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

Go 语言的变量类型:

  1. Go语言是一门强类型语言,每个变量都有它自己的变量类型。
  2. 常见的变量类型包括:字符串 整数 浮点型、布尔型等。
  3. Go语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。
  4. Go语言大部分运算符的使用和优先级都和 C 或者 C++ 类似,这里就不再概述。

变量的声明两种方法

var name int = 2

name := 3 // Go语言中不需要加分号!

常量的声明

const s string = "constant" //就是把 var 改成const
const h = 500 
const i = 3e20 / h //Go语言里面的常量没有确定的类型,会根据使用的上下文来自动确定类型

Go 语言中 if-else、switch 和 for 循环

  1. Golang中if 后没有括号,如果你写有括号,那么在保存时编译器会去除你的括号。
  2. if 和 else 后边必须带有花括号,不能将代码和if写在同一行。
if 7%2 == 0 {
    fmt.Println("7 is even")
} else {
    fmt.Println("7 is odd")
}

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")
}

switch 后不用括号,并且每一行结尾会默认加break。

switch a {
    case 1: 
        fmt.Println("one")
    case 2: 
        fmt.Println("two")
    default: 
        fmt.PrintLn("other")
}
  1. Go语言只有唯一的一种for循环。
  2. 最简单的 for 循环就是在 for 后面什么都不写,代表一个死循环。
  3. 也可以使用经典的 C 循环,这中间三段,任何一段都可以省略。
  4. 可以用 break 或者 continue 来跳出或者继续循环
for {
    fmt.Println("loop")
    break
}

for n := 0; n < 5; n++ {
    if n%2 == 0 {
        continue
    }
    fmt.Println(n)
}

Go 语言的切片:

  1. 切片是一个可变长度的数组
  2. 切片是引用传递,数组是值传递。
  3. 可以任意时刻更改切片的长度。切片可以用make创造,并且分配容量。
  4. 切片可以用append追加容量和数值,增加后必须要有一个接收值,对于原切片并不会改变。

注意: Go 中 slice 实际上是存储了一个长度加容量加上一个指向数组的指针。append 的过程中该切片容量不够,则会发生扩容,这个时候就需要返回一个新的切片,所以必须赋值回去。

s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"

s = append(s, "d")
s = append(s, "e", "f")

fmt.Println(s[2]) // c
fmt.Println(s) // [a b c d e f]
fmt.Println(s[2:5]) // 表示打印 slice 中从下标区间[2,5)的元素,即 c d e
fmt.Println(s[:5]) // 表示打印 slice 中从下标区间[0,5)的元素,即 a b c d
fmt.Println(s[2:]) // 表示打印 slice 中从下标区间[2,末尾)的元素,即 c d e f

可以用 copy 拷贝切片数值。

c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]

也可以直接初始化

good := []string{"g","o","o","d"}

Go语言中的map

map[key]value的数据类型

map["one"] = 1
map["two"] = 2       // 写入
fmt.Println(m)       // map["one":1 "one":2]
fmt.Println(m["one"])// 读取

r, ok := m["unknown"]// r 为接收 value, ok 用来判断 map 中是否有这个key存在。

delete(m, "one")     // 通过delete来删除map中的key

m2 := map[string]int{"NO1":1, "NO2":2}
var m3 = map[string]int{"NO1":1, "NO2":2}

注意:map中的数据是完全无序的,他不会按照输入的先后顺序输出。

Go 语言中的 range

  1. 使用 range 可以快速遍历
  2. 遍历数组的时候会返回两个值,第一个值为数组下标,第二个值为数组下标所对应的值。
  3. 遍历 map 的时候 第一个返回值是 key 第二个值是 value ( map 是随机的)
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
    fmt.Println(k, v) // b B; a A 可能是无序的
}

Go 语言中的函数

  1. Go 语言中函数变量类型写在变量之后,返回值类型也写在最后,开头必须用func
  2. Go 语言中的指针主要作用就是修改值传递为引用传递,使函数中的内容得到全局修改。
  3. Golang 里面的西数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是返回结果,第二个值是一个错误信息
func exists(m map[string]string, k string) (v string, ok bool) {
    v, ok = m[k]
    return v, ok
}

Go 语言中的指针

  1. Go 语言也支持指针。相比 C 和 C++ 里面的指针,支持的操作很有限。指针的一个主要用途就是对于传入参数进行修改。
func add2(n int) {
    n += 2
}

func add2ptr(n *int) {
    *n += 2
}

func main(){
    n := 5
    add2(n)
    fmt.Println(n) // 5
    add2ptr(&n)
    fmt.Println(n) // 7
}

Go 语言中的结构体

// 结构体的定义方法
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 main() {
    //结构体的快速设置变量以及赋值的方法
    c := user{name: "wang"}
    c.password = "1024"
    c.resetPassword("2048")
    fmt.Println(c.checkPassword("2048")) // true
}

注意:

  1. 结构体也是一种值传递。如果想要修改传入的数据需要借助于指针。结构体方法和函数不同。
  2. 注意引用的方法首字母一定要大写。在引用其他包的时候,所定义的函数或方法如果首字母是小写,则只可以在原包中使用而无法被其他包所调用。

Go 语言中的错误处理

  • 在定义一个函数时,可以返回一个 error 错误类型(需要引入 error 包)如果发生了错误就返回一个错误信息,否则返回一个空值。
  • 在调用这些定义了error返回值的函数时,也需要接收两个值,判断是否错误时,只需判断error的返回值是否为nil。

Go 语言中的字符串操作

  • strings.Contains 判断一个字符串中是否包含另一个字符串
  • strings.Count 符串计数
  • strings.Index 判断另一个字符串在这个字符串中首次出现的下标位置
  • strings.Join 在指定位置的字符串中加入某些字符串
  • strings.Repeat 重复打印n次字符串
  • strings.Replace 把全部的e替换为E,-1表示全部替换 正数表示替换几个
  • strings.Split 替换指定字符串为空
  • strings.ToLower 打印小写的字符串
  • strings.ToUpper 打印大写的字符串
  • 一个中文占据3个字节
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, "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
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

Go 语言中的字符串格式化

在标准库的 fmt 包里面有很多的字符串格式相关的方法,比如 printf 这个类似于 C 语言里面的printf 函数。不同的是,在go语言里面的话,你可以很轻松地用 %v 来打印任意类型的变量,而不需要区分数字字符串。你也可以用 %+v 打印详细结果,%#v 则更详细。

type point struct {
    x, y int
}

s := "hello"
n := 123
p := point{1, 2}

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}

Go 语言中的json

  • 对于字段首字母大写的结构体,都可以用json.Marshal将其序列化。
  • 可以使用json.Unmarshal(序列化, &结构体变量)进行反序列化。

Go 语言中的时间处理

  • time.Now()快速获取当前时间。
  • time.Data()构造一个带时区的时间。
  • 可以用sub来对时间进行一个减法,然后获得时间差
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
diff := t2.Sub(t)
fmt.Println(diff)                           //1h5m0s
  • Format格式化时有一个特定的时间 :2006-01-02 15:04:05

Go 语言中的数字解析

在 Go 语言当中,关于字符串和数字类型之问的转换都在 strconv 这个包下,这个包是 string convert 这两个单词的缩写。

  • 可以用 parselnt 或者 parseFloat 来解析一个字符串。parseint 参数
  • 我们可以用 Atoi 把一个十进制字符串转成数字。可以用 itoA 把数字转成字符串。如果输入不合法,那么这些函数都会返回error
package main

import (
    "fmt"
    "strconv"
)

func main(){
    f, _ := strconv.ParseFloat("1.234", 64)
    fmt.Println(f) // 1.234
    
    n, _ := strconv.ParseInt("111", 10, 64) // 第二个参数指定生成几进制
    fmt.Println(n) // 111
    
    m, _ := strconv.Atoi("123")
    fmt.Println(m) // 123
    
    n2, err := strconv.Atoi("AAA")
    fmt.Println(n2) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}

Go 语言中的进程信息

在 Go 里面,我们能够用 os.argv 来得到程序执行的时候的指定的命令行参数。 比如我们编译的一个二进制文件,command。后面接 abcd 来启动,输出就是 os.argv 会是一个长度为 5 的slice ,第一个成员代表二进制自身的名字。 我们可以用 so.getenv 来读取环境变量exec。

总结

本文主要对第五届青训营基础班的后端入门课程进行了总结,很多内容摘自《Go 语言原理与实践》课程的内容,旨在对本次青训营课程做笔记记录课程所学的内容。虽然我有很多地方不懂,但是我会尽力做到要求,力求本次青训营能学到一些东西。