一、环境配置和集成环境搭建
此步骤按照网上教程来,goland和vscode都可。go语言包搭建,go语言基本环境配置变量
再进行goland或者vscode的安装和配置。处高效,转另一篇我觉得很棒的文章,按步骤必然完美配置成功。 go语言安装以及环境搭建
二、go语言基础语法的学习
其次进入第一天重头戏,因为本人具有一定但薄弱的编程语言基础,所以在go语言的学习上,要进行更加深入且详细的学习
1.变量基本类型以及变量命名
(1) 变量基本类型
在Go语言中,有以下基本的数据类型:
a. 整数类型(Integer Types):
int:根据底层平台,可能是32位或64位整数。int8:8位有符号整数,范围为-128到127。int16:16位有符号整数,范围为-32768到32767。int32:32位有符号整数,范围为-2147483648到2147483647。int64:64位有符号整数,范围为-9223372036854775808到9223372036854775807。uint:根据底层平台,可能是32位或64位无符号整数。uint8:8位无符号整数,范围为0到255。uint16:16位无符号整数,范围为0到65535。uint32:32位无符号整数,范围为0到4294967295。uint64:64位无符号整数,范围为0到18446744073709551615。
b. 浮点数类型(Floating-Point Types):
float32:32位浮点数类型,IEEE-754标准的单精度浮点数。float64:64位浮点数类型,IEEE-754标准的双精度浮点数。
c. 复数类型(Complex Types):
complex64:由两个float32组成的复数类型。complex128:由两个float64组成的复数类型。
d. 布尔类型(Boolean Type):
bool:表示真(true)或假(false)的布尔类型。
e. 字符串类型(String Type):
string:表示文本字符串的类型,使用UTF-8编码。
f. 指针类型(Pointer Types):
*T:表示类型T的指针,指向类型T的值的内存地址。
g. 数组类型(Array Types):
[n]T:表示包含n个类型为T的元素的数组,n是一个常量表达式。
h. 切片类型(Slice Types):
[]T:表示一个元素类型为T的切片,切片是对数组的引用。
i. 映射类型(Map Types):
map[K]V:表示键类型为K,值类型为V的映射(字典)类型。
j. 结构体类型(Struct Types):
- struct:表示一组字段(成员)的集合,每个字段可以有不同的类型。
k. 接口类型(Interface Types):
- interface:表示一组方法签名的集合,用于抽象类型的定义。
l. 函数类型(Function Types):
- func:表示函数类型,具有特定的参数和返回值类型。
这些是Go语言中的基本数据类型,它们是构建更复杂的数据结构和处理程序的基础。根据需要选择合适的数据类型可以帮助你编写更高效、安全和易于理解的代码。
(2) 变量的命名
在go语言中,变量命名是十分重要的,良好命名方式可以一定程度上影响代码的可读性。
go语言的变量命名语法为 var+变量名称+变量类型(不可省略) 在Go语言中,变量的类型是由其初始化的值决定的。如果在Go中看到以下代码:
var a
则此时变量a的类型将被推断为"零值"。Go语言中的变量声明不允许缺少类型信息,因此必须对a进行初始化。如果没有显式指定初始值,则该变量将被赋予其类型的零值。
对于不同类型的变量,其零值如下:
- 对于数值类型(如
int、float64等),零值是0。 - 对于布尔类型(
bool),零值是false。 - 对于字符串类型(
string),零值是空字符串""。 - 对于指针类型,零值是
nil。 - 对于复合类型(如数组、切片、字典、结构体等),零值是对应类型的空值,例如空切片、空字典等。
因此,如果变量a没有被初始化,它的类型将是其对应类型的零值类型。如果你想明确指定a的类型,你可以进行初始化并赋予它一个值:
var a int // 声明一个整数类型变量a
或者,你可以使用短变量声明方式,:
a := 10 // 声明一个整数类型变量a,并赋值为10
短变量声明(Short Variable Declaration)是Go语言中一种简洁的变量声明方式,它可以用来声明和初始化一个或多个变量。短变量声明使用简短的:=操作符来完成声明和赋值,而不需要显式地指定变量的类型。
短变量声明的语法如下:
variableName := expression
其中,variableName是变量名,expression是表达式,它可以是一个值、函数调用、运算等等。
使用短变量声明,你可以在一个语句中声明并初始化一个或多个变量。例如:
func main() {
// 短变量声明方式
name := "Alice"
age := 30
isStudent := true
fmt.Println(name, age, isStudent)
}
在上面的示例中,我们使用短变量声明方式声明并初始化了三个变量name、age和isStudent,并分别赋予了相应的值。
短变量声明的特点:
-
只能在函数内部使用:短变量声明只能在函数内部使用,不能用于全局变量的声明。
-
至少声明一个新变量:短变量声明至少要声明一个新的变量,如果其中有一个变量已经在当前的词法块中声明过,则会导致编译错误。
-
只能用于局部变量:短变量声明方式用于声明局部变量,不能用于包级别变量的声明。
短变量声明是Go语言中常用的一种声明变量的方式,它简洁明了,适合用于快速声明和初始化临时变量。同时,由于它自动推断变量类型,可以减少代码量和提高代码的可读性。 请注意,Go语言是静态类型语言,变量在声明时必须指定类型或由编译器根据初始值推断类型。
2.基础结构
(1) 顺序
此处是最基础的编程语言执行命令,不做过多赘述。
(2) 选择
Go语言中的选择结构主要通过 `if` 和 `switch` 语句来实现,它们用于在不同条件下执行不同的代码块。与Java语言相比,Go语言的选择结构有一些特点和区别。
a. if 语句:
在Go语言中,if 语句的语法如下:
if condition {
// if条件成立时执行的代码块
} else if anotherCondition {
// 可选的,当if条件不成立而另一个条件成立时执行的代码块
} else {
// 可选的,当所有条件都不成立时执行的代码块
}
示例:
num := 10
if num > 0 {
fmt.Println("Number is positive")
} else if num < 0 {
fmt.Println("Number is negative")
} else {
fmt.Println("Number is zero")
}
与Java的if语句类似,但Go语言的if语句中的条件表达式不需要用括号括起来。
b. switch 语句:
在Go语言中,switch 语句用于处理多个条件情况。与Java的switch语句相比,Go语言的switch更加灵活,且不需要显式地使用 break 语句。
switch expression {
case value1:
// expression等于value1时执行的代码块
case value2:
// expression等于value2时执行的代码块
default:
// 当expression不匹配任何case时执行的代码块
}
示例:
day := "Monday"
switch day {
case "Monday":
fmt.Println("It's Monday!")
case "Tuesday":
fmt.Println("It's Tuesday!")
default:
fmt.Println("It's another day.")
}
需要注意的是,Go语言的switch语句不需要显式的break,因为每个case执行完毕后自动跳出switch语句。
比较 Go 与 Java 的选择结构:
语法简洁性:Go语言的if和switch语句相对于Java更加简洁,去除了冗余的括号和不必要的break语句。
自动跳出:Go的switch语句自动跳出,不需要显式的break,可以减少错误。
if的初始化语句:Go语言中的if语句可以包含初始化语句,使得代码更具可读性。
总的来说,Go语言的选择结构在语法上更加简洁和灵活,同时避免了一些传统编程语言中的陷阱,使代码更加清晰易懂。
(3) 循环
在 Go 语言中,循环结构由 `for` 关键字实现。Go 语言的 `for` 循环有多种用法,以下是一些常用的循环语法:
a. 基本的 for 循环:
for initialization; condition; post {
// 循环体
}
这是最常见的循环形式,它在每次循环迭代时进行初始化、条件检查和后处理。
示例:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
b. 条件循环(类似 while 循环):
for condition {
// 循环体
}
这种形式的循环会在每次循环迭代时检查条件,只要条件为 true,就会继续执行循环。
示例:
sum := 0
for sum < 10 {
sum += 2
}
c. 无限循环:
for {
// 循环体
}
这种形式的循环没有条件,会无限循环执行,通常需要在循环体内使用 break 语句来手动跳出循环。
示例:
for {
fmt.Println("This will loop forever unless you use 'break'")
break
}
d. for 循环中的 range 迭代:
range 关键字可以用于循环迭代数组、切片、映射、通道等数据结构。
for index, value := range collection {
// 使用 index 和 value 进行循环体操作
}
示例:
numbers := []int{1, 2, 3, 4, 5}
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
Go 语言的循环结构非常灵活,可以根据具体的需求选择不同的循环形式。循环是编程中非常重要的控制结构,用于多次执行一段代码,直到满足某个条件为止。在选择循环形式时,根据场景考虑清楚循环的初始化、条件和后处理,以确保正确的循环行为。
3.指针
当涉及Go语言中的指针与C语言进行比较时,有一些重要的区别和相似之处需要注意。以下是更详细的比较:
Go语言中的指针:
-
定义指针: 在Go中,通过在变量类型前加上
*符号来声明一个指针变量。例如:var ptr *int声明了一个指向整数类型的指针。 -
获取变量地址: 使用
&运算符可以获得一个变量的内存地址。 -
解引用指针: 使用
*运算符将指针解引用,以获得指针所指向的值。 -
空指针: 在Go中,未初始化的指针默认值为
nil,表示指针不指向任何有效的内存地址。 -
指针参数: 当你需要在函数中修改函数外部的变量时,可以传递该变量的指针作为函数参数。
示例:
func main() {
var num int = 42
var ptr *int
ptr = &num // 获取num的地址,赋值给ptr
fmt.Println(*ptr) // 解引用ptr,输出42
var nilPtr *int
if nilPtr == nil {
fmt.Println("nilPtr is nil")
}
modifyValue(ptr) // 通过指针修改num的值
fmt.Println(num) // 输出修改后的值
}
func modifyValue(p *int) {
*p = 100
}
与C语言的比较:
-
类型安全性: Go语言对指针的使用更加安全。它不支持指针的算术运算,不允许将不同类型的指针进行直接赋值,从而避免了类型错误。
-
空指针: 在C语言中,未初始化的指针值是不确定的,可能指向任意内存位置。在Go语言中,空指针始终是
nil,指向无效内存。 -
自动垃圾回收: Go语言通过自动垃圾回收(Garbage Collection)机制来管理内存,避免了内存泄漏问题。
-
指针解引用: 在C语言中,使用
*运算符解引用指针以访问其所指向的值,与Go语言类似。 -
传递指针参数: 在C语言中,你可以传递指针参数以在函数内部修改外部变量。这与Go语言类似,但Go语言中的指针更加类型安全。
总体而言,Go语言的指针使用更加安全和直观,避免了许多C语言中常见的指针问题。此外,Go语言通过垃圾回收机制简化了内存管理。虽然Go语言中的指针操作相对较少,但它们在需要时仍然具有重要作用。
4.结构体
在Go语言中,结构体(Struct)是一种用户定义的数据类型,用于组合不同类型的数据字段。结构体可以包含零个或多个字段,每个字段可以有不同的类型。通过结构体,你可以创建自定义的数据类型,将相关的数据组织在一起。
以下是Go语言中结构体的详解:
定义结构体:
结构体的定义使用 type 关键字和 struct 关键字,如下所示:
type Person struct {
FirstName string
LastName string
Age int
}
在上面的例子中,我们定义了一个名为 Person 的结构体,它有三个字段:FirstName、LastName 和 Age。
创建结构体实例:
可以通过初始化字段来创建结构体的实例:
func main() {
person := Person{
FirstName: "John",
LastName: "Doe",
Age: 30,
}
fmt.Println(person)
}
访问结构体字段:
可以使用点操作符(.)来访问结构体的字段:
fmt.Println(person.FirstName)
fmt.Println(person.Age)
匿名结构体:
有时你可能只需要一个临时的结构体实例,不需要给它命名。这就是匿名结构体的用法:
point := struct {
X, Y int
}{X: 10, Y: 20}
结构体嵌套:
结构体可以嵌套在其他结构体中,形成更复杂的数据结构:
type Address struct {
Street string
City string
Country string
}
type Person struct {
FirstName string
LastName string
Age int
Address Address
}
方法与结构体:
可以给结构体关联方法,实现面向对象的特性:
func (p Person) FullName() string {
return p.FirstName + " " + p.LastName
}
指针接收者方法:
使用指针接收者,可以修改结构体实例的字段:
func (p *Person) UpdateAge(newAge int) {
p.Age = newAge
}
以上仅是Go语言中结构体的简要介绍。结构体是Go语言中非常重要的数据结构,可用于构建复杂的数据模型和对象。通过定义结构体和关联的方法,你可以创建更具有结构和功能的数据类型。
5.数组
在Go语言中,数组是一种固定大小的数据结构,用于存储相同类型的元素。数组在声明时需要指定数组的长度,且长度在声明后不可更改。数组的元素可以通过索引访问,索引从0开始。
以下是Go语言中数组的详细介绍:
定义数组:
数组的定义使用格式如下:
var arrayName [length]dataType
其中,arrayName 是数组的名称,length 是数组的长度,dataType 是数组元素的数据类型。
示例:
var numbers [5]int // 声明一个包含5个整数的数组
var names [3]string // 声明一个包含3个字符串的数组
初始化数组:
数组可以在声明时进行初始化,或者在声明后通过索引为数组元素赋值。
var numbers = [5]int{1, 2, 3, 4, 5} // 初始化数组
var names = [3]string{"Alice", "Bob", "Charlie"}
var weekdays [7]string
weekdays[0] = "Sunday"
weekdays[1] = "Monday"
// ...
数组长度和索引:
数组的长度在声明时指定,并且长度不可更改。数组的索引从0开始,最大索引为数组长度减1。
遍历数组:
可以使用循环结构遍历数组的所有元素。
for i := 0; i < len(numbers); i++ {
fmt.Println(numbers[i])
}
多维数组:
Go语言支持多维数组,例如二维数组、三维数组等。多维数组可以看作是数组的数组。
var matrix [3][3]int
matrix[0] = [3]int{1, 2, 3}
matrix[1] = [3]int{4, 5, 6}
matrix[2] = [3]int{7, 8, 9}
数组作为函数参数:
当数组作为函数参数传递时,实际上是传递数组的副本。如果需要在函数中修改数组,可以使用指针作为参数。
func modifyArray(arr *[5]int) {
arr[0] = 100
}
func main() {
numbers := [5]int{1, 2, 3, 4, 5}
modifyArray(&numbers)
fmt.Println(numbers[0]) // 输出 100
}
虽然数组在Go语言中是固定大小的,但是在实际开发中,切片(Slice)更常用,因为切片是动态大小的,更加灵活。切片在数组的基础上提供了更多功能和便利性。
6.切片
在Go语言中,切片(Slice)是一种动态数组,它提供了一种便捷的方式来操作和处理序列化的数据。与数组不同,切片的长度可以动态改变,因此更灵活适用于实际的编程场景。
以下是Go语言中切片的详细介绍:
创建切片:
切片可以通过对数组或切片进行切割来创建。切片的语法如下:
slice := arrayOrSlice[start:end]
其中,start 是切片的起始索引(包含),end 是切片的结束索引(不包含)。
示例:
numbers := []int{1, 2, 3, 4, 5}
slice := numbers[1:4] // 创建一个包含 [2, 3, 4] 的切片
切片的特性:
切片具有动态大小和灵活性,可以自由地添加、删除、修改元素。
修改切片:
切片是引用类型,修改切片会影响底层数组中的数据。
slice[0] = 100 // 修改切片中的元素,会修改底层数组
append函数:
可以使用内置的 append 函数向切片添加元素。
slice = append(slice, 6) // 向切片添加一个元素
slice = append(slice, 7, 8, 9) // 向切片添加多个元素
创建切片的其他方式:
- 使用
make函数创建指定长度的切片,并指定容量。
slice := make([]int, 3, 5) // 创建长度为3,容量为5的切片
- 创建空切片。
var emptySlice []int
切片的扩容:
当切片的容量不足以容纳新元素时,Go会自动扩容切片,通常扩容策略为成倍增加容量。
切片和数组的关系:
切片底层是基于数组实现的,切片维护了一个指向底层数组的指针、切片的长度以及切片的容量。切片是动态的,数组是静态的。
传递切片作为函数参数:
传递切片给函数时,实际上是传递了切片的引用。因此,在函数内部对切片的修改会影响原始切片。
func modifySlice(s []int) {
s[0] = 100
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
modifySlice(numbers)
fmt.Println(numbers[0]) // 输出 100
}
总的来说,切片是Go语言中非常强大和实用的数据结构,它为动态数组的需求提供了灵活的解决方案,适用于各种数据处理和集合操作。
7. map
在Go语言中,map 是一种无序的键值对集合,也被称为哈希表或字典。map 中的每个键唯一,并且与一个值关联。map 是一种非常实用的数据结构,用于存储和检索键值对。
以下是Go语言中map的详细介绍:
创建和初始化map:
使用以下语法可以创建和初始化一个map:
var m map[keyType]valueType
其中,keyType 是键的数据类型,valueType 是值的数据类型。
示例:
// 创建一个string到int的map
var ages map[string]int
// 创建并初始化一个map
scores := map[string]int{
"Alice": 100,
"Bob": 90,
"Charlie": 85,
}
map操作:
- 添加键值对:使用赋值操作向
map中添加或修改键值对。
scores["David"] = 95 // 添加键值对
scores["Bob"] = 92 // 修改键值对
- 获取值:通过键来获取
map中的值。
aliceScore := scores["Alice"]
- 删除键值对:使用
delete函数来删除指定键的键值对。
delete(scores, "Charlie") // 删除键值对
- 检查键是否存在:通过
ok值判断指定键是否存在。
score, ok := scores["David"]
if ok {
fmt.Println("David's score:", score)
} else {
fmt.Println("David not found")
}
迭代map:
可以使用for range循环迭代map中的键值对。
for key, value := range scores {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
map的值类型:
map中的值可以是任意类型,包括内置类型、结构体、甚至其他map。但是,map的键类型必须是支持相等运算符(==)的类型,例如:数值类型、字符串类型、指针类型、数组类型等。
nil map:
map默认值是nil,在声明后需要使用make函数进行初始化,才能使用。
var players map[string]int
players = make(map[string]int)
players["Alice"] = 10
map是Go语言中用于存储键值对的重要数据结构,非常适用于构建查找表和关联数据的场景。使用map可以高效地进行数据检索和更新。需要注意的是,由于map是无序的,遍历map的顺序可能不是添加键值对的顺序。