1 Go 语言背景

Go 语言被称为 21 世纪的 C 语言,最终的目标据说是设计网络和多核时代的 C 语言。

Go 语言的历史可以说是充满了奇闻和趣事,故事要从 2007 年说起,当时谷歌的工程师们因为软件开发过程中频繁使用的 C++存在一些痛点,比如编译速度慢、语言复杂等。于是,由 Robert Griesemer、Rob Pike 和 Ken Thompson 三位谷歌工程师联合发起了一个新的项目,旨在开发一门更高效、更简洁的编程语言。

他们的努力在 2009 年开始见到成果,那一年的 3 月,Go 语言正式面向全球开源,并发布了首个公开的版本。

Go 语言的设计目标是提供一种简洁、高效和易于使用的编程语言,以满足现代软件开发的需求。它借鉴了其他语言的优点,同时也摒弃了一些复杂性和冗余性。Go 语言拥有强大的并发性能和内置的垃圾回收机制,使其成为构建高性能和可伸缩的应用程序的理想选择。

有趣的是,Go 语言的名称源自游戏世界。根据创始人之一 Rob Pike 的说法,他们希望给这门语言一个简短而有力的名称,于是取名为"Go",寓意着前进、快速和简洁。

2 为什么要学习 Go 语言

学习 Go 语言(也被称为 Golang)有多种原因,它是一门现代的、高效的编程语言,适用于各种应用场景。以下是学习 Go 语言的一些主要原因:

  1. 高效性能: Go语言被设计成具有高效的执行性能。它的编译速度快,运行时性能优秀,适用于需要快速响应时间的应用程序,如网络服务和分布式系统。
  2. 并发支持: Go语言内置了强大的并发支持,通过goroutines和channels可以轻松实现并发编程,这对于构建高性能、高并发的应用程序非常有用。
  3. 内置工具: Go语言提供了丰富的标准库,包括网络、文本处理、加密、测试等方面的工具,使开发变得更加便捷。
  4. 静态类型检查: Go是一门静态类型语言,它在编译时进行类型检查,有助于减少运行时错误,提高代码的稳定性和可维护性。
  5. 跨平台支持: Go语言支持多个操作系统和体系结构,可以编写跨平台的应用程序。
  6. 开源社区: Go语言拥有活跃的开源社区,提供了大量的第三方库和工具,使开发人员能够更轻松地构建各种应用。
  7. 学习曲线低: Go语言的语法相对简单,与其他编程语言相比,学习曲线较低,新手可以相对快速地上手。
  8. Google支持: Go语言是由Google开发的,Google在许多项目中使用Go语言,这表明它在大规模系统开发方面有强大的支持。
  9. 云原生和微服务: Go语言在云原生和微服务架构中得到广泛应用,如Docker和Kubernetes等重要工具都是用Go语言编写的。

3 快速开始 Hello World

下面是在 Mac 上的实现:

3.1 安装 Go 环境

  1. 访问官方Go下载页面 https://go.dev/dl/ ,选择适合你操作系统的安装包,并下载最新版本的 Go 安装程序。
  2. 执行下载的安装程序,并按照提示进行安装。默认情况下,Go会安装到一个默认的目录,不需要进行额外配置。
  3. 验证 Go 是否安装成功,打开终端或命令行窗口,运行以下命令:
go version

如果显示 Go 的版本号,说明 Go 已成功安装。

3.2 编写第一个 go 程序

  1. 打开你喜欢的文本编辑器,创建一个新文件,将以下代码复制并粘贴到文件中:

    package main
    
    import "fmt"
    
    func main() {
        fmt.Println("Hello, World!")
    }
    

    这是一个简单的 Go 程序,它会输出"Hello, World!"。

  2. 保存文件,通常使用 .go 扩展名,比如 hello.go

在上面的代码中,我们定义了一个包,例如 main

package main

我们引入了一个标准的包:

  import "fmt"

最后是我们最重要的 main 函数,它是应用程序的入口,就像 C、Java 或 C# 等其他语言一样。

  func main() {
       ...
  }

3.3 运行 Go 程序

  1. 打开终端或命令行窗口,导航到包含你的 Go 程序文件的目录。

  2. 使用以下命令来编译和运行程序:

    go run hello.go
    

    如果一切正常,你将在终端上看到输出结果:"Hello, World!"。

这就是编写并运行第一个 Go 程序的基本步骤。你现在已经安装了 Go 环境,可以开始编写更多的 Go 代码并探索 Go 语言的功能和库。请注意,Go 具有强制的代码格式要求,你可以使用 gofmt 工具来格式化你的 Go 代码以符合标准。

Go 语言是编译型的语言,Go 的工具链将程序的源文件转变成为机器相关的二进制指令,这些工具可以通过单一的 go 命令配合其子命令进行使用,最简单的命令就是 run,它将一个或多个 .go 为后缀的源文件进行编译,链接,最后生成可执行文件。

如果我们不是一次性的实验,我们可以先编译输出一个可复用的程序,可以通过 build 来实现:

go build hello.go

上面的命令会生成一个 hello 的二进制程序,可以不经过任何的处理,随时可以运行:

./hello

4 Go 语言编程基本认识

4.1 包

Go 的标准库中有 100 多个包用来完成输入,输出,排序,文本处理等任务,比如我们常用的 fmt 包中的函数大多数是用于格式化的输入输出的。

main 包比较特殊,用于定义一个独立的可执行程序,而不是库。同样的,main 包中的 main 函数也是特殊的存在,main 函数相当于程序的入口,总是在程序开始执行的地方。

我们如果需要使用某一个包的内容,需要精准地导入该包,比如:

import(
	"fmt"
	"os"
)

4.2 函数

一个函数的声明由 func 关键字,函数名,参数列表(main 函数的参数是空的),返回值列表(可以为空),放在大括号内的函数体组成,函数体定义函数时用来做什么的。

Go 语言不需要再语句或者声明后面加上分号,除非是多个语句或者声明出现在同一行。Go 语言对于代码的格式化要求非常的严格,比如函数定义的 “{” 必须和关键字 “func” 在同一行,不能独自作为一行。

4.3 循环

Go 语言中有两种主要的循环结构:for 循环和 range 循环。下面我会分别介绍这两种循环的用法。

for 循环在 Go 语言中可以用来执行一段代码块多次,通常有三种基本形式:

4.3.1 基本的 for 循环:

for 初始化语句; 条件表达式; 后续语句 {
    // 循环体
}

示例:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

4.3.1.1 省略初始化语句的 for 循环:

for ; 条件表达式; 后续语句 {
    // 循环体
}

示例:

j := 0
for ; j < 5; j++ {
    fmt.Println(j)
}

4.3.1.2 省略初始化语句和后续语句的 for 循环:

for ; 条件表达式; {
    // 循环体
}

示例:

k := 0
for k < 5 {
    fmt.Println(k)
    k++
}

4.3.1.3 无限循环:

for {
    // 无限循环体
}

示例:

for {
    fmt.Println("无限循环")
}

4.3.2 range 循环

range 循环用于迭代数组、切片、映射(map)、字符串等数据结构的元素。它的基本语法如下:

for index, value := range 集合 {
    // 循环体
}

示例:

numbers := []int{1, 2, 3, 4, 5}
for index, value := range numbers {
    fmt.Printf("索引:%d,值:%d\n", index, value)
}

上述示例中,range 循环会依次将切片 numbers 中的元素的索引和值赋值给 indexvalue 变量,并执行循环体。

这就是 Go 语言中两种常见的循环方式,我们可以根据具体的需求选择合适的循环结构。

4.4 声明

Go 语言支持多种声明方式,用于声明变量、常量、类型等。以下是 Go 语言中常见的声明方式:

  1. 变量声明

    var variableName dataType // 声明一个变量
    

    示例:

    var age int // 声明一个整数变量
    

    或者使用简短声明方式:

    variableName := value // 使用简短声明方式初始化并声明一个变量
    

    示例:

    name := "Alice" // 声明一个字符串变量并初始化为 "Alice"
    
  2. 常量声明

    const constantName dataType = value // 声明一个常量
    

    示例:

    const pi = 3.1415926 // 声明一个浮点数常量
    
  3. 类型声明

    type typeName typeLiteral // 声明一个自定义类型
    

    示例:

    type Celsius float64 // 声明一个自定义的摄氏度类型
    
  4. 多个变量或常量同时声明

    var (
        variable1 dataType1 = value1
        variable2 dataType2 = value2
        // ...
    )
    

    示例:

    var (
        name  = "Bob"
        age   = 30
        email = "bob@example.com"
    )
    
  5. 短声明方式声明多个变量

    var (
        variable1, variable2, variable3 = value1, value2, value3
    )
    

    示例:

    var (
        x, y, z = 1, 2, 3
    )
    
  6. 声明并初始化映射(map)、切片(slice)、通道(channel)等复合类型

    mapVariable := make(map[keyType]valueType)
    sliceVariable := make([]dataType, length, capacity)
    channelVariable := make(chan dataType)
    

    示例:

    scores := make(map[string]int)
    names := make([]string, 0, 10)
    dataChannel := make(chan int)
    

这些是 Go 语言中常见的声明方式,我们可以根据需要选择适合的方式来声明变量、常量和自定义类型。

4.5 类型

Go 语言具有多种基本数据类型和复合数据类型。以下是 Go 语言中常见的数据类型:

4.5.1 基本数据类型

  1. 整数类型(Integer Types)

    • int :有符号整数类型,根据计算机架构可以是 32 位或 64 位。
    • int8int16int32int64 :有符号整数类型,分别占 8、16、32、64 位。
    • uint :无符号整数类型,根据计算机架构可以是 32 位或 64 位。
    • uint8uint16uint32uint64 :无符号整数类型,分别占 8、16、32、64 位。
  2. 浮点数类型(Floating-Point Types)

    • float32 :单精度浮点数类型。
    • float64 :双精度浮点数类型。
  3. 复数类型(Complex Types)

    • complex64 :包含 32 位实部和 32 位虚部的复数类型。
    • complex128 :包含 64 位实部和 64 位虚部的复数类型。
  4. 布尔类型(Boolean Type)

    • bool :表示布尔值,只有两个可能的值:truefalse
  5. 字符串类型(String Type)

    • string :表示文本字符串。
  6. 字符类型(Character Type)

    • byteuint8 的别名,通常用于表示 ASCII 字符。
    • runeint32 的别名,通常用于表示 Unicode 字符。

4.5.2 复合数据类型

  1. 数组类型(Array Types)

    • array :具有固定长度的数组,元素类型相同。
  2. 切片类型(Slice Types)

    • slice :可变长度的切片,基于数组创建。
  3. 映射类型(Map Types)

    • map :键值对集合,用于实现关联数组。
  4. 结构体类型(Struct Types)

    • struct :用户自定义的复合数据类型,可以包含不同类型的字段。
  5. 通道类型(Channel Types)

    • chan :用于在 Go 协程之间传递数据的通信机制。
  6. 函数类型(Function Types)

    • func :函数类型,可以作为参数传递给其他函数。
  7. 接口类型(Interface Types)

    • interface :一组方法的抽象集合,用于定义对象的行为。
  8. 指针类型(Pointer Types)

    • pointer :指向某个变量内存地址的指针类型。

这些是 Go 语言中的常见数据类型。每种类型都有其用途和特点,你可以根据需求选择合适的类型来定义变量和数据结构。

4.6 并发

Go 语言(也称为 Golang)是一种支持并发编程的编程语言,它内置了许多特性和工具,使并发编程更加容易和高效。Go 语言的并发模型基于 Goroutines 和 Channels。

以下是一些关于 Go 语言并发编程的基本概念和技术:

  1. Goroutines(协程):Goroutine 是 Go 语言中的轻量级线程,由 Go 语言的运行时系统管理。与传统的线程相比,Goroutines 的创建和销毁成本非常低,因此可以轻松创建成千上万个 Goroutines。你可以使用 go 关键字来创建一个新的 Goroutine。

    go someFunction() // 创建一个新的Goroutine来执行someFunction
    
  2. Channels(通道):通道是 Goroutines 之间用于通信的安全机制。它们可以用来传递数据或信号。通道有两种类型:带缓冲的通道和非缓冲通道。通道可以用于同步和协调 Goroutines 之间的操作。

    ch := make(chan int) // 创建一个整数类型的非缓冲通道
    ch <- 42             // 向通道发送数据
    value := <-ch        // 从通道接收数据
    
  3. 并发控制:Go 语言提供了一些工具,如 sync 包中的 WaitGroupMutex,用于控制并发程序的执行流程和共享资源的访问。WaitGroup 用于等待一组 Goroutines 完成,而 Mutex 用于实现互斥锁,以确保共享数据的安全访问。

    var wg sync.WaitGroup
    var mu sync.Mutex
    
  4. Select 语句select 语句用于处理多个通道操作,允许你选择首先准备好的通道来执行操作,从而避免 Goroutines 在等待某个通道操作时被阻塞。

    select {
        case result := <-ch1:
            // 处理ch1的数据
        case result := <-ch2:
            // 处理ch2的数据
    }
    
  5. 并发模式:Go 语言支持多种并发模式,包括生产者-消费者、工作池、并行迭代等。你可以根据具体的应用场景选择合适的模式。

下面是一个简单的 Go 语言并发编程示例,演示了如何使用 Goroutines 和 Channels 来实现并发执行:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)

	// 启动两个Goroutines
	go produce(ch)
	go consume(ch)

	// 等待一段时间,以便Goroutines完成
	time.Sleep(10 * time.Second)
}

func produce(ch chan int) {
	for i := 0; i < 5; i++ {
		ch <- i
		time.Sleep(1 * time.Second)
	}
	close(ch)
}

func consume(ch chan int) {
	for val := range ch {
		fmt.Println("Received:", val)
	}
}

这个示例中,一个 Goroutine 用于生成数据,另一个 Goroutine 用于消费数据,它们通过通道进行通信。这种模式可以应用于各种并发编程场景,如并行处理任务、数据流处理等,结果如下:

4.7 简单 web 编程

使用 Go 语言编写简单的 Web 应用程序通常涉及使用 Go 的标准库中的 net/http 包。以下是一个创建简单 Web 服务器的示例:

package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
}

func main() {
    http.HandleFunc("/hello", helloHandler)

    // 启动Web服务器,监听端口8080
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

在上面的示例中,我们首先导入 net/http 包,然后定义了一个 helloHandler 函数,该函数会在用户访问 /hello 路径时执行。http.HandleFunc 函数用于将 helloHandler 与指定的 URL 路径关联起来。

最后,我们使用 http.ListenAndServe 函数启动一个 Web 服务器,监听端口 8080。当你访问 http://localhost:8080/hello 时,服务器会响应并显示 "Hello, World!"。 20231011224418.png

这只是一个简单的示例,Go 的 net/http 包提供了更多的功能,允许你构建更复杂的 Web 应用程序,包括路由、中间件、模板渲染等。你还可以考虑使用外部的 Web 框架,如 Gin 或 Echo,来简化 Web 应用程序的开发。

5 小结

当你决定学习 Go 语言时,你正在迈出一步通向编程世界的精彩旅程。Go 是一门强大而富有表现力的编程语言,它具备一系列独特的特性,让你能够构建高效、可维护、并发安全的应用程序。

编程是一项持之以恒的工作,就像是长途跋涉。它不一定总是轻松的,但在你坚持不懈的过程中,你将逐渐见证自己的成长。每一行代码都是你通向成功的一步,即使它们是缓慢而小小的一步。