Go语言的基础语法 | 青训营笔记

89 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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>来编译后运行。

总结与提升:

  1. 通常一个包的名字和包的导入路径的最后一个字段相同(即包所在的文件夹名),而main包是最特殊的包,它是Go程序的入口,一般在项目的根目录的main.go文件中声明。
  2. 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/templatehtml/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语言的循环可以使用continuebreak语句。

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语言原理与实践

Go语言圣经 (studygolang.com)