Go语言学习笔记

基于Go指南的个人总结

  博主通过Go官网提供的学习文档进行Go语言的学习,并整理笔记,记录如下!

一、包、函数、变量、常量

1、包的导入与导出

  包的导入:无论导入一个包还是多个包,为了便于后续再添加、更改,使用如下语法

1
2
3
4
5
6
import (
"package1" // 熟悉吗,Go的注释方法同C、C++一致
"package2/package3" // 导入package2包中的package3子包
"package4" // 导入package4
····
)

  包的导入 > 注:导入的包必须使用,不使用则Go语言会报错 —-> “包名” imported and not used

  包的导出:在自定义包/标准库中,如果你想让其他包访问某些函数、类型、变量或常量,你需要以大写字母开头来声明它们;在引用某一包中的元素时,需要增加包名作前缀以使程序识别

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"math/rand" // 导入math中的rand包,包名即为rand
"fmt" // 导入fmt包,包名即为fmt
)

func main() {
fmt.Println(rand.Intn(100)) // 生成一个0到99之间的随机整数并输出
// fmt.println(rand.Intn(100)) // 错误,因为能导出包的首字母均大写,引用包中属性时,也需要首字母大写
// fmt.Println(math.Intn(100)) // 错误,前缀需为包名,故引用函数Intn()前应加rand
}

2、函数定义

  函数基本结构:func ~1 ( ~2 ) ( ~3 ) { ~4 }

  ~1:函数名,首字母大写与小写会导致函数是否能被导出

1
2
func Myfunction() {}   // 可以被外部程序导出并使用
func myfunction() {} // 只能在包内部才能被识别,外界无法使用

  ~2:参数列表,可以设置1或多个传入参数,也可以不设置参数;设置参数需要参数名与参数类型,参数名在参数类型前面

1
2
3
4
5
6
func myfunction() {}                     // 不设置参数
func myfunction(x int) {} // 设置int型参数x
func myfunction(x int, y int) {} // 设置int型参数x、y
func myfunction(x, y int) {} // 多个相同类型参数可以合并参数类型写于末尾
func myfunction(x int, y string) {} // 设置int型参数x,string型参数y
func myfunction(x, y int, z string) {} // 设置int型参数x、y,string型参数z

  ~3:返回值,可以设置一个或多个返回值,逗号分隔;( 特色!:返回值也可以取名字,作用独特)

1
2
3
4
func myfunction(a int, b int) int {}               // 单个返回值或无返回值可以省略括号
func myfunction(a int, b int) (int, string) {} // 多返回值需对应一一点名类型
func myfunction(a int, b int) (int, int) {} // 多个相同类型返回值,类型不能省去(没有人会这么想吧我想)
func myfunction(a int, b int) (x, y int) {} // 当然,当返回值取了名字,就不一样了,相同类型返回值可以合并

  ~3 > 特性:当返回值有名字后,被称为命名返回值或裸返回值,它们会被视作定义在函数顶部的变量,当函数使用的return语句不跟参数时,会自动返回这些特殊的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 一般返回值:return语句后必须跟参数,逗号隔开,类型顺序对应
func myfunction(a int, b int) (int, int) {
return b, a
}
// 命名返回值、一般返回值不可混合使用
return语句后允许不跟参数,自动按序返回命名返回值的值
func myfunction(a int, b int) (x, y int) {
// 如果不对这些返回值赋值,它们会正常输出程序自动初始化的值,int型为0,string型为"",bool型为false
// 在返回值中声明命名返回值,等效为在函数开头将其视为变量声明,比如此例,即为下述两行:
// x = 0
// y = 0
return
}
// 当然你也可以声明命名返回值后在使用return时继续跟上对应参数,一旦return后跟上参数,参数必须同返回值数量、类型、顺序一致
func myfunction(a int, b int) (x, y int, z string) {
x = 1
y = 2
z = "China"
return 2, 4, "Power" // 不会返回 1 2 China ,返回 2 4 Power
}
// 错误1:声明返回值后,函数体中必须使用return语句
func myfunction(a int, b int) (x, y int) {} // 返回错误提示:missing return
// 错误2:命名返回值、一般返回值不可混合使用
func myfunction(a int, b int) (x int, int) { // 返回错误提示:mixed named and unnamed parameters
return 0, 1
}

  ~4:函数体,没啥好说的,注意声明返回值后,函数体中必须使用return语句即可

3、变量声明

  声明区域:可以声明在包内或函数内,包级别声明的变量包内全局可被访问修改,而函数级别声明的变量只在函数体内有效

  变量声明的一般方法:使用var语句可以声明一或多个变量,允许声明的类型、位置均不限,声明的格式为“ 变量名 变量类型”

1
2
3
var x int, y bool                     // 每次声明的变量间逗号隔开,若没有在声明时赋值,则变量自动初始化为默认值
var x, y int // 当"所有声明"的变量均一致时,可以将变量类型合并置于末尾
var x, y = 1, true // 懒人方法,当你声明变量时对其赋初始值时,可以不在声明时注明类型,程序自动推断

  短变量声明:使用 := 短赋值语句可以为函数体级别的变量进行声明,语法为:变量名 := 初始值

1
2
3
4
5
k := 12                       // k被自动推断为int型
a, b, c := 1, 3.14, "China" // 当然,一次性可以声明一或多个变量
// 如果初始值是一变量,则自动认为是该变量的类型
var name string
firstname := name // k被自动推断为string型

  Go的变量类型:不报菜名了,点这里☜

  Go的变量类型 > 注-1:int、uint、uintptr的位数同操作系统有关

  Go的变量类型 > 注-2:var语句可以一个代码块的方式声明变量,建议以后均使用此语法,便于添加、修改

1
2
3
4
5
6
7
var (  
a int = 1
b, c int = 2, 3
d = 4
e = "China"
f string
)

  类型转换:使用表达式T(v),其中T为需转化为的变量类型,v为转化变量本身,使用该表达式不会对变量v本身造成影响

1
2
3
var x = 1                    // x声明为int型变量
var y = float32(x) // 表达式返回一个float32型变量,其值为x,y通过初始化确定其类型也为float32
z := float32(x) // 短赋值语句也可以使用

  类型转换 > 注:不是任意变量的类型转换均可使用该表达式,这里特别指出与其余主流编程语言的不同,即字符串和数值无法互相转换,布尔型数据也无法和数值型变量互相转换

4、常量声明

  声明区域:同变量声明机制完全相同

  声明方法:常量的声明只能使用const关键字,不能使用 := 语句,且常量的声明必须初始化;常量的类型仅字符、字符串、布尔值或数值四种,其格式为:const 常量名 常量类型 = 初始化值

1
2
3
const x int = 1                       // x为int型常量1
const y, z int = 2, 2 // 相同类型常量,其类型可合并
const p, q = 3, "China" // 同样,由于进行了初始化,常量类型可不写明,但这我并不建议

  声明方法 > 注:同var语句声明变量一样,const关键字也可以一个代码块的方式声明变量

1
2
3
4
5
const (  
a = 1
b, c = 2, 3
d = "China"
)

  未指定类型常量的特点:一个未指定类型的常量由上下文来决定其类型,故建议声明时即显式确定其类型

1
2
3
4
// 比如,根据算术运算式确定类型
const a = 1
const b = 2.0
const c = a + b // c被推断为float64型,因为b是float64型,而a会被提升为float64运算

二、for、if、else、switch和defer

1、for循环的多种用法

  一般结构:for ~1; ~2; ~3 { ~4}

  ~1:变量声明初始化语句,可选,在进入循环之前定义,只能使用 := 语句,所定义的变量只存活于该for循环内

1
2
3
4
5
6
7
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ { fmt.Println(i) } // i被声明为0,可以被循环体中的fmt.Println(i)访问
// for var i = 0; i < 10; i++ { fmt.Println(i) } // 错误,不可以使用var语句,返回报错:var declaration not allowed in for initializer
// fmt.Println(i) // 外界不可访问for中的i,返回报错:undefined: i
}

  ~2:进入循环条件表达式,可选,在每次循环开始前执行表达式,为真则进入循环

  ~3:后置语句,可选,在每次循环结束后执行一次

  ~4:循环体,可以为空,循环体中语句运行完即运行后置语句

  作为while使用:for ~2 { ~4}

1
2
3
4
5
6
7
package main
import "fmt"
func main() {
i := 1
for i < 10 { i += i } // 等效于C++中的while (i < 10) { i += i;}
fmt.Println(i) // 输出应为16
}

  无限循环:**for { ~4 }**,慎用且一般不用或避免使用

2、if判断语句

  语句结构:if ~1; ~2 { ~3 }