这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
今天学习的主要内容是Go语言的基础语法和具体运用,其实大部分编程语言都是相通的,因为有C/C++和Python的基础,所以这部分内容还算容易理解。下面的笔记主要总结了Go语言比较特殊的一些内容,并且和C/C++做了一些对比和总结。
个人水平有限,如果有错误的地方还请指正。
0x00 Hello, World
每个Go的源文件都必须以包(package)的声明语句开始,然后是导入的其它依赖包,最后才是包一级的类型、变量、常量、函数声明等。
下面是最简单的输出Hello world的Go源代码示例:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
我们可以直接使用go run <filename>来运行它,或者使用go build <filename>来编译后运行。
总结与提升:
- 通常一个包的名字和包的导入路径的最后一个字段相同(即包所在的文件夹名),而main包是最特殊的包,它是Go程序的入口,一般在项目的根目录的
main.go文件中声明。 - Go的源代码要求简洁,因此导入的依赖包都必须被使用,声明的变量也必须被使用;
0x01 数据类型
1.1 基础数据类型
Go语言的基础数据类型有整型、浮点数、复数、布尔型、字符串和常量
| 数据类型 | 类型名 |
|---|---|
| 整型 | int8、int16、int32、int64、uint8、uint16、uint32、uint64 |
| 浮点数 | float32、float64 |
| 复数 | complex64、complex128 |
| 布尔型 | bool |
| 字符串 | string |
| 常量 | const |
值得注意的是Go语言没有C/C++中的字符char类型,表示一个Unicode字符可以使用rune类型,它和int32是等价的类型,通常用于表示一个Unicode码点;同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
1.2 复合数据类型
Go语言的复合数据类型有数组、切片、Map、结构体、JSON、文本和HTML模板
| 数据类型 | 描述 |
|---|---|
| 数组 | 固定长度的特定类型元素组成的序列,如[3]int为长度为3的int类型的一维数组 |
| 切片 | 代表变长的序列,一般写作[]T |
| Map | 哈希表是一种巧妙并且实用的数据结构,它是一个无序的key/value对的集合 |
| 结构体 | 一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体 |
| JSON | 由标准库中的encoding/json支持 |
| 文本和HTML模板 | 由text/template和html/template等模板包提供 |
重点1 数组(array)
Go语言的数组是一个固定长度的特定类型元素组成的序列,它和C/C++的数组类似,需要提前定义数组的长度,长度不能是变量,可以是固定值或者常量:
const size = 5
nums := [size]int{1, 2, 3, 4, 5}
nums := [5]int{1, 2, 3, 4, 5}
我们可以通过索引读取数组某个位置的值,也可以使用len函数获取数组的长度:
fmt.Println("nums[2]:", nums[2])
fmt.Println("len:", len(nums))
重点2 切片(slice)
Go语言的切片是一个特定类型元素组成的变长的序列,一般使用make函数构造,也可以通过赋值的方式构造:
nums := make([]int, 3) // 构造一个长度为3的整型类型的切片,切片所有值默认为0
nums := []int{1, 2, 3}
Go语言也有和Python类似的使用:来获取切片或者数组的其中一些元素(左闭右开),但是不能使用负数表示倒数第几个位置:
s := []string{"a", "b", "c", "d", "e", "f"}
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
我们可以通过上述方法,使用append来添加元素或者删除元素:
nums := []int{1, 2, 3}
nums = append(nums, 5, 6, 7) // 尾部添加
nums = append([]int{0}, nums...) // 头部添加 (两个切片相加, 切片需要解包)
nums = append(nums[:4], append([]int{4}, nums[4:]...)...) // 第4和第5个位置中间添加元素
nums = append(nums[:4], nums[5:]...) // 删除第五个元素
重点3 结构体
Go语言结构体struct和C++类似,既可以单纯的表示为结构体,又可以是面向对象的类(class)。在面向对象编程中,Go语言没有显示的私有(private)和公有(public)的字段声明,而是使用大小写区分,大写则表示公有可以被导出,小写则表示私有只能在包内使用,该规则适用于所有的方法名、常量名、变量名、结构体名等。
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
}
user类(结构体)的成员变量和成员函数均为小写开头,故为私有不能被导出。
0x02 声明
2.1 变量声明
带类型的变量声明
var <name> <type> = <expression>
var age uint8 = 24
var cnt int // 未初始化则为 0
var commit bool // 未初始化则为false
由表达式推导类型的变量声明
var <name> = <expression>
<name> := <expression>
var age = 24
commit := true
nums := make([]int, 0)
2.2 常量声明
常量的声明同样有带类型的和不带类型的两种
const pi = 3.1415926
const pi float64 = 3.1415926
2.3 函数声明
和所有编程语言一样,函数声明包括函数名、形式参数列表、返回值列表以及函数体
func name(parameter-list) (result-list) {
body
}
总结和提升:
在C++编程中,对于包含数据较多的变量一般采用& (引用)的方式传参,对应到Go语言就可以用指针进行传参;还有一点值得注意的是,C++编程中可以在使用const字段修饰引用的参数,以避免程序员错误地对引用参数进行修改,而Go语言似乎并没有这一约束。
0x03 基本语句
3.1 循环语句
Go语言只有一种循环语句,即for循环,和C/C++一样,Go语言的循环可以使用continue和break语句。
for i := 1; i < 10; i++ {
...
}
for i<10 {
...
}
使用for循环遍历数组nums := [10]int{2, 3, 5, 4, 7, 8, 9, 10, 22, 0}
for i := 0; i < len(nums); i++ {
fmt.Printf("nums[%d]: %d\n", i, nums[i])
}
我们也可以采用和Python类似的for-range进行遍历:
for i, num := range nums {
fmt.Printf("nums[%d]: %d\n", i, num)
}
3.2 判断语句
Go语言同样也有if语句和switch语句。它和C/C++类似,但是Go语言不需要对表达式加括号。
if <expression> {
...
} else if {
...
} else {
...
}
和C/C++不同,Go语言的switch语句不需要在每个case语句结尾加break
switch <var> {
case <expression 1>:
...
case <expression 2>:
...
case <expression 3>:
...
case <expression 4>:
...
default:
...
}
0x04 其他
4.1 指针
Go语言也有指针,但是Go语言的指针功能没有C/C++强大。当一个函数传入的形参数据量过大时,我们就可以使用指针的方法传参,从而节省内存开销:
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2ptr(&n)
fmt.Println(n) // 7
}
但是Go语言的函数形参不能向C++一样使用const进行修饰,因此可能出现对指针数据的错误修改,导致未知错误的发生,需要我们特别注意。
4.2 Error
Go语言的Error错误提示在error包中:
errors.New("user not found")
Go语言中很多包的方法都会在返回值中添加Error信息
4.3 其它
Go语言中还有支持时间运算的time包,支持JSON数据处理的json包等。
参考
[青训课视频] 后端入门-Go语言原理与实践