Go 语言基础:快速上手 – wiki词典


Go 语言基础:快速上手

Go 语言(又称 Golang)是由 Google 开发的一种开源编程语言,它以其简洁、高效、并发支持良好以及快速编译等特性,在云计算、微服务、网络编程和命令行工具等领域获得了广泛应用。本文将带您快速了解 Go 语言的基础知识,帮助您轻松上手。

1. 为什么选择 Go 语言?

在开始学习之前,我们先了解一下 Go 语言的几个主要优势:

  • 编译速度快:Go 语言拥有极快的编译速度,可以大幅缩短开发周期。
  • 并发支持:内建 Goroutine 和 Channel 机制,使得编写高并发程序变得简单而高效。
  • 内存安全:Go 语言具有垃圾回收机制,自动管理内存,减少内存泄漏的风险。
  • 简洁易学:语法设计简洁,没有复杂的继承、泛型(早期版本)等概念,易于学习和使用。
  • 静态类型:编译时检查类型,减少运行时错误。
  • 强大的标准库:提供了丰富且高效的标准库,涵盖网络、I/O、加密等多种功能。
  • 跨平台:支持 Windows、Linux、macOS 等多种操作系统。

2. Go 语言环境搭建

首先,您需要在您的计算机上安装 Go。

  1. 下载 Go:访问 Go 官方下载页面:https://golang.org/dl/
  2. 安装:根据您的操作系统下载对应的安装包,并按照安装向导进行安装。
    • Windows: 双击 .msi 文件并按提示操作。
    • macOS: 双击 .pkg 文件并按提示操作。
    • Linux: 解压 .tar.gz 文件到 /usr/local (sudo tar -C /usr/local -xzf go*.tar.gz),然后将 /usr/local/go/bin 添加到 PATH 环境变量中。
  3. 验证安装:打开命令行工具(CMD/PowerShell for Windows, Terminal for macOS/Linux),输入 go version。如果显示 Go 的版本信息,则表示安装成功。

3. 您的第一个 Go 程序:”Hello, World!”

所有编程语言的入门都从 “Hello, World!” 开始。

  1. 创建文件:在一个您喜欢的目录中创建一个名为 main.go 的文件。
  2. 编写代码:将以下代码复制到 main.go 文件中。

    “`go
    package main // 声明主包,可执行程序的入口

    import “fmt” // 导入 fmt 包,用于格式化 I/O

    func main() { // main 函数是程序的入口点
    fmt.Println(“Hello, World!”) // 打印字符串到控制台
    }
    “`

  3. 运行程序:打开命令行,导航到 main.go 文件所在的目录,然后运行以下命令:

    bash
    go run main.go

    您将看到输出:Hello, World!

    如果您想编译成可执行文件:

    bash
    go build main.go // 编译,生成可执行文件 (例如:在 Windows 上是 main.exe)
    ./main // 运行可执行文件 (在 Windows 上是 main.exe 或 .\main.exe)

4. Go 语言基础语法

4.1. 包(Packages)

Go 语言通过包来组织代码。package main 表示这是一个可执行程序的主包,而 import 语句则用于导入其他包。

4.2. 变量(Variables)

Go 语言是静态类型语言,变量在使用前必须声明。

声明变量:

“`go
var name string = “Alice” // 声明并初始化一个字符串变量
var age int // 声明一个整数变量,未初始化时为零值 (0)
age = 30 // 赋值

var ( // 批量声明
width int = 100
height int = 200
)
“`

短声明(推荐):

在函数内部,可以使用 := 运算符进行变量的短声明和初始化,Go 会自动推断类型。

go
message := "Hello Go!" // 短声明,Go 推断 message 为 string 类型
count := 10 // 短声明,Go 推断 count 为 int 类型

零值(Zero Values):

当变量被声明但未显式初始化时,Go 会自动为它赋一个零值:
* int, float, complex: 0
* bool: false
* string: "" (空字符串)
* 指针、切片、映射、通道、函数、接口: nil

4.3. 常量(Constants)

常量是在编译时已知的值,不能被修改。

“`go
const Pi = 3.14159 // 声明一个常量
const ( // 批量声明
StatusOK = 200
StatusError = 500
)

const (
// iota 在 const 声明中用于创建一系列递增的常量值
A = iota // 0
B // 1
C // 2
)
“`

4.4. 基本数据类型

Go 语言支持以下基本数据类型:

  • 布尔型bool (true, false)
  • 整型int (根据系统决定 32 或 64 位), int8, int16, int32, int64, uint (无符号整型), uint8, uint16, uint32, uint64, byte (uint8 的别名), rune (int32 的别名,用于表示 Unicode 字符)。
  • 浮点型float32, float64
  • 复数型complex64, complex128
  • 字符串string (不可变)

go
var b bool = true
var i int = 42
var f float64 = 3.14
var s string = "Go programming"
var r rune = 'A' // Unicode 字符

5. 控制流

5.1. 条件语句:if-else

Go 的 if 语句不需要括号包围条件,但大括号 {} 必须存在。

“`go
num := 10
if num%2 == 0 {
fmt.Println(“Even number”)
} else {
fmt.Println(“Odd number”)
}

// if 语句可以带一个简短的语句,在条件表达式求值前执行
if x := 5; x > 0 { // x 的作用域仅限于 if-else 块
fmt.Println(“x is positive”)
} else if x < 0 {
fmt.Println(“x is negative”)
} else {
fmt.Println(“x is zero”)
}
“`

5.2. 循环语句:for

Go 语言只有 for 循环,没有 whiledo-while

经典 for 循环:

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

模拟 while 循环:

go
sum := 1
for sum < 10 { // 省略初始化和后置语句
sum += sum
}
fmt.Println(sum) // 输出 16

无限循环:

go
// for {
// fmt.Println("Infinite loop")
// }

遍历(range):

for...range 用于遍历数组、切片、字符串、映射和通道。

“`go
slice := []string{“apple”, “banana”, “cherry”}
for index, value := range slice {
fmt.Printf(“Index: %d, Value: %s\n”, index, value)
}

str := “你好 Go”
for i, r := range str { // 遍历字符串时,r 是 rune 类型
fmt.Printf(“%d: %c\n”, i, r)
}
“`

5.3. 选择语句:switch

Go 的 switch 语句比 C/C++ 更加灵活,默认带有 break

“`go
day := “Tuesday”
switch day {
case “Monday”:
fmt.Println(“It’s Monday!”)
case “Tuesday”, “Wednesday”: // 可以有多个值
fmt.Println(“It’s Tuesday or Wednesday!”)
default:
fmt.Println(“It’s another day.”)
}

// switch 也可以不带条件表达式,等同于 switch true
score := 85
switch {
case score >= 90:
fmt.Println(“Excellent!”)
case score >= 70:
fmt.Println(“Good!”)
default:
fmt.Println(“Needs improvement.”)
}
“`

6. 函数(Functions)

函数是 Go 语言的基本代码块,用于封装可重用的逻辑。

“`go
// 声明一个函数,接收两个 int 参数,返回一个 int
func add(x int, y int) int {
return x + y
}

// 当参数类型相同时,可以只写最后一个参数的类型
func subtract(x, y int) int {
return x – y
}

// 函数可以返回多个值
func swap(x, y string) (string, string) {
return y, x
}

// 命名返回值:可以在函数签名中命名返回值,并在函数体中直接使用它们
func divide(dividend, divisor int) (result, remainder int) {
result = dividend / divisor
remainder = dividend % divisor
return // 等同于 return result, remainder
}

func main() {
result := add(5, 3)
fmt.Println(“5 + 3 =”, result)

a, b := swap("world", "hello")
fmt.Println(a, b) // 输出 world hello

q, r := divide(10, 3)
fmt.Println("10 / 3 =", q, "remainder", r) // 输出 10 / 3 = 3 remainder 1

}
“`

7. 指针(Pointers)

Go 语言支持指针,但没有指针运算,比 C/C++ 更安全。

  • * 运算符用于声明指针类型或解引用(获取指针指向的值)。
  • & 运算符用于获取变量的内存地址。

go
i := 42
p := &i // p 现在指向 i 的内存地址
fmt.Println(*p) // 通过 p 读取 i 的值,输出 42
*p = 21 // 通过 p 设置 i 的值
fmt.Println(i) // 输出 21

8. 结构体(Structs)

结构体是用户自定义的复合数据类型,用于将零个或多个任意类型的值组合在一起。

“`go
type Person struct { // 声明一个 Person 结构体
Name string
Age int
City string
}

func main() {
// 创建结构体实例
p1 := Person{Name: “Alice”, Age: 30, City: “New York”}
fmt.Println(p1.Name, p1.Age, p1.City) // 访问字段

// 创建结构体实例(字段顺序可以不一致,但必须明确指定)
p2 := Person{Age: 25, Name: "Bob"} // City 会是零值 ""
fmt.Println(p2)

// 创建结构体指针
p3 := &Person{"Charlie", 35, "London"}
fmt.Println(p3.Name) // 通过指针访问字段,Go 会自动解引用

}
“`

9. 数组(Arrays)和切片(Slices)

9.1. 数组(Arrays)

数组是具有相同类型且固定长度的序列。

“`go
var a [5]int // 声明一个包含 5 个整数的数组,零值为 [0 0 0 0 0]
a[0] = 100 // 赋值
fmt.Println(a[0])

primes := [6]int{2, 3, 5, 7, 11, 13} // 声明并初始化
fmt.Println(primes)
“`

9.2. 切片(Slices)

切片是 Go 语言中最常用的数据结构,它提供了动态大小的、灵活的数组视图。切片是对底层数组的一个引用。

“`go
// 从数组创建切片
primes := [6]int{2, 3, 5, 7, 11, 13}
s := primes[1:4] // 创建一个从索引 1 到索引 3 的切片 (包含 1, 2, 3)
fmt.Println(s) // 输出 [3 5 7]

// 使用 make 函数创建切片
// make([]type, length, capacity)
// length 是切片长度,capacity 是底层数组的容量
t := make([]int, 5) // 创建一个长度为 5,容量为 5 的 int 切片
fmt.Println(t) // 输出 [0 0 0 0 0]

// 追加元素
t = append(t, 1, 2) // append 会返回一个新的切片,可能分配新的底层数组
fmt.Println(t) // 输出 [0 0 0 0 0 1 2]
“`

10. 映射(Maps)

映射(Map)是 Go 语言中用于存储键值对的数据结构,类似于其他语言中的哈希表或字典。

“`go
// 声明并初始化一个 map
m := make(map[string]int) // 键为 string,值为 int

m[“key1”] = 10
m[“key2”] = 20
fmt.Println(“Map:”, m)
fmt.Println(“key1 value:”, m[“key1”])

// 检查键是否存在
val, ok := m[“key3”] // 如果 key3 不存在,val 为零值,ok 为 false
fmt.Println(“key3 value:”, val, “exists:”, ok)

// 删除元素
delete(m, “key1”)
fmt.Println(“Map after delete:”, m)

// 声明并初始化一个带有初始值的 map
anotherMap := map[string]string{
“name”: “Bob”,
“age”: “30”,
}
fmt.Println(anotherMap)
“`

11. 并发:Goroutines 和 Channels

Go 语言最强大的特性之一是对并发的原生支持。

11.1. Goroutines

Goroutine 是 Go 语言的轻量级线程,由 Go 运行时管理,比操作系统线程开销小得多。通过在函数调用前加上 go 关键字即可启动一个 Goroutine。

“`go
func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond) // 暂停 100 毫秒
fmt.Println(s)
}
}

func main() {
go say(“world”) // 启动一个 Goroutine
say(“hello”) // 主 Goroutine 继续执行
// 由于主 Goroutine 很快结束,可能看不到 “world” 全部输出
// 实际应用中需要等待 Goroutine 完成,例如使用 sync.WaitGroup
}
“`

11.2. Channels

Channels 是 Goroutine 之间通信的管道,可以安全地发送和接收数据。

“`go
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将和发送到 channel c
}

func main() {
s := []int{7, 2, 8, -9, 4, 0}

c := make(chan int) // 创建一个 int 类型的 channel
go sum(s[:len(s)/2], c) // 计算前半部分的和
go sum(s[len(s)/2:], c) // 计算后半部分的和

x, y := <-c, <-c // 从 channel c 接收数据
// 接收顺序不确定,但两个 Goroutine 都会发送数据
fmt.Println(x, y, x+y) // 输出两个 Goroutine 的和以及总和

}
“`

12. 错误处理(Error Handling)

Go 语言通常通过返回多个值来处理错误,其中一个值是 error 类型。

“`go
import (
“errors”
“fmt”
)

func divideWithErr(dividend, divisor float64) (float64, error) {
if divisor == 0 {
return 0, errors.New(“cannot divide by zero”) // 返回一个 error
}
return dividend / divisor, nil // 没有错误时返回 nil
}

func main() {
result, err := divideWithErr(10, 2)
if err != nil {
fmt.Println(“Error:”, err)
} else {
fmt.Println(“Result:”, result)
}

result, err = divideWithErr(10, 0)
if err != nil {
    fmt.Println("Error:", err) // 输出 Error: cannot divide by zero
} else {
    fmt.Println("Result:", result)
}

}
“`

13. 包和模块(Packages and Modules)

Go 语言的代码组织基于包(package),包是同一目录下源文件的集合。
Go Modules 是 Go 语言的依赖管理系统,用于版本控制和包管理。

创建一个新模块:

bash
mkdir myproject
cd myproject
go mod init myproject // 初始化模块,会生成 go.mod 文件

go.mod 文件记录了项目的模块路径和依赖信息。

导入其他模块:

如果您在 main.go 中使用了第三方库,例如 github.com/gin-gonic/gin

“`go
package main

import (
“fmt”
“github.com/gin-gonic/gin” // 假设使用了 gin 框架
)

func main() {
fmt.Println(“Hello Go Modules!”)
// gin.Default() // 示例调用
}
“`

运行 go run main.gogo build 时,Go 会自动下载并管理 gin 模块的依赖。您也可以手动下载:

bash
go get github.com/gin-gonic/gin

14. 总结与下一步

通过本文,您应该已经对 Go 语言的基础语法、数据类型、控制流、函数、结构体、切片、映射、并发以及错误处理有了初步的了解。

Go 语言是一个强大而有趣的语言,其设计哲学强调简洁和效率。要进一步深入学习,建议您:

  • 多动手实践:尝试编写更多的小程序,解决实际问题。
  • 阅读官方文档https://golang.org/doc/ 提供了最权威的资料。
  • 学习标准库:Go 的标准库非常强大,掌握它们能大大提高开发效率。
  • 探索并发模式:深入理解 Goroutine 和 Channel 的高级用法,以及 sync 包的使用。
  • 阅读优秀开源项目代码:学习 Go 社区的最佳实践。

祝您在 Go 语言的学习旅程中愉快!


滚动至顶部