【3w字吐血总结 | 新手必看】全网最详细Go笔记
温馨提示:这篇文章已超过399天没有更新,请注意相关的内容是否还可用!
写在前面
鉴于全网Go语言知识点的总结分散难懂、良莠不齐,为了避免初学者少走弯路,更好更快地掌握Go知识,博主特地将自己所学的笔记分享出来。
文章目录
- 写在前面
- Go语言概念
- 语言特色
- Go 语言用途
- Go语言环境安装
- Go语言基础组成
- GO语言基础语法
- Go标记
- 行分隔符
- 字符串连接
- 空格
- 格式化字符串
- Go语言数据类型
- Go语言变量
- 局部变量和全局变量
- Go语言常量
- Go语言运算符
- Go语言条件语句
- Go语言循环语句
- Go语言函数
- Go语言数组
- Go语言指针
- Go语言结构体
- Go语言切片
- Go语言范围(Range)
- Go 语言Map(集合)
- Go 语言递归函数
- Go 语言类型转换
- Go 语言接口
- Go 错误处理
- Go 并发
- Go语言开发工具汇总
- 写在最后
Go语言概念
Go语言(又称为Golang)是一种开源的编程语言,由Google于2007年启动并于2009年首次公开发布。Go语言是一门静态类型、编译型的语言,旨在提供一种简单、高效、可靠的编程方式。
语言特色
现在越来越多的人开始使用Go语言进行开发,其原因有以下几点:
- Go语言设计简洁,语法清晰明了,容易上手和理解。它避免了冗余的语法和复杂的概念,使得编写和维护代码更加高效。
- Go语言天生支持并发编程,提供了轻量级的Goroutine和通道(channel)机制,使并发编程变得更加简单和安全。
- 高性能:Go语言在运行时表现出色,具有低延迟和高吞吐量。它采用了垃圾回收机制,使内存管理变得自动化且高效,同时还提供了一些优化策略,如原生的协程调度器和快速编译等。
- 内建工具:Go语言提供了丰富的标准库,覆盖了网络编程、文件处理、文本处理、加密解密等各个领域。它还有强大的构建工具,可以方便地进行代码的构建、测试和分发。
Go 语言用途
Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。
对于高性能分布式系统领域而言,Go 语言比大多数语言有着更高的开发效率。它提供了海量并行的支持,十分适用于游戏服务端的开发。
Go语言环境安装
安装包下载地址:https://go.dev/dl/
根据操作系统选择安装包:
运行msi文件:
一路next,并且选择安装路径:
等待安装:
安装完成后将bin目录添加到path环境变量中:
创建一个practice目录来测试安装配置是否成功:
在practice目录中新建test.go文件
package main import "fmt" func main() { fmt.Println("Hello, World!") }//Println不能写作println在命令行输出:
若页面回显Hello,World! 则说明Go环境安装成功。
Go语言基础组成
我们以下面的代码为例:
package main import "fmt" func main() { /* 输出 */ fmt.Println("Hello, World!") }- 包声明
Go语言中的每个文件都属于一个包(package)。包声明用于定义当前文件所属的包名,不同的包之间可以通过包名进行引用和调用。
包的声明必须是在源文件中非注释的第一行,且每一个Go程序都包含一个名为main的包。
- 引入包
通过 import 关键字引入其他包,以便在当前文件中使用其他包提供的功能和类型。引入包后,就可以使用其提供的函数、变量和结构体等。本题中,fmt 包实现了格式化 IO(输入/输出)的函数
- 函数
函数是实现特定功能的代码块。在Go语言中,函数由 func 关键字定义,并可以带有参数和返回值。通过定义函数,可以将代码模块化并重复使用。
- 变量
在Go语言中,变量用于存储数据。使用关键字 var 来声明变量,同时指定变量的名称和类型。变量可以存储数值、字符串、布尔值等不同类型的数据。
- 语句 & 表达式
语句是Go程序的执行单位,由一个或多个表达式组成。表达式用于计算值或执行特定操作。常见的语句包括赋值语句、条件语句(如 if 语句)、循环语句(如 for 语句)等。
- 注释
注释用于向代码中添加注解和说明信息,对于其他人阅读代码时起到解释作用。在Go语言中,注释可以使用 // 开始的单行注释,或者使用 /* */ 包围的多行注释。
注意事项
- { 不能单独放在一行,如
func main() { // 错误,{ 不能在单独的行上 fmt.Println("Hello, World!") }在 Go 语言中,大括号通常应该与相关的语句在同一行,并且需要有一个空格将大括号与前面的语句分隔开。
同样,函数的左括号 { 也应该与函数签名在同一行,并且右括号 } 应该独占一行。
-
Go 语言在大多数情况下不需要显式的分号来结束语句。编译器会根据规则自动插入分号。但是,如果一行上有多个语句,则需要使用分号将它们分隔开。
-
Go 语言采用驼峰命名法。变量和函数应该使用有意义且描述性的名称。公共(public)的标识符应该以大写字母开头,非公共(private)的标识符应该以小写字母开头。
也就是说,当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Qiu,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(类似于面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(类似于面向对象语言中的 protected )
GO语言基础语法
Go标记
在Go语言中,标记(Tokens)是源代码的最小语法单位,编译器将源代码分解为一系列标记进行解析和处理。以下是Go语言中的一些常见标记类型:
-
标识符(Identifiers):标识符用于表示变量、函数、类型等的名称。标识符由大小写字母、数字和下划线组成,并且不能以数字开头。
以下是无效的标识符: 1aht(以数字开头) case(Go 语言的关键字) a+3(运算符是不允许的)
-
关键字(Keywords):Go语言预先定义了一些关键字,它们具有特殊的含义和用途,例如if、for、func等。关键字不能作为标识符使用。
-
运算符(Operators):运算符用于执行各种算术、逻辑和比较操作,例如+、-、*、/等。
-
分隔符(Delimiters):分隔符用于将程序的不同部分分隔开来,例如括号( )、花括号{ }、方括号[ ]、逗号,、分号;等。
-
字面量(Literals):字面量表示直接使用的常量值,例如整型字面量123、浮点型字面量3.14、字符串字面量"QiuShuo"、布尔字面量true和false等。
-
注释(Comments):注释用于向代码中添加注解和说明,不会被编译器解析。单行注释以//开头,多行注释以/*开始,以*/结束。
举个例子:
fmt.Println("Hello, World!")以上代码含有6个标记:
1. fmt 2. . 3. Println 4. ( 5. "Hello, World!" 6. )
这些标记构成了Go语言源代码的基本元素,它们按照一定的规则组合在一起形成具有意义的句子和表达式。编译器通过解析这些标记来理解和执行代码逻辑。
行分隔符
在 Go 程序中,一行代表一个语句结束。每个语句不需要以分号结尾。
如果将多个语句写在同一行,它们必须使用 ; 进行区分,使编译器理解代码逻辑。
例如:
package main import "fmt" func main() { var a = 10; var b = 20; fmt.Println(a + b) }但我们并不推荐这种做法,因为它会降低代码的可读性。
字符串连接
Go 语言的字符串连接可以通过 + 实现:
package main import "fmt" func main() { fmt.Println("Qiu" + "Shuo") }空格
Go 语言中变量的声明必须使用空格隔开,例如:
var a float const Pi float64 = 3.14159265358979323846
在关键字和表达式之间要使用空格,例如:
if x // do something } }) string var code = 1 var date = "2020" var url = "Code=%d&date=%s" var a = fmt.Sprintf(url, code, date) fmt.Println(a) } var code = 2 var date = "1990" var url = "code=%d&date=%s" fmt.Printf(url,code,date) } globalVariable = 10 // 在主函数中访问和修改全局变量 fmt.Println(globalVariable) someFunction() } func someFunction() { fmt.Println(globalVariable) // 在其他函数中访问全局变量 } someFunction() } func someFunction() { localVariable := 20 // 局部变量 fmt.Println(localVariable) } someFunction() fmt.Println(localVariable) // 在函数外部尝试访问局部变量,会导致编译错误 } func someFunction() { localVariable := 10 // 声明并初始化局部变量 fmt.Println(localVariable) // 在函数内部可以访问局部变量 } /* 声明局部变量 */ var a int = 10 fmt.Printf ("a=%d",a) } const ( strLen = len("hello") // 使用 len() 函数计算字符串长度 arrayLen = len([3]int{1, 2, 3}) // 使用 len() 函数计算数组长度 size = unsafe.Sizeof(int(0)) // 使用 unsafe.Sizeof() 函数计算整数类型的大小 ) sliceLen := len([]int{1, 2, 3}) // 使用 len() 函数计算切片长度 capacity := cap(make(chan int, 10)) // 使用 cap() 函数计算通道容量 fmt.Println(strLen, sliceLen, arrayLen, capacity, size) } fmt.Println(Red, Green, Blue) } const ( a = iota //0 b //1 c //2 d = "qiu" //独立值,iota += 1, iota变为3 e //e是显式赋值的常量声明,它们不会影响 iota 的自增。因此 e 的值仍然是 "qiu",同时iota += 1, iota变为4 f = 100 //iota +=1,iota变为5 g //100 iota +=1,iota变为6 h = iota //7,恢复计数 i //8 ) fmt.Println(a,b,c,d,e,f,g,h,i) }p输出:/p pre class="brush:python;toolbar:false"0 1 2 qiu qiu 100 100 7 8 /pre hr / h3Go语言运算符/h3 pGo语言中常用的运算符包括:/p olli算术运算符:用于执行基本的算术操作,如加法 +,减法 -,乘法 *,除法 /,取余 %,以及自增 ++ 和自减 --。/li/ol tabletheadtrth运算符/thth描述/thth示例/th/tr/theadtbodytrtd+/tdtd相加/tdtda + b/td/trtrtd-/tdtd相减/tdtda - b/td/trtrtd*/tdtd相乘/tdtda * b/td/trtrtd//tdtd相除/tdtda / b/td/trtrtd%/tdtd取余/tdtda % b/td/trtrtd++/tdtd自增/tdtda++ 或 ++a/td/trtrtd–/tdtd自减/tdtda-- 或 --a/td/tr/tbody/table ol start="2"li p关系运算符:用于比较两个值之间的关系,如相等 ==,不等 !=,大于 >,小于 =,小于等于 bp q p & q p | q p ^ q 0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 -
赋值运算符:用于将值赋给变量,如赋值 =,加法赋值 +=,减法赋值 -=,乘法赋值 *=,除法赋值 /=,取余赋值 %=
-
其他运算符:包括取地址 &,取值 *,指针运算符 ->,条件运算符 ? :,类型断言运算符 .,管道运算符 |,索引运算符 [],以及取长度 len() 等。
运算符 描述 示例 & 取地址运算符 &a * 取值运算符 *ptr -> 指针运算符(C语言中使用) ptr->data ?: 条件运算符 condition ? expr1 : expr2 . 类型断言运算符 value.(type) | 管道运算符 cmd1 | cmd2 [] 索引运算符 array[index] len() 取长度函数 len(array) 除了要熟练使用这些运算符之外,我们还需要掌握运算符优先级。
下面的表格中,由上至下代表优先级由高到低:
优先级 运算符 5 * / % > & &^ 4 + - | ^ 3 == != = 2 && 1 || Go语言条件语句
Go语言中的条件语句有两种形式:if语句和switch语句。
- if语句:
if语句用于根据一个条件的真假执行不同的代码块。
语法:
if condition { // 当条件为真时执行的代码块 } else { // 当条件为假时执行的代码块(可选) }示例:
num := 10 if num%2 == 0 { fmt.Println("num是偶数") } else { fmt.Println("num是奇数") }除了基本的if语句外,还可以使用if语句的简短语法:
语法:
if condition { // 当条件为真时执行的代码块 }示例:
if num := 10; num > 0 { fmt.Println("num大于0") }- switch语句:
switch语句用于基于不同的条件执行不同的代码块。
语法:
switch expression { case value1: // 当expression等于value1时执行的代码块 case value2: // 当expression等于value2时执行的代码块 default: // 当expression不等于任何已匹配的值时执行的代码块(可选) }示例:
grade := "C" switch grade { case "A": fmt.Println("优秀") case "B": fmt.Println("良好") case "C": fmt.Println("及格") default: fmt.Println("不及格") }在Go语言的switch语句中,每个case后面的值和expression的类型必须相同。此外,当匹配的case执行完毕后,不会自动执行后续的case,而是跳出switch语句,除非使用fallthrough关键字。
Go语言循环语句
Go语言中有三种主要的循环语句:for循环、while循环和do-while循环。
- for循环:
for循环用于重复执行一段代码块,可以指定循环的起始条件、循环执行前的初始化语句,以及每次循环结束后的迭代语句。
语法:
for 初始化语句; 条件表达式; 迭代语句 { // 循环体 }示例:
for i := 0; i
- while循环:
Go语言中没有专门的while循环关键字,但可以使用for循环来实现类似的功能。
语法:
for 条件表达式 { // 循环体 }示例:
i := 0 for i
- do-while循环:
Go语言中也没有专门的do-while循环关键字,但可以使用for循环结合break语句来实现类似的功能。
语法:
for { // 循环体 if !条件表达式 { break } }示例:
i := 0 for { fmt.Println(i) i++ if i >= 5 { break } }除了以上常用的循环语句外,Go语言还提供了range关键字用于遍历数组、切片、映射等数据结构。
示例:
arr := []int{1, 2, 3, 4, 5} for index, value := range arr { fmt.Println(index, value) }//在每次循环时,range 返回两个值:当前元素的下标 index 和对应的值 value在循环中,常用continue和goto控制流程:
- continue:
continue 是一个控制流程的关键字,用于跳过当前循环迭代中的剩余代码,直接进入下一次迭代。
示例:
for i := 0; i
上述代码的输出结果为:
0 1 3 //i==2时,跳出当前循环,进入下一次循环 4
- goto:
goto 是一个控制流程的关键字,用于无条件地转移到程序中的一个标签。
示例:
package main import "fmt" func main() { i := 0 Loop: for i上述代码的输出结果为:
0 1 2 3 4
在这个例子中,我们使用 goto 关键字和标签 Loop 实现了一个完整的循环,当 i 的值为 3 时,程序会跳转到标签 Loop 处,继续执行循环。
Go语言函数
可以使用函数来执行需要的功能。Go 语言程序中最少有个 main() 函数。
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] { 函数体 }- func:函数由 func 开始声明
- function_name:函数名称
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
- 函数体:函数定义的代码集合。
举个例子:
package main import "fmt" // 定义一个计算两个整数之和的函数 func add(x int, y int) int { return x + y } func main() { result := add(3, 5) fmt.Println(result) // 输出结果为 8 }以上代码定义了一个名为 add 的函数。该函数接受两个整数类型的参数 x 和 y,并返回它们的和。在 main 函数中,我们调用 add 函数,并将参数传递为 3 和 5。然后,将返回的结果赋值给变量 result。
Go语言数组
在Go语言中,数组是一种固定长度的数据结构,用于存储一组相同类型的元素。
语法格式如下:
var arrayName [size]dataType
其中,arrayName 是数组的名称,size 是数组的大小,dataType 是数组中元素的数据类型。
举个例子:
var a [10]float64
以上定义了数组 a 长度为 10 类型为 float64
数组的初始化:
- 默认初始化
var numbers [5]int
数组初始值为0
- 初始化列表
var numbers = [5]int{1, 2, 3, 4, 5}分别被赋值为1,2,3,4,5
- 使用:=初始化
numbers := [5]int{1, 2, 3, 4, 5}如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var a = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 1 和 3 的元素初始化 a := [5]float32{1:9.9,3:7.7}访问数组元素:
数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:
var b float32 = a[9]
以上实例读取了数组 a 第 10 个元素的值。
Go语言指针
在Go语言中,指针是一种特殊的数据类型,用于存储变量的内存地址。指针可以用于间接访问和修改变量的值。
语法格式:
-
声明指针:
var ptr *Type
其中,ptr 是指针变量的名称,Type 是指针所指向的变量类型。指针变量的初始化可以选择性地进行。
-
取地址操作符(&):
ptr = &variable
使用 & 运算符可以获取变量 variable 的内存地址,并将其赋值给指针变量 ptr。
-
解引用操作符(*):
value = *ptr
使用 * 运算符可以获取指针变量 ptr 所指向的变量的值。
-
修改指针所指变量的值:
*ptr = newValue
使用 * 运算符,可以修改指针变量 ptr 所指向的变量的值。
下面是使用Go语言定义和操作指针的示例代码:
package main import "fmt" func main() { // 定义一个整数变量 var num int = 42 // 声明一个指向整数的指针,并将其初始化为num的内存地址 var ptr *int = &num // 输出指针的值和所指向的变量的值 fmt.Println("指针的值:", ptr) // 输出: 指针的值: 0xc000096068 fmt.Println("指针所指向的变量的值:", *ptr) // 输出: 指针所指向的变量的值: 42 // 修改所指向的变量的值 *ptr = 100 // 输出被修改后的变量的值 fmt.Println("被修改后的变量的值:", num) // 输出: 被修改后的变量的值: 100 }Go语言结构体
在Go语言中,结构体(Struct)是一种用户定义的复合类型,用于封装不同类型的数据字段。结构体可以包含零个或多个字段,并且可以根据需要进行组合。
语法格式
-
定义结构体:
type StructName struct { field1 fieldType1 field2 fieldType2 // ... }其中,StructName 是结构体的名称,field1、field2 等是字段的名称,fieldType1、fieldType2 等是字段的类型。
-
创建结构体对象:
var obj StructName
使用 var 声明结构体对象,并初始化为零值。
-
访问结构体字段:
obj.field = value
使用对象名加上.操作符来访问结构体中的字段,并进行赋值或获取值操作。
下面代码展示了结构体的定义和使用:
package main import "fmt" // 定义一个结构体类型 type Person struct { name string age int } func main() { // 创建一个结构体对象p1 var p1 Person // 访问结构体字段并赋值 p1.name = "Alice" p1.age = 20 // 输出结构体字段的值 fmt.Println("姓名:", p1.name) fmt.Println("年龄:", p1.age) // 创建结构体对象并初始化 p2 := Person{name: "Bob", age: 25} // 输出结构体字段的值 fmt.Println("姓名:", p2.name) fmt.Println("年龄:", p2.age) }结构体参数传递
在Go语言中,可以将结构体作为函数的参数进行传递,以便在函数中对结构体进行操作或使用结构体中的字段。
结构体作为函数参数有两种传递方式:值传递和引用传递。
-
值传递(Pass by Value):
在值传递方式下,函数会复制传入的结构体,函数内部对结构体的修改不会影响原始结构体。
下面是一个使用值传递方式的示例代码:
package main import "fmt" type Person struct { name string age int } func updateName(p Person) { p.name = "Alice" } func main() { p := Person{name: "Bob", age: 25} fmt.Println("修改前:", p) updateName(p) fmt.Println("修改后:", p) } //输出 修改前: {Bob 25} 修改后: {Bob 25}在该示例中,我们定义了一个 Person 结构体,并在 updateName 函数中修改了结构体的 name 字段。然而,在 main 函数中调用 updateName 函数时,输出结果仍然是原来的结构体,表明在函数内部对结构体字段的修改不会影响原始结构体。
-
引用传递(Pass by Reference):
在引用传递方式下,函数接收的是结构体的指针,函数内部对结构体的修改会影响原始结构体。
下面是一个使用引用传递方式的示例代码:
package main import "fmt" type Person struct { name string age int } func updateName(p *Person) { p.name = "Alice" } func main() { p := &Person{name: "Bob", age: 25} fmt.Println("修改前:", p) updateName(p) fmt.Println("修改后:", p) }结构体指针
在Go语言中,可以使用指针来操作结构体。通过指针,可以直接修改结构体的字段值,而无需进行复制操作。
指向结构体的指针,定义格式如下:
var struct_pointer *Person
查看结构体变量地址,可以将 & 符号放置于结构体变量前:
struct_pointer = &Person1
使用结构体指针访问结构体成员,使用 “.” 操作符:
struct_pointer.title
实例如下:
package main import "fmt" type Person struct { name string age int } func main() { var Person1 Person /* 声明 Person1 为 Person 类型 */ var Person2 Person /* 声明 Person2 为 Person 类型 */ /* Person 1 描述 */ Person1.name="秋说" Person1.age="1" /* Person 2 描述 */ Person2.name="花无缺" Person2.age="2" /* 打印 Person1 信息 */ printPerson(&Person1) /* 打印 Person2 信息 */ printPerson(&Person2) } func printPerson( Person *Person ) { fmt.Printf( "Person name : %s\n", Person.name) fmt.Printf( "Person age : %d\n", Person.age) }Go语言切片
Go语言中的切片(Slice)是一种动态数组的抽象。切片提供了对底层数组的封装,可以方便地操作和管理数组的片段。
具体来说:
- 切片是对数组的引用,它包含了指向底层数组的指针、切片的长度和切片的容量。
- 切片的长度表示其中元素的个数,切片的容量则是从切片的起始位置到底层数组的末尾位置的元素个数。
- 切片的长度可以动态改变,而切片的容量只能向后扩展。
在Go语言中,使用切片的语法为[]T,其中T表示切片中元素的类型。创建切片可以通过以下方式:
- 通过数组创建切片的模板语法:
slice := array[start:end]
其中,array 是一个已有的数组,start 是切片的起始索引(包含),end 是切片的结束索引(不包含)。这个语法将创建一个切片 slice,包含了从 start 索引到 end-1 索引的元素。
实例:
arr := [5]int{1, 2, 3, 4, 5} slice := arr[1:4] // 创建一个切片,包含arr索引1到索引3的元素,即[2, 3, 4]- 使用 make 函数创建切片的模板语法:
slice := make([]T, length, capacity)
其中,T 是切片中元素的类型,length 是切片的长度,capacity 是切片的容量。通过 make 函数创建的切片具有指定的长度和容量,并初始化了相应类型的零值。
实例:
slice := make([]int, 3, 5) // 创建一个长度为3,容量为5的切片
- 使用切片字面量创建切片的模板语法:
slice := []T{element1, element2, ..., elementN}其中,T 是切片中元素的类型,element1 到 elementN 是要添加到切片中的元素。使用切片字面量创建切片时,切片的长度会根据提供的元素个数自动确定。
实例:
slice := []int{1, 2, 3, 4, 5} // 直接创建一个切片,包含元素1到5切片常用的操作有以下几种:
- 获取切片的长度和容量:
length := len(slice) // 获取切片的长度 capacity := cap(slice) // 获取切片的容量
- 切片的追加元素:
slice = append(slice, 6) // 在切片的末尾追加元素6
- 切片的遍历:
for index, value := range slice { // 遍历切片的索引和对应的值 }- 切片的切割:
newSlice := slice[1:3] // 对切片进行切割,创建新的切片包含索引1到2的元素
- append() 和 copy() 是在切片操作中常用的两个函数。
- append() 函数用于向切片末尾追加元素或另一个切片:
slice = append(slice, element1, element2, ..., elementN)
其中,slice 是要追加元素的切片,element1 到 elementN 是要添加到切片中的元素。append() 函数会返回一个新的切片,如果原切片的容量不够,会自动分配更大的底层数组,并将新元素追加到其中。
示例:
slice := []int{1, 2, 3} slice = append(slice, 4, 5) // 追加元素 4 和 5- copy() 函数用于将一个切片的内容复制到另一个切片:
copy(destSlice, srcSlice)
其中,destSlice 是目标切片,srcSlice 是源切片。copy() 函数会将源切片中的元素复制到目标切片中,两个切片必须有相同的元素类型。
示例:
srcSlice := []int{1, 2, 3} destSlice := make([]int, len(srcSlice)) copy(destSlice, srcSlice) // 复制 srcSlice 到 destSlice需要注意的是,append() 函数会返回一个新的切片,因此在使用时需要将其赋值给原来的切片变量;而 copy() 函数则直接在目标切片上进行复制操作。
以下是一个使用切片的示例代码:
package main import "fmt" func main() { // 创建切片 numbers := []int{1, 2, 3, 4, 5} // 获取切片长度和容量 fmt.Println("Length:", len(numbers)) // 输出:Length: 5 fmt.Println("Capacity:", cap(numbers)) // 输出:Capacity: 5 // 追加元素 numbers = append(numbers, 6) fmt.Println(numbers) // 输出:[1 2 3 4 5 6] // 遍历切片 for index, value := range numbers { fmt.Println(index, value) } // 切割切片 newSlice := numbers[1:4] fmt.Println(newSlice) // 输出:[2 3 4] }Go语言范围(Range)
Go语言中的范围(Range)是一种迭代数据结构(如数组、切片、映射等)的元素的方法。通过使用范围,可以遍历并访问数据结构中的每个元素,而不需要使用索引或迭代器。
范围语法如下:
for index, value := range collection { // 使用 index 和 value 来处理元素 }其中,collection 是要迭代的数据结构(如数组、切片、映射等),index 是当前元素的索引,value 则是当前元素的值。在循环的每次迭代中,范围语句会将 index 和 value 更新为下一个元素的索引和值,直到遍历完整个集合。
范围还支持忽略索引或值,如果你只关心其中一项,可以使用 _(下划线)来忽略另一项。例如:
for _, value := range collection { // 只使用 value 处理元素,忽略索引 }举个例子:
遍历简单的数组,2**%d 的结果为 2 对应的次方数:
package main import "fmt" var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } }输出:
2**0 = 1 2**1 = 2 2**2 = 4 2**3 = 8 2**4 = 16 2**5 = 32 2**6 = 64 2**7 = 128
for 循环的 range 格式可以省略 key 和 value,如下实例:
package main import "fmt" func main() { map1 := make(map[int]float32) map1[1] = 1.0 map1[2] = 2.0 map1[3] = 3.0 map1[4] = 4.0 // 读取 key 和 value for key, value := range map1 { fmt.Printf("key is: %d - value is: %f\n", key, value) } // 读取 key for key := range map1 { fmt.Printf("key is: %d\n", key) } // 读取 value for _, value := range map1 { fmt.Printf("value is: %f\n", value) } }以上实例运行输出结果为:
key is: 4 - value is: 4.000000 key is: 1 - value is: 1.000000 key is: 2 - value is: 2.000000 key is: 3 - value is: 3.000000 key is: 1 key is: 2 key is: 3 key is: 4 value is: 1.000000 value is: 2.000000 value is: 3.000000 value is: 4.000000
Go 语言Map(集合)
在Go语言中,Map(映射)是一种无序的键值对的集合。可以将其看作是一个动态的数组,其中每个元素都是一个键值对,即一个唯一的键关联一个值。您可以使用键来访问映射中的值,并可以通过添加、修改和删除元素来修改映射。
Map的定义方式如下:
// 定义一个键为string类型,值为int类型的map var m map[string]int // 初始化map m = map[string]int{"foo": 1, "bar": 2} // 或者可以使用make函数初始化map m = make(map[string]int)可以通过make()函数来初始化一个空的Map对象,然后使用 map[key] = value 的方式向Map中添加元素。例如:
m := make(map[string]int) // 添加元素 m["foo"] = 1 m["bar"] = 2
可以使用 delete() 函数来删除Map中的元素:
delete(m, "bar") // 删除键为"bar"的元素
可以使用 len() 函数获取Map中键值对的数量。还可以使用范围(Range)语句迭代Map中的所有键值对:
for key, value := range m { fmt.Println(key, value) }需要注意的是,Map 的遍历是无序的,因为 Map 内部实现了哈希表(Hash Table)来存储键值对,所以元素的排列顺序是不确定的。
package main import "fmt" func main() { // 定义一个string类型的键,int类型的值的map scores := make(map[string]int) // 添加学生的成绩 scores["张三"] = 90 scores["李四"] = 85 scores["王五"] = 98 // 循环遍历map中的每个元素 for name, score := range scores { fmt.Printf("%s的成绩是:%d\n", name, score) } // 删除指定的元素 delete(scores, "李四") // 输出删除后的map fmt.Println("删除李四之后的成绩:", scores) // 判断指定的键是否存在 if score, ok := scores["张三"]; ok { fmt.Printf("张三的成绩是:%d\n", score) } else { fmt.Println("找不到张三的成绩") } }输出:
张三的成绩是:90 李四的成绩是:85 王五的成绩是:98 删除李四之后的成绩: map[王五:98 张三:90] 张三的成绩是:90
Go 语言递归函数
在Go语言中,递归函数是指在函数体内调用自身的函数。递归函数是一种常用的算法设计技巧,可以简化问题的解决方法,并且能够解决一些需要重复执行相同操作的问题。
语法格式如下:
func recursion() { recursion() /* 函数调用自身 */ } func main() { recursion() }下面是一个示例,展示了如何使用递归函数来计算一个数的阶乘:
package main import "fmt" // 计算n的阶乘 func factorial(n int) int { if n return 1 } return n * factorial(n-1) } func main() { num := 5 result := factorial(num) fmt.Printf("%d的阶乘是:%d\n", num, result) } if n
- append() 和 copy() 是在切片操作中常用的两个函数。
- 切片的切割:
- 切片的遍历:
- 切片的追加元素:
-
- 使用:=初始化
- 初始化列表
- 默认初始化
- 注释
- 语句 & 表达式
- 变量
- 函数
- 引入包
















