1.什么是go语言
go语言是由Google开发的一种开源编程语言。它于2007年开始设计,2009年首次正式发布。Go语言的设计目标是提供一个简单、高效、可靠的系统编程语言。
Go语言的设计借鉴了一些其他编程语言的特性,例如静态类型、垃圾回收、并发编程等。它提供了丰富的标准库,可以满足各种常见的编程需求,并且具有优秀的性能。
Go语言的语法简洁,易于理解和学习。它采用了结构化的编程风格,支持面向对象编程和函数式编程,同时具有强大的并发特性。其中,Goroutine和通道是Go语言并发编程的重要特点,可以轻松实现高效的并发程序。
Go语言也注重代码的可读性和可维护性,强制采用一些编码规范,例如使用短小的命名方式、代码缩进的规范等。这些规范使得Go代码更具一致性,增加了代码的可读性和可维护性。
2.go语言的特性
2.1 并发编程
Go语言原生支持并发编程,通过 Goroutine 和通道(Channel)的机制,可以轻松地编写并发程序,实现高效地利用多核处理器的能力,提高程序的性能。
2.2 内存管理
Go语言的垃圾回收器(Garbage Collector)能够自动管理内存,减轻开发者的负担,避免了手动内存管理带来的错误。
2.3 高效编译
Go语言的编译器(go build 或 go run)具有快速编译的特点,使用预编译技术,将代码转换为机器码的过程很快,并生成与操作系统相关的可执行文件。
2.4 静态类型和类型推导
Go语言是静态类型语言,变量在声明时需要指定类型,有助于提早发现类型错误。同时,Go语言也支持类型推导,可以根据赋值的字面量自动推导变量的类型,简化了代码书写。
2.5 强大的标准库
Go语言标准库提供了许多常用的功能模块,包括网络编程、文件操作、加密解密、并发编程等,开发者可以直接使用标准库提供的功能,减少重复造轮子的工作。
2.6 多平台支持
Go语言具有很好的跨平台支持,可以在不同的操作系统上进行开发和部署。
2.7 调试和测试支持
Go语言提供了丰富的调试和测试工具,比如内置的调试器(go tool pprof)、单元测试和性能测试框架,方便开发者进行代码调试和质量保证。
3.go语言基础语法
3.1 变量声明
可以使用关键字 var声明变量,具体的数据类型后置,例如:var x int
可以同时声明多个变量,例如:var x , y int
可以使用赋值运算符 = 进行初始化
可以使用简短声明方式 := 来进行变量的声明和初始化,由go语言自行推导数据类型。例如:x:=10,同一个变量只能使用一次
3.2 数据类型
包括基本数据类型(int,float,bool,string等)和复合数据类型(数组,切片,映射,结构体等)
编译器不允许对从标识符引用的值进行强制类型转换
a := 1.1
b := 1 + a
上述代码中a被推断为浮点数,1会变成浮点数与a相加后赋给1
a := 1
b := a + 1.1
但上述代码将会报错,a已经被推断为整数,不能被强制转换为浮点数与1.1相加
3.2.1 切片
切片是go语言中一种对数组的抽象,用于动态的创建和操作可变长度的序列,由一个指向底层数组的指针、长度和容量组成。与数组相比,切片的长度可以动态改变。
由于切片是对底层数组进行了引用,因此共享同一片内存空间,因此切片传递给函数时也只会复制切片本身的信息,不会复制底层数组,降低了内存和性能的开销。
package main
import "fmt"
func main() {
// 切片的初始化
s := []int{1, 2, 3} // 使用切片字面量创建初始元素已知的切片
fmt.Println(s) // 输出: [1 2 3]
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // 从数组中创建切片
fmt.Println(slice) // 输出: [2 3 4]
str := "Hello, World!"
strSlice := str[7:12] // 从字符串中创建切片
fmt.Println(strSlice) // 输出: World
// 切片的截取
subSlice := s[1:3] // 截取切片的一部分
fmt.Println(subSlice) // 输出: [2 3]
// 切片的追加和扩容
s = append(s, 4, 5) // 追加元素到切片末尾
fmt.Println(s) // 输出: [1 2 3 4 5]
newSlice := make([]int, len(s), 10) // 创建一个新的切片,底层数组容量为10
copy(newSlice, s) // 复制切片内容到新的切片
fmt.Println(newSlice) // 输出: [1 2 3 4 5]
// 切片的长度和容量
fmt.Println(len(s)) // 输出: 5
fmt.Println(cap(s)) // 输出: 5
}
3.2.2 空结构体
空结构体是go语言特有的一种数据类型,表示一个没有任何字段的结构体,可能在需要表示某种概念但不需要实际存储数据的场景中使用。
空结构体在内存中不占用任何空间,因此特别适用于需要大量相同概念的标记、计数、集合等场景。
由于不占用内存,其值始终相等
package main
import "fmt"
type EmptyStruct struct{}
func main() {
// 声明一个空结构体变量
var empty EmptyStruct
fmt.Println(empty) // 输出: {}
// 创建一个空结构体切片,长度为5
emptySlice := make([]EmptyStruct, 5)
fmt.Println(emptySlice) // 输出: [{} {} {} {} {}]
// 使用空结构体作为映射的键
emptyMap := make(map[EmptyStruct]string)
emptyMap[EmptyStruct{}] = "value"
fmt.Println(emptyMap) // 输出: map[{}:value]
}
3.2.3 通道
在Go语言中,通道(Channel)是一种用于在 goroutine 之间进行通信和同步的数据类型。它提供了一种安全、高效的方式来传递数据。
通道的数据类型表示了通道中允许传输的值的类型。可以在通道声明时指定数据类型,也可以使用空接口类型 interface{} 来代表任意类型的值。
对于通道而言,发送和接收的数据类型必须匹配。如果要在通道之间传输不同类型的值,可以使用空接口类型 interface{} 或进行类型断言来处理。
-
通道的基本类型:
chan int:用于传输整数类型数据的通道chan string:用于传输字符串类型数据的通道chan bool:用于传输布尔类型数据的通道chan float64:用于传输浮点数类型数据的通道
-
自定义结构体类型:
- 通过
type关键字定义的自定义结构体类型,可以作为通道的数据类型。
type Person struct { Name string Age int } chanPerson := make(chan Person) // 用于传输 Person 类型数据的通道 - 通过
-
空接口类型:
- 使用空接口类型
interface{}来表示通道中的任意类型的值。
chanAny := make(chan interface{}) // 用于传输任意类型数据的通道 - 使用空接口类型
3.3 控制流
3.3.1 if-else语句
if condition {
// 条件满足时执行的代码块
} else if condition {
// 满足其他条件时执行的代码块
} else {
// 上述条件都不满足时执行的代码块
}
3.3.2 循环语句
go语言中只有for循环
for initialization; condition; post {
// 循环体中的代码块
}
for condition { ... }:顶部循环,没有初始化和后置语句。for { ... }:无限循环。
3.3.3 开关语句
switch expression {
case value1:
// 如果 expression 等于 value1
case value2:
// 如果 expression 等于 value2
default:
// 表达式不等于任何一个 value
}
case后不需要加break,找到符合条件的代码块,执行完后自动退出switch代码块
如果希望在一个case分支结束后继续执行后续的case分支,可以使用fallthrough关键字来实现。使用fallthrough关键字会强制执行下一个case分支,不论后续的分支条件是否成立。例如:
switch num {
case 1:
fmt.Println("One")
fallthrough
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
default:
fmt.Println("Other")
}
在上述示例中,如果num的值为1,除了执行fmt.Println("One")之外,还会继续执行下一个case分支fmt.Println("Two"),因为使用了fallthrough关键字。
3.4 函数定义
在go语言中,使用func关键字定义函数,基本语法如下
func add(x int, y int) int {
sum := x + y
return sum
}
go语言支持多返回值函数
func swap(a, b int) (int, int) {
return b, a
}
Go语言还支持可变参数函数,即函数的参数个数是可变的。这可以通过使用 ... 表示参数类型的方式来实现。
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
上述示例中的 sum 函数接受任意个 int 类型的参数,并将它们求和后返回结果。
3.5 包和导入
3.5.1 包的声明和命名:
- 在源代码文件的开头使用 `package` 关键字进行声明,指定包的名称。
- 按照惯例,包名应该是小写字母,可以使用多个单词,但不推荐使用下划线。
- 例如:`package main`、`package utils`。
3.5.2 导入其他包:
- 使用 `import` 关键字导入其他包,以在当前文件中使用其中的函数、变量等。
- 可以导入单个包,也可以导入多个包。
- 例如:
```
import "fmt"
import "math"
```
**
或
```
import (
"fmt"
"math"
)
```
**
3.5.3 导入包的使用:
通过导入包的名称,可以访问其中的函数、变量等。
可以使用.操作符来省略包名,直接使用导入包的函数和变量。
可以使用别名给导入的包重命名,以避免命名冲突。
例如:
import (
"fmt"
m "math"
)
func main() {
fmt.Println("Hello, world!")
fmt.Println(m.Sqrt(16))
}
或
import . "fmt"
func main() {
Println("Hello, world!")
}
```