这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
年过完了,边写论文边学习的节奏也跟上了,Just do it!
一、环境安装(Ubuntu 18.04)
1. 安装包下载
点击下载 Linux 版本的以 tar.gz 结尾的 Go 二进制安装包。
2. 安装 Go 二进制包
-
进入安装包所在目录,将下载的二进制包解压至 /usr/local目录。
tar -C /usr/local -xzf go1.4.linux-amd64.tar.gz sudo mv go /usr/local/ -
将必要的环境变量添加至 PATH ,编辑 ~/.bashrc 加入下面三行代码。
export GOROOT=/usr/local/go export GOPATH=$HOME/go export PATH=$GOPATH/bin:$GOROOT/bin:$PATH -
刷新环境
source ~/.bashrc
-
从
Go 1.11版本开始,Go 提供了 Go Modules 的机制,推荐设置以下环境变量,第三方包的下载将通过国内镜像,避免出现官方网址被屏蔽的问题。go env -w GOPROXY=https://goproxy.cn,direct
二、基础语法
1. Hello World
-
新建一个文件
main.go,写入package main import ( "fmt" ) func main() { fmt.Println("hello world") }
- package main:声明了 main.go 所在的包,Go 语言中使用包来组织代码。一般一个文件夹即一个包,包内可以暴露类型或方法供其他包使用。
- import “fmt”:fmt 是 Go 语言的一个标准库/包,用来处理标准输入输出。
- func main:main 函数是整个程序的入口,main 函数所在的包名也必须为
main。 - fmt.Println(“Hello World!”):调用 fmt 包的 Println 方法,打印出 “Hello World!”
2. 变量
-
Go 语言与其他语言显著不同的一个地方在于,Go 语言的类型在变量后面
var a int // 如果没有赋值,默认为0 var a int = 1 // 声明时赋值 var a = 1 // 声明时赋值 // 自动确定的赋值方式 // int a := 1 // string msg := "Hello World!" // array arr := [5]int{1, 2, 3, 4, 5} // map m2 := map[string]int{ "Apple": 1, "Banana": 2, } // pointer *p = "Hello"
3. 简单类型
- 空值:nil
- 整型类型: int(取决于操作系统), int8, int16, int32, int64, uint8, uint16, …
- 浮点数类型:float32, float64
- 字节类型:byte (等价于uint8)
- 字符串类型:string
- 布尔值类型:boolean,(true 或 false)
4. 流程控制
-
if else 条件语句
if score := 60; score < 60 { ... } else { ... } -
for 循环
for i := 0; i < 5; i++ { ... } -
switch 分支选择
type Score int16 const ( NORMAL Score = 65 GOOD Score = 70 ) score := 70 switch score { case NORMAL: fmt.Println("normal") case GOOD: fmt.Println("good") default: fmt.Println("low") }if 和 for 语句在判断条件之前能够进行值的初始化!
5. 函数
-
一个典型的函数定义如下,使用关键字
func,参数可以有多个,返回值也支持有多个。特别地,package main中的func main()约定为可执行程序的入口。func funcName(param1 Type1, param2 Type2, ...) (return1 Type3, ...) { // body }
6. 结构体和方法
-
结构体类似于其他语言中的 class,可以在结构体中定义多个字段,为结构体实现方法,实例化等。接下来我们定义一个结构体 Student,并为 Student 添加 name,age 字段,并实现
hello()方法。type Student struct { name string age int } func (stu *Student) hello(person string) string { return fmt.Sprintf("hello %s, I am %s", person, stu.name) } func main() { stu := &Student{ name: "Tom", } msg := stu.hello("Jack") fmt.Println(msg) // hello Jack, I am Tom }
7. 错误处理
- 示例中,用 r 捕获了能够预知的错误,defer 用来接手出现 panic 以后的控制权
-
func get(index int) (ret int) { defer func() { if r := recover(); r != nil { fmt.Println("Some error happened!", r) ret = -1 } }() arr := [3]int{2, 3, 4} return arr[index] } func main() { fmt.Println(get(5)) fmt.Println("finished") }
8. 接口
-
不需要显式地声明实现了哪一个接口,只需要直接实现该接口对应的方法即可。
type Person interface { getName() string } type Student struct { name string age int } func (stu *Student) getName() string { return stu.name } type Worker struct { name string gender string } func (w *Worker) getName() string { return w.name }
9. JSON处理
-
go 语言言里面的 JSON 操作非常简单,对于一个已有的结构体,我们可以什么都不做,只要保证每个字段的第一个字母是大写,也就是是公开字段。那么这个结构体就能用 JSON.marshaler 去序列化,变成一个 JSON 的字符串。序列化之后的字符串也能够用 JSON.unmarshaler 去反序列化到一个空的变是里面。这样默认序列化出来的字符串的话,它的风格是大写字母开头,而不是下划线。我们可以在后面用 json tag 等语法去修改输出 JSON 结果里面的字段名。
package main import ( "encoding/json" "fmt" ) type userInfo struct { Name string Age int `json:"age"` // 表示可以用首字母小写的‘age’表示这个key Hobby []string } func main() { a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}} buf, err := json.Marshal(a) if err != nil { panic(err) } fmt.Println(buf) // [123 34 78 97...] fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]} buf, err = json.MarshalIndent(a, "", "\t") if err != nil { panic(err) } fmt.Println(string(buf)) var b userInfo err = json.Unmarshal(buf, &b) if err != nil { panic(err) } fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}} }
10. 时间处理
-
在 go 浯言里面最常用的就是 time.now() 来获取当前时间,然后你也可以用 time.date 去构造一个带时区的时间,构造完的时间。上面有很多方法来获取这个时间点的年月日小时分钟秒,然后也能用 sub 去对两个时间进行减法,得到一个时间段。时间段又可以去得到它有多少小时 , 多少分,多少秒。
now := time.Now() fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933 t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC) t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC) fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25 fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36 diff := t2.Sub(t) fmt.Println(diff) // 1h5m0s fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
11. 数字解析
-
go 浯言当中 , 关于字符串和数字类型之间的转都在 strconv 这个包下,用 parselnt 或者 parseFloat 来解析一个字符串 。用 Atoi 把一个十进制字符串转成数字,也可以用 itoA 把数字转成字符串 。
f, _ := strconv.ParseFloat("1.234", 64) fmt.Println(f) // 1.234 // 中间的参数10,代表按照10进制数进行解析 n, _ := strconv.ParseInt("111", 10, 64) fmt.Println(n) // 111 // 中间的参数0,代表按照规定字符书写前缀的进制数进行解析 n, _ = strconv.ParseInt("0x1000", 0, 64) fmt.Println(n) // 4096 n2, _ := strconv.Atoi("123") fmt.Println(n2) // 123 n2, err := strconv.Atoi("AAA") fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
12. 进程信息
-
用 os.argv 来得到程序执行的时候的指定的命令行参数 ,用 os.getenv 来读取环境变量 。
// go run example/20-env/main.go a b c d fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d] fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin... fmt.Println(os.Setenv("AA", "BB")) // 设置环境变量AA为字符串"BB" buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() if err != nil { panic(err) } fmt.Println(string(buf)) // 127.0.0.1 localhost
以上过了一遍 go 的基础,包括变量和语法以及一些必要的内部库用法,基本上能够让我能够看懂 go 代码的基本结构,也有很多小细节和小特性需要注意的地方,比如很多库函数会在第二返回值中返回错误信息,用 "_" 去跳过函数的某个返回值,汉语存储方式等等,需要更精细化的去看 go 语言在实际使用过程中对计算机资源的操作方式,以便能够更好的利用 go 的特性发挥出最大的价值。阅读《Go语言圣经》便是精细化的了解方式。