Go语言上手-基础语法 | 青训营笔记

115 阅读11分钟

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

7bd5f6f8edb2c0897a0db9c82d9380d.jpg

一、学习准备

为了帮助一些还没有安装go的朋友,这边提供教程和工具。

环境安装(win10安装)

1.进入网址进行windows10版本下载并安装

地址:<https://golang.google.cn/dl/>

选择.msi文件下载安装

2.在cmd修改相关环境

    set GO111MODULE=on
    set GOPROXY=https://goproxy.cn

相关说明配置:

GOPATH: Go项目的位置,现在我们用GO MOD来管理项目
GOROOT: 这个就是我们的go的安装路径

3.VSCode相关配置

按ctrl+shift+p 调出命令面板,输入go install tools 选Go: Install/Update Tools

本地展示图: image.png

4.VsCode的插件推荐

  • code runner
  • go
  • tabnine

5.在线平台

如果你有 github 的话,可以很方便地使用 gitpods.IO 的在线编程环境来试用 golang 。

只需要浏览器打开 gitpod.io/#github.com… ,用你的 github 账号登录,就可以打开这个课程的示例项目开始编码 。

二、GO语法基础

Go 语言

  1. package main 代表这个文件属于 main 包的一部分,main 包也就是程序的入口包。

  2. 通过import导入了标准库里面的包、如FMT包。这个包主要是用来往屏幕输入输出字符串、格式化字符串。

  3. import 下面是 main 函数,main 函数的话里面调用了 fmt.Println 输出 helloword 要运行这个程序的话,我们就直接 go run 文件名.go

  4. 如果我们想编译成二进制的话,可以在 go build 来编译。编译完成之后直接通过指令 ./文件名 就可以运行。

A. 基础语法 - 变量和常量

go语言是一门强类型语言,每一个变量都有它自己的变量类型。 常见的变量类型包括

  • 字符串
  • 整数
  • 浮点型
  • 布尔型等等。

变量的声明有两种方式:

1.  通过 var name string = "" 这种方式来声明变量,声明变量的时候,一般会自动去推导变量的类型。如果有需要,你也可以显示写出变量类型。
2.  使用变量 冒号 := 等于值。

常量的声明:

大致与变量一样,仅仅将 **var** 改成 **const**

注意: go语言里面的常量,它没有确定的类型,会根据使用的上 下文来自动确定类型

B. 基础语法 - if

  • go 中 if 后面没有括号,即使你写括号的话,那么在保存的时候编辑器会自动把你的括号去掉。
  • go 中的 if 后面必须接大括号,不能像 C 或者 C++语言直接把 if 里面的语句同一行。

PS: go 去掉了大部分控制语句中需要使用表达式的地方的括号,如 if, for, switch 等。

C. 基础语法 - 循环

  1. go语言没有 while、do while循环,只有唯一的 for 循环
  2. 最简单的 for 循环是 for 后面什么都不写,是一个死循环。
  3. 循环途中可以使用 break 跳出,也可以使用经典的三段循环,这三段,任何一段都可以省略。

PS:可以使用 break 和 continue 来跳出或继续循环。

D.基础语法 - switch

  1. 与 C 或者 C++ 比较类似,与if与for一样,加变量名而不需要括号

  2. 相比 C 或者 C++ , go语言里面的 switch 功能更强大。

    强大的点在于:在C++里面,switch case如果不显示加 break 的话会继续向下运行,但是在go语言中不需要添加break;

    • 在go语言中,我们可以使用任意的变量类型,甚至可以用来取代任意的 if else 语句。
    • 不仅如此,你可以在 switch 后面不加任何的变量,然后在 case 里面写条件分支,这使得代码相对于ifelse更为清晰。

E. 基础语法 - 数组

数组定义:一个具有编号且长度固定的元素序列。

  1. 对于一个数组,可以很方便地取特定索引的值或者往特定索引取存储值,可以直接打印一个数组。
  2. 在真实的业务代码里面,很少直接使用数组,因为它的长度是固定的,我们用的更多的是切片

F. 基础语法 - 切片

切片不同于数组,它可以任意的更改长度,同时也具有更多丰富的操作。

如,

  1. 使用 make 来创建一个切片,可以像数组一样去取值,使用 append 来追加元素。 注意 append 的用户,需要把 append 的结果赋值为原数组。
  2. slice 的原理实际上是它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行 append 操作的时候,如果容量不够的话,会扩容并且返回新的 slice 。
  3. slice 初始化的时候可以指定长度。
  4. slice 拥有像 python 一样的切片操作(左开右闭),例如 [2:5] 这个代表去除第二个到第五个位置的元素,不包括第五个元素
  5. 不同于python,这里不支持负数索引。

G. 基础语法 - map

在其他的编程语言中,它常被叫做哈希或者字典。

在go语言中,map 是实际使用过程中最频繁的数据结构。

  1. 使用 make 来创建一个空的 map ,这里会需要两个类型,第一个是 key 的类型,另一个是 value 的类型。
  2. 可从里面去存储或取出键值对,可以用delete从里面删除键值对。
package main

import "fmt"

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

	r, ok := m["unknow"]
	fmt.Println(r, ok) // 0 false

	delete(m, "one")

	m2 := map[string]int{"one": 1, "two": 2}
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)
}

需要注意 golang 中的 map 是完全无序的,遍历的时候不会按照字母进行排序,也不会按照插入顺序输入,而是随机顺序

H.基础语法 - range

对于一个 slice 或 map ,我们可以通过 range 来快速遍历  

这样可以使得代码更加简洁。

range 遍历的时候,对于数组会返回两个值(第一个是索引,第二个是对应位置的值)。如果我们不需要索引的话,可以使用下划线来忽略。

I. 基础语法 - 函数

golang 函数中和其他语言不同的是,变量类型是后置的

函数原生支持返回多个值

在真实业务的go语言,逻辑代码里面几乎所有的函数都返回两个值: 第一个是返回结果 第二个值是一个错误信息。

package main

import "fmt"

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
}

func main() {
	res := add(1, 2)
	fmt.Println(res) // 3

	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // A True
}

J. 基础语法 - 指针

golang中的指针,相比 C 和 C++ 里面的指针,支持的操作很有限。

指针的一个重要用途就是对于传入参数进行修改

可以看下面的代码,例子中add2函数中试图把一个变量+2,但是单纯像该函数中的写法是无效的,因为传入函数的参数实际上是一个拷贝,+2也只是对拷贝的+2,对实际的值没有起作用。

如果要使其起作用,就要将该类型写成指针类,同时也要类型匹配,下图中add2ptr函数,调用的时候会增加一个 & 符号。

package main

import "fmt"

func add2(n int) {
	n += 2
}

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

func main() {
	n := 1
	add2(n)
	fmt.Println(n) // 3
	add2ptr(&n)
	fmt.Println(n) // 用到了指针,n值不为1,已经加了2了,显示为5
}

K. 基础语法 - 结构体

结构体定义:带类型的字段的集合

例如,下面代码中 user 结构包含了两个字段,name 和 password。

  1. 可以用结构体的名称去初始化一个结构变量,构造的时候需要传入每个字段的初始值。
  2. 可以用这种键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。
  3. 能支持指针,这样能够实现对于结构体的修改,也可以在某些情况下避免一些大结构的拷贝开销。
package main

import "fmt"

type user struct {
	name     string
	password string
}

func main() {
	a := user{name: "wang", password: "1024"}
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	fmt.Println(a, b, c, d)                 // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
	fmt.Println(checkPassword(a, "haha"))   // false
	fmt.Println(checkPassword2(&a, "haha")) // false
}

func checkPassword(u user, password string) bool {
	return u.password == password
}

func checkPassword2(u *user, password string) bool {
	return u.password == password
}

L. 基础语法 - 结构体方法

在golang中可以为结构体定义方法,类似于其他语言里面的类成员函数。

从上面代码中可以看到:checkPassword 的实现,从一个普通函数改成了结构体的方法,这样用户可以使用 a.checkPassword() 这样调用,具体的代码修改:把第一个参数加上括号,写到函数名称前面。

package main
import "fmt"
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() {
	a := user{name: "wang", password: "1024"}
	a.resetPassword("2048")
	fmt.Println(a.checkPassword("2048")) // true
}

实现结构体的方法

  • 带指针
  • 不带指针

区别:如果带指针,那么你就可以对这个结构体去做修改,否则你实现的操作仅仅是一个拷贝,无法对结构体进行修改。。

M. 基础语法 - 错误处理

符合go语言习惯的做法:

使用一个单独的返回值来传递错误信息

在函数里面,我们可以在函数的返回值类型里面,增加一个error,代表这个函数可能返回错误。

在函数实现的时候,return需要同时return两个值。

  • 如果出现错误的话,就可以return nil 和一个 error 。
  • 如果没有的话,那么就返回原本的结果和 nil。

N. 基础语法 - 字符串操作

在标准库 strings 包里面有很多常用的字符串工具函数

  1. contains 判断一个字符串里面是否有包含另一个字符串
  2. count 字符串计数
  3. index 查找某个字符串的位置
  4. join 连接多个字符串
  5. repeat 重复多个字符串
  6. replace 替换字符串
  7. 等等

O. 基础语法 - 字符串格式化

在标准库的 FMT 包里面有很多的字符串相关的方法。

go的printf类似于C中的printf函数,不同的是, 在go语言中,

  1. 可以使用 %v 来打印任意类型的变量,不需要区分数字字符串等其他类型。
  2. 可以使用 %+v来打印详细的结果,%#v则更加详细。

P. 基础语法 - JSON 处理

go中的 JSON 操作非常简单,对于一个已有的结构体——只要保证每个字段的第一个字母是大写即公开字段:

  1. 那么这个结构体就能用 JSON.marshaler 去序列化;变成一个 JSON 的字符串。
  2. 序列化之后的字符串也能够用 JSON.unmarshaler 去反序列化到一个空的变量里面。

这样默认序列化出来的字符串,它的风格是大写字母开头,而不是下划线,可以在后面用 json.tag 等语法来修改输出 JSON 结果里面的字段名,代码如下所示。

type userInfo struct {
	Name  string
	Age   int `json:"age"`
	Hobby []string
}

Q. 基础语法 - 数字解析

字符串和数字之间的转换是如何进行的。

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

  1. 可以使用 parseInt 或者 parseFloat 来解析一个字符串

  2. 可以使用 Atoi 把一个十进制字符串转换成数字,可以用 itoA 把数字转换成字符串

  3. 如果输入不合法,那么这些函数都会返回 error。

R. 基础语法 - 进程信息

在 go 中,我们能够用 os.argv 来得到程序执行的时候的指定命令行参数。

但其实可能大家用的频率不高。

S. 基础语法 - 时间处理

  • 在go语言里面最常用的就是 time.now() 来获取当前时间

  • 可以用 time.date 去构造一个带时区的时间,构造完的时间(具有一定格式)

  • 能用点 sub 去对两个时间进行减法,得到一个时间段,得到时间段后可以写相应的Minutes(),Seconds()……

  • 可以用 .UNIX 来获取时间戳,可以作为时间参数值设置随机种子

三、实例

3.1 猜数字

3.2 在线词典

3.3 Socks5 代理

需要大家好好听课,然后研究透三个例子。

四、总结

认真对待课程,有选择性的听课,达到高效学习的效果,互勉加油!