[toc]
GO笔记1
目前最新的GO稳定版本为1.26.2
Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。
GO安装
GO官网截图 
GO官网地址 https://golang.google.cn/
Go安装包下载地址 https://golang.google.cn/dl/
windows安装GO的话,下载msi文件,然后双击安装即可。 
GO基础语法
行分隔符
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号;结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用;人为区分。
示例如下
fmt.Println("Hello, World!")
fmt.Println("菜鸟教程:runoob.com")注释
Go 支持两种注释:单行注释和多行注释。
- 单行注释以
//开头,直到行末。 - 多行注释也叫块注释,以
/*开头,并以*/结尾。
示例如下
// 单行注释
/*
多行注释
*/
/* 这是一个多行注释 */标识符和关键字
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
示例如下
// a 就是一个标识符
var a int关键字就是 Go 语言中官方已经定义好的、不能被用户使用的标识符。
常用的关键字有:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var格式化字符串
Go 语言中使用 fmt.Sprintf 或 fmt.Printf 格式化字符串并赋值给新串。
- fmt.Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
- fmt.Printf 根据格式化参数生成格式化的字符串并写入标准输出。
示例如下
// 定义包名
package main
//导入fmt包,用于格式化输出
import "fmt"
// main函数,程序入口
func main() {
// %d 表示整型数字,%s 表示字符串
var stockcode=123
var enddate="2020-12-31"
var url="Code=%d&endDate=%s"
var target_url=fmt.Sprintf(url,stockcode,enddate)
fmt.Println(target_url)
// 输出结果为 Code=123&endDate=2020-12-31
fmt.Printf(url,stockcode,enddate)
// 输出结果为 Code=123&endDate=2020-12-31
}GO语言-数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。数据类型的出现是为了把数据分成各个内存大小不同的数据。
Go 语言按类别有以下几种数据类型。
- 数字类型:包含整型 int 和浮点型 float32、float64。默认值为0。
- 字符串类型:包含单引号和双引号的字符串。默认值为空字符串""。
- 布尔类型:只有 true 和 false 两个值。默认值为false。
- 派生类型:
- (a) 指针类型(Pointer)
- (b) 数组类型(Array)
- (c) 结构化类型(struct)
- (d) Channel 类型
- (e) 函数类型
- (f) 切片类型
- (g) 接口类型(interface)
- (h) Map 类型
数字类型
数字类型:包含整型 int 和浮点型 float32、float64。具体有以下几种:
| 序号 | 类型和描述 |
|---|---|
| 1 | uint8 无符号 8 位整型 (0 到 255) |
| 2 | uint16 无符号 16 位整型 (0 到 65535) |
| 3 | uint32 无符号 32 位整型 (0 到 4294967295) |
| 4 | uint64 无符号 64 位整型 (0 到 18446744073709551615) |
| 5 | int8 有符号 8 位整型 (-128 到 127) |
| 6 | int16 有符号 16 位整型 (-32768 到 32767) |
| 7 | int32 有符号 32 位整型 (-2147483648 到 2147483647) |
| 8 | int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
浮点型
浮点型:包含 float32 和 float64。具体有以下几种:
| 序号 | 类型和描述 |
|---|---|
| 1 | float32 32 位浮点型 (4 字节) |
| 2 | float64 64 位浮点型 (8 字节) |
| 3 | complex64 32 位实数和虚数 (8 字节) |
| 4 | complex128 64 位实数和虚数 (16 字节) |
变量
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字。
声明变量有几种方式。
方式1:声明单个或多个变量
如果变量没有初始化,则变量默认为该数据类型默认的值。
示例如下
// 语法
var 变量名 数据类型
// 声明一个字符串变量 a
var a string
a = "123"
// 声明两个整型变量 b 和 c
var b, c int
b = 1
c = 2方式2:声明变量并初始化
示例如下
// 语法
var 变量名 数据类型 = 值
// 声明一个字符串变量 a,并赋值为 "123"
var a string = "123"
// 声明两个整型变量 b 和 c,并赋值为 1 和 2
var b, c int = 1, 2方式3: 声明变量,无需填写数据类型,会根据值自行判定变量类型
当声明变量的时候,若不指定数据类型,则根据值自行判定变量类型。
// 语法
var 变量名 = 值
// 声明一个变量 a,并赋值为 "123"。此时变量a的数据类型会被判定为字符串类型。
var a = "123"
// 声明两个变量 b 和 c,并赋值为 1 和 2。此时变量b和c的数据类型会被判定为整型。
var b, c = 1, 2注意:方式4: 通过短变量声明操作符
:=符号来声明变量
- 如果变量已经使用 var 声明过了,再使用短变量声明操作符
:=声明该变量,就产生编译错误。 - 短变量声明操作符
:=符号用于在函数体内部声明变量并赋值。
示例如下
// 语法
变量名 := 值
//相当于
var 变量名 数据类型 = 值
package main
import "fmt"
func main() {
// 声明一个变量 a,并赋值为 "123"。此时变量a的数据类型会被判定为字符串类型。
a := "123"
// 声明三个变量b、c、d,并赋值为 5、7、"abc"。此时变量b、c、d的数据类型会被判定为整型、整型、字符串类型。
b, c, d := 5, 7, "abc"
}常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
声明常量
// 语法
const 常量名 数据类型名称(可选) = 值
package main
import "fmt"
func main() {
// 声明一个常量 LENGTH,并赋值为 10。
const LENGTH int = 10
// 声明一个常量 WIDTH,并赋值为 5。
const WIDTH = 5
//声明常量 a、b、c,并赋值为 1、false、"str"。
const a, b, c = 1, false, "str" // 多重赋值
// 声明一个变量 area,并赋值为 LENGTH * WIDTH。
var area int
area = LENGTH * WIDTH
}运算符
运算符用于在程序运行时执行数学或逻辑运算。
算术运算符
下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。
| 运算符 | 描述 | 实例 |
|---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
-- | 自减 | A-- 输出结果 9 |
示例代码如下
package main
import "fmt"
func main() {
var a int = 21
var b int = 10
var c int
c = a + b // 31
c = a - b // -10
c = a * b // 210
c = a / b // 2
c = a % b // 1
a++ // 22
a-- // 21
}关系运算符
下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。
| 运算符 | 描述 | 实例 |
|---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
逻辑运算符

示例代码如下
package main
import "fmt"
func main() {
var a bool = true
var b bool = false
if ( a && b ) {
fmt.Printf("第一行 - 条件为 true\n" )
}
if ( a || b ) {
fmt.Printf("第二行 - 条件为 true\n" )
}
/* 修改 a 和 b 的值 */
a = false
b = true
if ( a && b ) {
fmt.Printf("第三行 - 条件为 true\n" )
} else {
fmt.Printf("第三行 - 条件为 false\n" )
}
if ( !(a && b) ) {
fmt.Printf("第四行 - 条件为 true\n" )
}
}赋值运算符

条件语句
Go 语言提供了以下几种条件判断语句:
| 语句 | 描述 |
|---|---|
| if 语句 | if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 |
| if...else 语句 | if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 |
| if 嵌套语句 | 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 |
| switch | 语句 switch 语句用于基于不同条件执行不同动作。 |
| select | 语句 select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 |
if 语句
If 语句在布尔表达式为 true 时,其后紧跟的语句块执行,如果为 false 则不执行。
// 语法
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* 使用 if 语句判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" )
}
fmt.Printf("a 的值为 : %d\n", a)
}
// 输出结果
// a 小于 20
// a 的值为 : 10if...else 语句
if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
// 语法
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
package main
import "fmt"
func main() {
/* 局部变量定义 */
var a int = 100;
/* 判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" );
} else {
/* 如果条件为 false 则执行以下语句 */
fmt.Printf("a 不小于 20\n" );
}
fmt.Printf("a 的值为 : %d\n", a);
}
// 输出结果
// a 不小于 20
// a 的值为 : 100if 嵌套 语句
你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。
// 语法
if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
/* 判断条件 */
if a == 100 {
/* if 条件语句为 true 执行 */
if b == 200 {
/* if 条件语句为 true 执行 */
fmt.Printf("a 的值为 100 , b 的值为 200\n" );
}
}
fmt.Printf("a 值为 : %d\n", a );
fmt.Printf("b 值为 : %d\n", b );
}
// 输出结果
// a 的值为 100 , b 的值为 200
// a 值为 : 100
// b 值为 : 200switch 语句
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的。switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
// 语法
switch var1 {
case val1:
...
case val2:
...
default:
...
}
package main
import "fmt"
func main() {
/* 定义局部变量 */
var grade string = "B"
var marks int = 90
switch marks {
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
fmt.Printf("你的等级是 %s\n", grade );
}
// 输出结果
// 优秀!
// 你的等级是 Afallthrough
使用 fallthrough 会强制执行后面的 case 语句。
如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("1、case 条件语句为 false")
fallthrough
case true:
fmt.Println("2、case 条件语句为 true")
fallthrough
case false:
fmt.Println("3、case 条件语句为 false")
fallthrough
case true:
fmt.Println("4、case 条件语句为 true")
case false:
fmt.Println("5、case 条件语句为 false")
fallthrough
default:
fmt.Println("6、默认 case")
}
}
// 输出结果
// 2、case 条件语句为 true
// 3、case 条件语句为 false
// 4、case 条件语句为 trueselect 语句
select 是 Go 中的一个控制结构,类似于 switch 语句。
select 语句只能用于通道操作,每个 case 必须是一个通道操作,要么是发送要么是接收。select 语句会监听所有指定的通道上的操作,一旦其中一个通道准备好就会执行相应的代码块。
如果多个通道都准备好,那么 select 语句会随机选择一个通道执行。如果所有通道都没有准备好,那么执行 default 块中的代码。
// 语法
select {
case <- channel1:
// 执行的代码
case value := <- channel2:
// 执行的代码
case channel3 <- value:
// 执行的代码
// 你可以定义任意数量的 case
default:
// 所有通道都没有准备好,执行的代码
}以下描述了 select 语句的语法:
- 每个 case 都必须是一个通道操作
- 所有 channel 表达式都会被求值
- 所有被发送的表达式都会被求值
- 如果有任意某个通道可以进行,它就执行,其他被忽略。
- 如果有多个 case 都可以运行,select 会随机公平地选出一个执行,其他不会执行。 否则:
- 如果有 default 子句,则执行该语句。
- 如果没有 default 子句,select 将阻塞,直到某个通道可以运行;Go 不会重新对 channel 或值进行求值。
示例代码
package main
import ("fmt""time")
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
// 输出结果
// received one
// received two循环语句
for 循环语句
for 循环是一个循环控制结构,可以执行指定次数的循环。
Go 语言的 For 循环语句有 3 种语法形式。
语法1
// 语法1
for init; condition; post {
// 循环体
}
// init: 一般为赋值表达式,给控制变量赋初值;
// condition: 关系表达式或逻辑表达式,循环控制条件;
// post: 一般为赋值表达式,给控制变量增量或减量。语法1的for循环语句的执行过程:
- 执行 init 表达式,初始化控制变量。
- 执行 condition 表达式,判断是否继续循环。若为 true,则执行循环体;否则为 false,退出循环。
- 执行 post 表达式,更新控制变量的值。
- 跳转到步骤 2,重复执行循环。直到 condition 表达式为 false 或循环体中使用 break 语句退出循环。
示例代码如下
package main
import "fmt"
func main() {
// 输出1 到 10 的数字
for i := 0; i <= 10; i++ {
fmt.Println(i)
}
}语法2
类似 while 循环。
//语法2
for condition {
// 循环体
}
//示例代码
package main
import "fmt"
func main() {
i := 1
// 这样写也可以,更像 While 语句形式
for i <= 10{
fmt.Println(i)
i++
}
}语法3
当没有循环控制条件时,使用 for 循环。循环体中的代码会无限执行,类似无限循环。
// 语法3
for {
// 循环体
}
//示例代码
package main
import "fmt"
func main() {
i := 0
for {
fmt.Println(i)
}
}for range 循环语句
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。
代码中的 key 和 value 是可以省略。
// 语法1
for key, value := range oldMap {
// 循环体
}
// 如果只想读取 value,语法如下
for _, value := range oldMap {
// 循环体
}
// 如果只想读取 key,语法如下
for key := range oldMap {
// 循环体
}
//示例代码
package main
import "fmt"
func main() {
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
//输出结果
// 0 google
// 1 runoob
numbers := [4]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
//输出结果
// 第 0 位 x 的值 = 1
// 第 1 位 x 的值 = 2
// 第 2 位 x 的值 = 3
// 第 3 位 x 的值 = 5
}break 语句
在 Go 语言中,break 语句用于终止当前循环或者 switch 语句的执行,并跳出该循环或者 switch 语句的代码块。
break 语句可以用于以下几个方面:。
- 用于循环语句中跳出循环,并开始执行循环之后的语句。
- break 在 switch 语句中在执行一条 case 后跳出语句的作用。
- break 可应用在 select 语句中。
- 在多重循环中,可以用标号 label 标出想 break 的循环。
// 示例代码1 在 for 循环中使用 break 语句
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
if i == 5 {
break //当i等于5时,跳出循环
}
fmt.Println(i)
}
}
// 示例代码2 在 switch 语句中使用 break 语句
func main2() {
day := "Tuesday"
switch day {
case "Monday":
fmt.Println("It's Monday.")
case "Tuesday":
fmt.Println("It's Tuesday.")
break // 跳出 switch 语句
case "Wednesday":
fmt.Println("It's Wednesday.")
}
}continue 语句
continue 语句用于跳过当前循环的剩余语句,继续执行下一次循环。
//示例代码
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* for 循环 */
for a < 20 {
if a == 15 {
/* 跳过此次循环,继续执行下一次循环。 */
a = a + 1;
continue;
}
fmt.Printf("a 的值为 : %d\n", a);
a++;
}
}goto 语句
Go 语言的 goto 语句可以无条件地转移到过程中指定的行。
goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。
但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。
//语法格式
goto label;
..
.
label: statement;
//示例代码
// 在变量 a 等于 15 的时候直接转移到语句 LOOP 处
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* 循环 */
LOOP: for a < 20 {
if a == 15 {
/* 转移到语句 LOOP 处 */
goto LOOP
}
fmt.Printf("a的值为 : %d\n", a)
a++
}
}函数
函数是基本的代码块,用于执行一个任务。你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
Go 语言最少有个 main() 函数。
函数定义(函数声明)
// 语法格式
func 函数名称( [参数列表] ) [返回类型] {
函数体
}- func:函数由 func 开始声明。
- 函数名称:函数的名称,用于调用函数。
- 参数列表:参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- 返回类型:函数的返回类型,用于返回数据。有些函数是不需要返回值的,这种情况下 return_types 不是必须的。
- 函数体:函数的代码块,用于执行任务。
// 示例代码
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}函数调用
当创建函数时,你定义了函数需要做什么,通过调用该函数来执行指定任务。
// 示例代码
package main
import "fmt"
// 主函数
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
var ret int
/* 调用max函数并返回最大值 */
ret = max(a, b)
fmt.Printf( "最大值是 : %d\n", ret )
// 输出结果:最大值是 : 200
}
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 定义局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}函数返回多个值
Go 函数可以返回多个值。
package main
import "fmt"
//swap函数,交换两个字符串的值,返回交换后的两个字符串
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
// 输出结果:Runoob Google
}函数参数-值传递
默认情况下,Go 语言使用的是值传递。
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
// 示例代码
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值为 : %d\n", a )
fmt.Printf("交换前 b 的值为 : %d\n", b )
/* 通过调用函数来交换值 */
swap(a, b)
fmt.Printf("交换后 a 的值 : %d\n", a )
fmt.Printf("交换后 b 的值 : %d\n", b )
//输出结果
// 交换前 a 的值为 : 100
// 交换前 b 的值为 : 200
// 交换后 a 的值 : 100
// 交换后 b 的值 : 200
}
// swap 函数,交换两个整数的值
func swap(x, y int) int {
var temp int
temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/
return temp;
}函数参数-引用传递
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
// 示例代码
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200
fmt.Printf("交换前,a 的值 : %d\n", a )
fmt.Printf("交换前,b 的值 : %d\n", b )
/* 调用 swap() 函数
* &a 指向 a 指针,a 变量的地址
* &b 指向 b 指针,b 变量的地址
*/
swap(&a, &b)
fmt.Printf("交换后,a 的值 : %d\n", a )
fmt.Printf("交换后,b 的值 : %d\n", b )
//输出结果
// 交换前,a 的值 : 100
// 交换前,b 的值 : 200
// 交换后,a 的值 : 200
// 交换后,b 的值 : 100
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
}