主页 > 软件开发  > 

【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句

【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句

文章目录 一、复合类型Ⅰ 数组1. 语法2. 示例3. 特点4. 数组的传递 Ⅱ 切片1. 定义2. 语法3. 示例4. 特点5. 切片的创建6. 切片的操作切片的扩展切片的拷贝 Ⅲ 映射1. 定义2. 语法3. 示例4. 特点5. 映射的创建6. 映射的操作示例:插入、访问和删除判断键是否存在示例:判断键是否存在映射的遍历 Ⅳ 映射与数组、切片的区别Ⅴ 结构体1. 结构体的定义示例: 2. 创建和初始化结构体3. 结构体字段的访问访问结构体字段:通过指针访问结构体字段: 4. 修改结构体字段5. 结构体作为函数参数传递结构体值:传递结构体指针: 6. 结构体的嵌套示例:结构体嵌套 7. 结构体与方法示例:为结构体定义方法 二、控制流`if` 语句`if` 语句中的 `else if` `for` 循环标准 `for` 循环无限循环`range` 遍历 `switch` 语句基本语法省略 `expression`多个 `case` 合并`fallthrough` 关键字

一、复合类型 Ⅰ 数组

数组是固定长度的序列,一旦定义其长度就不可更改。Go 中的数组是值类型,当我们将一个数组赋值给另一个数组时,会发生值拷贝。

1. 语法 var arrayName [length]type 2. 示例 package main import "fmt" func main() { // 定义一个长度为5的整数数组 var arr [5]int fmt.Println(arr) // [0 0 0 0 0] // 初始化数组 arr2 := [3]int{1, 2, 3} fmt.Println(arr2) // [1 2 3] // 数组的长度是固定的,不能动态改变 arr3 := [3]int{4, 5, 6} fmt.Println(len(arr3)) // 3 } 3. 特点 固定长度:数组一旦定义其长度就不能更改。值类型:数组是值类型,赋值和传递数组会复制整个数组。元素初始化:数组元素的默认值为零值(对于 int 类型来说是 0)。内存连续:数组是一个内存连续的块,元素在内存中是连续存储的。 4. 数组的传递

由于 Go 中的数组是值类型,传递数组时会将整个数组拷贝一份到函数中。如果不希望这样,可以通过传递数组的指针来避免拷贝。

func modifyArray(arr [3]int) { arr[0] = 10 } func main() { arr := [3]int{1, 2, 3} modifyArray(arr) fmt.Println(arr) // [1 2 3],数组没有改变 }

如果传递指针:

func modifyArray(arr *[3]int) { arr[0] = 10 } func main() { arr := [3]int{1, 2, 3} modifyArray(&arr) fmt.Println(arr) // [10 2 3],数组被修改 }
Ⅱ 切片

切片是 Go 中的一个重要特性,是动态大小的数组。与数组不同,切片是引用类型,不会复制整个数据结构,而是指向底层数组的一部分。因此切片操作更加灵活高效。

1. 定义

切片是基于数组的一个引用类型,它没有固定的长度,可以动态增长。切片包含三个要素:指向底层数组的指针、切片的长度、切片的容量。

2. 语法 var sliceName []type 3. 示例 package main import "fmt" func main() { // 定义一个切片 slice1 := []int{1, 2, 3} fmt.Println(slice1) // [1 2 3] // 使用 make 函数创建切片 slice2 := make([]int, 5) // 创建一个长度为5的切片,默认值为0 fmt.Println(slice2) // [0 0 0 0 0] // 切片的容量 fmt.Println(cap(slice2)) // 5 fmt.Println(len(slice2)) // 5 } 4. 特点 动态大小:切片的长度可以动态改变,可以根据需要扩展。引用类型:切片是引用类型,赋值和传递切片时是传递的底层数组的引用。零值:切片的零值是 nil,并且没有分配内存空间。可伸缩性:切片会根据需要动态扩展容量。底层数组:切片实际上是对数组的一个视图,它是一个指向底层数组的指针,具有长度和容量。 5. 切片的创建

可以使用 make 函数创建切片:

slice := make([]int, 5) // 创建一个长度为5的切片,默认值为零值(0) slice := make([]int, 5, 10) // 创建一个长度为5,容量为10的切片 6. 切片的操作

切片支持切片操作,可以从一个切片中提取子切片:

package main import "fmt" func main() { arr := []int{1, 2, 3, 4, 5} slice := arr[1:4] // 从 arr 中提取从索引 1 到索引 3 的部分,结果是 [2 3 4] fmt.Println(slice) }

切片的操作并不会复制底层数组,只是引用了原数组的一部分。

切片的扩展

切片支持动态扩展,当切片的容量不足时,Go 会自动扩展切片的容量。扩展的规则通常是将容量翻倍。

package main import "fmt" func main() { slice := []int{1, 2, 3} slice = append(slice, 4) // 添加元素到切片 fmt.Println(slice) // [1 2 3 4] } 切片的拷贝

当我们想要拷贝一个切片时,可以使用 copy 函数。

package main import "fmt" func main() { slice1 := []int{1, 2, 3} slice2 := make([]int, len(slice1)) // 创建一个新的切片 copy(slice2, slice1) // 将 slice1 的内容拷贝到 slice2 fmt.Println(slice2) // [1 2 3] }
Ⅲ 映射 1. 定义

映射是由键值对组成的集合,Go 中的映射是引用类型。每个键都对应一个值,且每个键在映射中是唯一的。如果使用一个已经存在的键进行赋值,旧的值将被替换。

2. 语法 var mapName map[keyType]valueType

其中,keyType 是映射的键的类型,valueType 是映射的值的类型。

3. 示例 package main import "fmt" func main() { // 创建一个映射,键为string类型,值为int类型 var m map[string]int fmt.Println(m) // 输出: nil,未初始化的映射是 nil // 初始化映射并添加元素 m = make(map[string]int) m["age"] = 30 m["score"] = 100 fmt.Println(m) // 输出: map[age:30 score:100] // 访问映射的值 fmt.Println(m["age"]) // 输出: 30 fmt.Println(m["score"]) // 输出: 100 // 访问不存在的键 fmt.Println(m["nonexistent"]) // 输出: 0,值的零值(int 类型的零值是 0) } 4. 特点 无序性:映射中的键值对是无序的,在迭代映射时,元素的顺序是不确定的。引用类型:映射是引用类型,赋值和传递映射时是传递的底层数据的引用。键唯一:每个映射的键都是唯一的,不允许重复。如果给已有的键赋值,原来的值会被覆盖。自动扩容:映射会根据元素的添加自动扩展。 5. 映射的创建

可以通过 make 函数来创建映射,make 函数接受两个参数:映射的键类型和映射的值类型。

// 创建一个空映射,键类型为string,值类型为int m := make(map[string]int) 6. 映射的操作 插入键值对:通过 map[key] = value 语法将键值对插入映射。访问值:通过 map[key] 语法访问映射中某个键对应的值。删除键值对:通过 delete(map, key) 函数删除某个键值对。判断键是否存在:通过 value, ok := map[key] 可以判断一个键是否存在。如果键存在,ok 为 true,否则为 false。 示例:插入、访问和删除 package main import "fmt" func main() { m := make(map[string]int) // 插入元素 m["apple"] = 5 m["banana"] = 3 fmt.Println(m) // 输出: map[apple:5 banana:3] // 访问元素 val, exists := m["apple"] if exists { fmt.Println("apple exists with value:", val) // 输出: apple exists with value: 5 } // 删除元素 delete(m, "banana") fmt.Println(m) // 输出: map[apple:5] } 判断键是否存在

当访问映射时,如果键不存在,Go 会返回该值的零值(如 0、""、nil 等)。为了区分键是否存在,可以使用 comma ok 语法:

value, ok := m["key"] 如果键存在,ok 为 true,value 为该键对应的值。如果键不存在,ok 为 false,value 为该类型的零值。 示例:判断键是否存在 package main import "fmt" func main() { m := map[string]int{ "apple": 5, "banana": 3, } // 判断 "apple" 是否存在 val, exists := m["apple"] fmt.Println(val, exists) // 5 true // 判断 "grape" 是否存在 val, exists = m["grape"] fmt.Println(val, exists) // 0 false } 映射的遍历

Go 提供了 for range 语法来遍历映射中的键值对。

package main import "fmt" func main() { m := map[string]int{ "apple": 5, "banana": 3, } // 遍历映射 for key, value := range m { fmt.Println(key, value) } }

输出结果可能类似于:

apple 5 banana 3

注意:映射的遍历顺序是不确定的,因为映射是无序的。


Ⅳ 映射与数组、切片的区别 数组:固定长度、值类型、元素位置有序。切片:动态长度、引用类型、元素位置有序。映射:无固定顺序、引用类型、键值对唯一。
Ⅴ 结构体 1. 结构体的定义

结构体通过 type 关键字定义,通常每个字段都有一个名称和类型。定义结构体的基本语法如下:

type StructName struct { Field1 type1 Field2 type2 // 可以继续添加其他字段 } 示例: type Person struct { Name string Age int Address string }

这个 Person 结构体有三个字段:Name(字符串类型)、Age(整数类型)、Address(字符串类型)。每个字段都有一个名称和类型。

2. 创建和初始化结构体

在 Go 中,可以通过多种方式创建和初始化结构体。

方式 1:使用字面量初始化结构体

可以使用结构体字面量(即直接在定义时给字段赋值)来创建一个结构体对象:

package main import "fmt" type Person struct { Name string Age int Address string } func main() { // 使用字面量创建并初始化结构体 p := Person{ Name: "Alice", Age: 30, Address: "Wonderland", } fmt.Println(p) // 输出: {Alice 30 Wonderland} }

方式 2:使用默认值创建结构体

如果没有指定字段值,字段将使用类型的零值进行初始化(例如 string 类型为 "",int 类型为 0)。

package main import "fmt" type Person struct { Name string Age int Address string } func main() { // 使用零值初始化结构体 p := Person{} fmt.Println(p) // 输出: { 0 } }

方式 3:使用指针创建结构体

Go 中的结构体是值类型,意味着传递结构体时是将值复制。如果希望修改结构体的值,可以使用结构体指针。

package main import "fmt" type Person struct { Name string Age int Address string } func main() { // 创建结构体指针 p := &Person{ Name: "Bob", Age: 25, Address: "Home", } fmt.Println(p) // 输出: &{Bob 25 Home} } 3. 结构体字段的访问

结构体的字段通过 . 运算符进行访问。可以通过结构体对象(或者结构体指针)访问字段。

访问结构体字段: package main import "fmt" type Person struct { Name string Age int Address string } func main() { p := Person{Name: "John", Age: 28, Address: "New York"} // 访问结构体字段 fmt.Println("Name:", p.Name) // 输出: Name: John fmt.Println("Age:", p.Age) // 输出: Age: 28 fmt.Println("Address:", p.Address) // 输出: Address: New York } 通过指针访问结构体字段:

当存在结构体指针时,通过 -> 运算符访问字段(其实在 Go 中是通过 * 解引用来实现的):

package main import "fmt" type Person struct { Name string Age int Address string } func main() { p := &Person{Name: "Alice", Age: 30, Address: "Wonderland"} // 通过指针访问结构体字段 fmt.Println("Name:", p.Name) // 输出: Name: Alice fmt.Println("Age:", p.Age) // 输出: Age: 30 fmt.Println("Address:", p.Address) // 输出: Address: Wonderland } 4. 修改结构体字段

结构体的字段可以在创建后进行修改:

package main import "fmt" type Person struct { Name string Age int Address string } func main() { p := Person{Name: "John", Age: 28, Address: "New York"} // 修改结构体字段的值 p.Name = "Tom" p.Age = 30 p.Address = "California" fmt.Println(p) // 输出: {Tom 30 California} }

如果使用的是结构体指针,则可以直接修改字段值。

5. 结构体作为函数参数

结构体可以作为函数的参数进行传递。由于结构体是值类型,传递结构体时会复制整个结构体,这意味着修改副本不会影响原结构体。如果需要修改原结构体,可以传递结构体指针。

传递结构体值: package main import "fmt" type Person struct { Name string Age int Address string } func changeName(p Person) { p.Name = "Changed" // 只是修改了副本,不会改变原结构体 } func main() { p := Person{Name: "John", Age: 28, Address: "New York"} changeName(p) fmt.Println(p) // 输出: {John 28 New York} 原结构体没有改变 } 传递结构体指针: package main import "fmt" type Person struct { Name string Age int Address string } func changeName(p *Person) { p.Name = "Changed" // 通过指针修改原结构体 } func main() { p := &Person{Name: "John", Age: 28, Address: "New York"} changeName(p) fmt.Println(p) // 输出: &{Changed 28 New York} 结构体被修改 } 6. 结构体的嵌套

Go 支持结构体嵌套,可以在结构体中嵌套其他结构体。这有助于实现类似“继承”的功能,但它与传统面向对象编程中的继承不同。

示例:结构体嵌套 package main import "fmt" type Address struct { Street, City, Country string } type Person struct { Name string Age int Address Address // 嵌套 Address 结构体 } func main() { p := Person{ Name: "John", Age: 28, Address: Address{ Street: "123 Main St", City: "New York", Country: "USA", }, } fmt.Println(p) // 输出: {John 28 {123 Main St New York USA}} } 7. 结构体与方法

在 Go 中,可以为结构体定义方法(即函数),这些方法可以操作结构体的字段。方法是与特定类型(结构体)绑定的。

示例:为结构体定义方法 package main import "fmt" type Person struct { Name string Age int } func (p *Person) Greet() { fmt.Println("Hello, my name is", p.Name) } func main() { p := &Person{Name: "John", Age: 28} p.Greet() // 输出: Hello, my name is John }

在上述例子中,Greet 是 Person 类型的方法,使用结构体的指针来调用它。


二、控制流 if 语句

if 语句是 Go 语言中的一种条件控制结构,用于判断给定条件是否成立。如果条件为 true,则执行大括号内的代码,否则执行 else 块中的代码。

基本语法

if condition { // 如果 condition 为 true 执行的代码块 } else { // 如果 condition 为 false 执行的代码块 }

例子

package main import "fmt" func main() { age := 20 if age > 18 { fmt.Println("成年人") // 如果年龄大于18,输出"成年人" } else { fmt.Println("未成年") // 如果年龄不大于18,输出"未成年" } } if 语句中的 else if

当有多个条件时,可以使用 else if 来进行多条件判断:

if condition1 { // 如果 condition1 为 true 执行的代码块 } else if condition2 { // 如果 condition1 为 false 且 condition2 为 true 执行的代码块 } else { // 如果 condition1 和 condition2 都为 false 执行的代码块 }

例子

package main import "fmt" func main() { age := 20 if age < 13 { fmt.Println("儿童") } else if age < 18 { fmt.Println("青少年") } else { fmt.Println("成年人") } }
for 循环

Go 语言的 for 循环有三种常见形式:标准 for 循环、无限循环、以及基于 range 的遍历。

标准 for 循环

这是最常见的循环形式,包含了初始化语句、条件判断语句以及更新语句。

语法:

for initialization; condition; post { // 循环体代码 }

例子

package main import "fmt" func main() { for i := 0; i < 5; i++ { fmt.Println(i) // 输出 0, 1, 2, 3, 4 } }

在此例中,i 从 0 开始,每次循环结束时,i 增加 1,直到 i 不满足 i < 5 这个条件时停止循环。

无限循环

Go 中可以使用 for 语句创建无限循环,语法为 for 后面没有条件判断。

例子

package main import "fmt" func main() { for { fmt.Println("无限循环") // 无限输出 "无限循环" } }

这个循环会一直执行,除非显式地使用 break 语句或发生其他中断操作(例如程序终止)。

range 遍历

range 关键字是 Go 中一种常用的遍历数组、切片、字符串、映射等数据结构的方式。它返回两个值:一个是索引,另一个是元素值。

语法:

for index, value := range collection { // 对每个元素执行的操作 }

例子

package main import "fmt" func main() { arr := []int{10, 20, 30} for index, value := range arr { fmt.Println(index, value) // 输出数组的索引和对应的值 } }

此例中,index 和 value 分别表示数组中的索引和对应的值,输出会是:

0 10 1 20 2 30
switch 语句

Go 中的 switch 语句是一个多路选择结构,它根据某个表达式的值来选择匹配的 case 语句执行。与传统的 switch 语句不同,Go 的 switch 语句不需要 break 来防止贯穿,每个 case 语句默认是结束的。

基本语法 switch expression { case value1: // 如果 expression == value1,执行此处代码 case value2: // 如果 expression == value2,执行此处代码 default: // 如果没有匹配到任何 case,执行此处代码 }

例子

package main import "fmt" func main() { day := 2 switch day { case 1: fmt.Println("星期一") case 2: fmt.Println("星期二") // 输出 "星期二" case 3: fmt.Println("星期三") default: fmt.Println("无效的星期") } } 省略 expression

如果没有给出 expression,则 switch 被当作 switch true 处理,这时每个 case 表达式都会被依次判断,直到匹配到 true。

例子

package main import "fmt" func main() { num := 4 switch { case num < 0: fmt.Println("负数") case num == 0: fmt.Println("零") case num > 0 && num < 10: fmt.Println("正数小于10") // 输出 "正数小于10" default: fmt.Println("其他") } } 多个 case 合并

多个 case 可以合并为一条代码块,只要它们执行相同的操作。

例子

package main import "fmt" func main() { grade := 'B' switch grade { case 'A': fmt.Println("优秀!") case 'B', 'C': // B 和 C 合并在一起 fmt.Println("做得不错!") case 'D': fmt.Println("通过!") case 'F': fmt.Println("下次加油!") default: fmt.Println("无效成绩") } } fallthrough 关键字

fallthrough 关键字允许在一个 case 执行后继续执行下一个 case,即使下一个 case 的条件不满足。

例子

package main import "fmt" func main() { num := 2 switch num { case 1: fmt.Println("1") case 2: fmt.Println("2") fallthrough // 会进入下一个 case case 3: fmt.Println("3") default: fmt.Println("无效数字") } }

输出结果:

2 3

在这个例子中,num 为 2,它会首先输出 2,然后由于 fallthrough,控制流继续进入 case 3 并输出 3。

标签:

【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句