导论
-
Go语言简介
-
为什么选择Go语言
-
Go语言的应用领域
第一章: 开始
-
安装Go语言环境
-
编写你的第一个Go程序
-
Go语言的基本语法
第二章: 数据类型与变量
-
基本数据类型
-
变量声明与赋值
-
数据类型转换
第三章: 控制流程
-
条件语句
-
循环结构
-
跳转语句
第四章: 函数
-
函数的定义与调用
-
函数参数与返回值
-
可变参数函数
-
匿名函数与闭包
第五章: 数组与切片
-
数组的定义与初始化
-
数组的操作
-
切片的定义与初始化
-
切片的操作
第六章: 映射与结构体
-
映射的定义与初始化
-
映射的操作
-
结构体的定义与初始化
-
结构体的操作
第七章: 方法与接口
-
方法的定义与调用
-
方法与接收者
-
接口的定义与实现
-
空接口与类型断言
第八章: 并发编程
-
Goroutine的创建与调度
-
通道的使用
-
同步与互斥
-
常见并发模式
第九章: 包管理与工程组织
-
包的导入与使用
-
自定义包
-
Go语言工程的组织与管理
第十章: 错误处理
-
错误类型与错误处理策略
-
defer语句
-
panic与recover机制
第十一章: 测试与性能优化
-
单元测试与性能测试
-
性能优化技巧
-
基准测试的使用
附录: 实战项目
-
构建一个简单的Web应用
-
使用Go语言编写一个命令行工具
-
与数据库交互的示例程序
导论
Go语言是一种由谷歌开发的开源编程语言,于2009年正式发布。它是一种静态类型、编译型语言,旨在提供简洁、高效、可靠的编程体验。自问世以来,Go语言在网络编程、云计算、分布式系统等领域广受欢迎,并被许多知名公司和项目所采用。
为什么选择Go语言?
-
简洁直观: Go语言拥有清晰简洁的语法和规范,易于学习和使用。它摒弃了一些传统语言中繁琐的语法和特性,使得代码更加易读易写。
-
高效性能: Go语言的编译器和运行时系统被设计为高效稳定,能够充分利用现代计算机硬件资源。其轻量级的协程(Goroutine)和通道(Channel)机制使得并发编程变得简单而高效。
-
丰富标准库: Go语言提供了丰富而强大的标准库,涵盖了网络编程、文本处理、加密解密、图像处理等各个领域,开发者可以直接利用标准库来完成许多常见任务,避免重复造轮子。
-
强大工具链: Go语言提供了一套完善的工具链,包括编译器、格式化工具、测试工具等,这些工具能够大大提升开发效率和代码质量。
Go语言的应用领域
-
网络编程: 由于Go语言天生支持并发编程,并具有优秀的网络库,因此在构建高性能的网络服务和分布式系统方面具有显著优势。许多知名的互联网公司如谷歌、Facebook、Twitter等都在使用Go语言开发其后端服务。
-
云计算: Go语言被广泛应用于云计算领域,如容器编排工具Kubernetes就是用Go语言编写的。其并发编程能力和高效性能使得Go语言成为构建大规模云原生应用的首选语言之一。
-
系统编程: 由于Go语言的性能和可靠性,它也被广泛用于系统编程领域。例如,Docker等容器技术的底层就是用Go语言实现的。
-
Web开发: Go语言提供了简单易用的Web框架,如Gin、Beego等,使得开发者能够快速构建高性能的Web应用程序。
总而言之,Go语言以其简洁高效的特性,成为了现代软件开发中不可或缺的重要工具之一,无论是构建网络服务、云原生应用,还是编写高性能的系统程序,都能够发挥其强大的优势。
第一章: 开始
在这一章节中,我们将介绍如何开始使用Go语言,并编写你的第一个Go程序。我们将从安装Go语言环境开始,然后编写一个简单的Hello World程序,来熟悉Go语言的基本语法和编程环境。
1、安装Go语言环境
要开始学习和使用Go语言,首先需要安装Go语言的开发环境。你可以从官方网站下载适用于你操作系统的安装包,并按照官方文档进行安装步骤。
2、编写你的第一个Go程序
打开你喜欢的文本编辑器,创建一个名为hello.go
的文件,并输入以下代码:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
让我们逐行解释一下这个程序:
package main
: 这一行告诉Go编译器这个文件属于main
包,而main
包是一个特殊的包,它包含了程序的入口点。import "fmt"
: 这一行导入了一个名为fmt
的标准库包,它提供了格式化输入输出的功能。func main() { ... }
: 这是我们的程序的入口点。main
函数是Go程序的入口,当程序启动时,会首先执行main
函数内的代码。fmt.Println("Hello, World!")
: 这一行代码使用fmt
包中的Println
函数,将字符串"Hello, World!"
打印到标准输出。
- 运行程序
保存好hello.go
文件后,打开终端,进入该文件所在的目录,然后执行以下命令:
你将看到终端输出了go run hello.go
Hello, World!
,这表示你的第一个Go程序成功运行了!现在,你已经完成了第一个Go程序的编写和运行。接下来,我们将深入学习Go语言的基本语法和特性。
3、Go程序的基础语法
在这一章节中,我们将探讨Go语言的基本语法。了解这些基础知识对于进一步学习和使用Go语言非常重要。
1. 注释
在Go语言中,注释使用//
进行单行注释,使用/* */
进行多行注释。例如:
// 这是单行注释
/*
这是
多行
注释
*/
2. 包声明
每个Go程序都是由包组成的,使用package
关键字声明包。其中,main
包是一个特殊的包,用于标识可执行程序的入口点。
package main
3. 导入包
使用import
关键字导入需要使用的包。
import "fmt"
4. 函数
使用func
关键字定义函数。main()
函数是程序的入口点。
func main() {
fmt.Println("Hello, World!")
}
5. 变量声明
使用关键字var
声明变量,可以指定变量类型也可以让编译器推断类型。
var x int
x = 10
var y = 20
z := 30 // 简短声明
6. 数据类型
Go语言具有丰富的数据类型,包括基本数据类型(如整数、浮点数、布尔值)、复合数据类型(如数组、切片、映射、结构体)等。
var age int = 30
var name string = "Alice"
var isStudent bool = true
7. 控制流程
Go语言提供了常见的控制流程语句,包括条件语句(if
、else
)、循环语句(for
)、跳转语句(break
、continue
、goto
)等。
if x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than or equal to 10")
}
for i := 0; i < 5; i++ {
fmt.Println(i)
}
8. 匿名函数与闭包
Go语言支持匿名函数的定义,也支持闭包。
add := func(x, y int) int {
return x + y
}
result := add(3, 5)
fmt.Println(result) // 输出 8
以上是Go语言的基本语法介绍。通过理解和掌握这些基础知识,你将能够开始编写简单的Go程序,并逐渐探索更复杂的应用和特性。
第二章: 数据类型与变量
在这一章节中,我们将深入了解Go语言中的数据类型以及如何声明和使用变量。
1. 基本数据类型
Go语言具有以下基本数据类型:
- 整数类型:
int
,int8
,int16
,int32
,int64
,uint
,uint8
,uint16
,uint32
,uint64
,uintptr
- 浮点数类型:
float32
,float64
- 复数类型:
complex64
,complex128
- 布尔类型:
bool
- 字符串类型:
string
- 字节类型:
byte
(类似于uint8
) - Unicode字符类型:
rune
(类似于int32
)
下面是一些基本数据类型的声明示例:
var age int = 30
var height float64 = 175.5
var isMarried bool = false
var name string = "Alice"
var char byte = 'A'
var runeVar rune = '♥'
2. 变量声明与赋值
在Go语言中,可以使用var
关键字声明变量,并使用=
进行赋值。也可以使用简短声明语法:=
进行变量声明和初始化。
var x int
x = 10
var y int = 20
z := 30 // 简短声明
3. 数据类型转换
在Go语言中,数据类型之间的转换需要显式地进行。可以使用类型转换操作符将一个类型的值转换为另一个类型。
var x int = 10
var y float64 = float64(x)
var a float64 = 5.67
var b int = int(a)
var c int = 10
var d byte = byte(c)
以上就是关于Go语言中数据类型与变量的基本介绍。通过理解和掌握这些知识,你可以更好地进行数据的处理和管理,在编写Go程序时更加得心应手。
第三章: 控制流程
在这一章节中,我们将学习如何使用条件语句、循环结构和跳转语句来控制程序的执行流程。
1. 条件语句
条件语句允许根据条件选择性地执行代码块。Go语言提供了if
语句和switch
语句来实现条件判断。
if
语句
age := 20
if age >= 18 {
fmt.Println("成年人")
} else {
fmt.Println("未成年人")
}
switch
语句
day := 3
switch day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
default:
fmt.Println("其他")
}
2. 循环结构
循环结构允许多次执行同一段代码。Go语言提供了for
循环来实现不同类型的循环。
for
循环
// 基本的for循环
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 类似于while循环
num := 0
for num < 5 {
fmt.Println(num)
num++
}
// 无限循环
for {
fmt.Println("无限循环")
}
3. 跳转语句
跳转语句允许在程序中执行跳转操作。Go语言提供了break
、continue
和goto
等跳转语句。
break
语句
for i := 0; i < 5; i++ {
if i == 3 {
break
}
fmt.Println(i)
}
continue
语句
for i := 0; i < 5; i++ {
if i == 3 {
continue
}
fmt.Println(i)
}
goto
语句
i := 0
Loop:
for i < 5 {
fmt.Println(i)
i++
goto Loop
}
以上就是关于控制流程的基本介绍。通过掌握这些知识,你可以更灵活地控制程序的执行流程,编写出更加复杂和有逻辑性的程序。
第四章: 函数
在这一章节中,我们将深入探讨Go语言中函数的定义、调用以及参数和返回值的相关知识,同时介绍可变参数函数、匿名函数和闭包的概念。
1. 函数的定义与调用
函数是一段具有特定功能的代码块,可以通过函数名进行调用。在Go语言中,函数使用func
关键字定义。
func sayHello() {
fmt.Println("Hello!")
}
func main() {
sayHello() // 调用函数
}
2. 函数参数与返回值
函数可以接受参数,并返回一个或多个值。参数和返回值都可以指定类型。
func add(x, y int) int {
return x + y
}
func main() {
result := add(3, 5)
fmt.Println(result) // 输出 8
}
3. 可变参数函数
Go语言支持可变参数函数,即函数的参数数量是可变的。使用...
来表示可变参数。
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 输出 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 输出 15
}
4. 匿名函数与闭包
匿名函数是指没有函数名的函数,可以在函数内部定义并直接调用。闭包是一个函数值,它引用了函数体外的变量。
func main() {
// 匿名函数
func() {
fmt.Println("匿名函数被调用")
}()
// 闭包
x := 10
increment := func() int {
x++
return x
}
fmt.Println(increment()) // 输出 11
fmt.Println(increment()) // 输出 12
}
以上就是关于函数的基本介绍。函数作为Go语言中的重要组成部分,具有丰富的功能和灵活性,可以帮助我们更好地组织和重用代码。
第五章: 数组与切片
在这一章节中,我们将学习关于数组和切片的定义、初始化以及操作方法,这两个数据结构在Go语言中非常常用,对于数据的存储和处理具有重要作用。
1. 数组的定义与初始化
数组是具有固定长度且拥有相同数据类型元素的集合。在Go语言中,数组的长度是数组类型的一部分。
// 定义一个包含5个整数的数组
var arr [5]int
// 初始化数组
arr = [5]int{1, 2, 3, 4, 5}
2. 数组的操作
数组的操作包括访问元素、修改元素、以及遍历数组等。
// 访问数组元素
fmt.Println(arr[0]) // 输出 1
// 修改数组元素
arr[0] = 10
// 遍历数组
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
3. 切片的定义与初始化
切片是一个长度可变的数组,是对底层数组的一个引用。切片使用make
函数进行初始化。
// 定义一个切片
var slice []int
// 使用make函数创建切片
slice = make([]int, 5) // 长度为5的切片
4. 切片的操作
切片支持动态增长、追加元素、删除元素等操作。
// 追加元素到切片
slice = append(slice, 6)
// 删除切片中的元素
slice = append(slice[:2], slice[3:]...)
// 遍历切片
for _, value := range slice {
fmt.Println(value)
}
通过以上学习,你已经掌握了数组和切片的基本概念以及在Go语言中的使用方法。数组适用于固定长度的数据集合,而切片则更加灵活,适用于长度不固定的情况,同时切片支持动态操作,使得数据的处理更加方便和高效。
第六章: 映射与结构体
在这一章节中,我们将学习关于映射(Map)和结构体(Struct)的定义、初始化以及操作方法。映射用于存储键值对数据,而结构体用于组织和管理复杂的数据结构。
1. 映射的定义与初始化
映射是一种无序的键值对集合,每个键对应一个值。在Go语言中,可以使用make
函数创建一个空的映射,并使用map
关键字定义映射的键值类型。
// 定义一个映射,键为string类型,值为int类型
var m map[string]int
// 初始化映射
m = make(map[string]int)
也可以在声明时直接进行初始化:
m := map[string]int{
"apple": 1,
"banana": 2,
"cherry": 3,
}
2. 映射的操作
映射支持添加、获取、删除元素等操作。
// 添加元素到映射
m["orange"] = 4
// 获取映射中的元素
value := m["banana"]
// 删除映射中的元素
delete(m, "cherry")
3. 结构体的定义与初始化
结构体是一种用户自定义的复合数据类型,用于组织和存储多个字段的数据。在Go语言中,使用type
关键字定义结构体。
// 定义一个结构体
type Person struct {
Name string
Age int
}
// 初始化结构体
p := Person{
Name: "Alice",
Age: 30,
}
4. 结构体的操作
结构体的字段可以通过.
操作符进行访问和修改。
// 访问结构体字段
fmt.Println(p.Name)
// 修改结构体字段
p.Age = 31
通过以上学习,你已经掌握了映射和结构体的基本概念以及在Go语言中的使用方法。映射用于存储键值对数据,适用于动态数量的数据集合;而结构体用于组织和管理复杂的数据结构,适用于存储固定数量、具有相关性的字段数据。
第七章: 方法与接口
在这一章节中,我们将学习关于方法和接口的定义、实现以及使用方法。方法是一种与特定类型关联的函数,而接口则是一种抽象类型,描述了对象的行为。
1. 方法的定义与调用
方法是与特定类型关联的函数,通过在函数名前加上类型名称,即可创建方法。方法允许我们在自定义类型上定义行为。
type Circle struct {
Radius float64
}
// 定义Circle类型的方法
func (c Circle) Area() float64 {
return 3.14 * c.Radius * c.Radius
}
// 调用Circle类型的方法
c := Circle{Radius: 5}
area := c.Area()
2. 方法与接收者
方法的接收者是指定方法所作用的类型。可以是指针类型或值类型。对于值类型接收者,方法内部对接收者的修改不会影响原对象,而对于指针类型接收者,则会影响原对象。
type Counter struct {
count int
}
// 值类型接收者的方法
func (c Counter) Increment() {
c.count++
}
// 指针类型接收者的方法
func (c *Counter) Reset() {
c.count = 0
}
3. 接口的定义与实现
接口是一种抽象类型,描述了对象的行为。接口定义了一组方法的集合,任何类型只要实现了接口中的所有方法,就被称为实现了该接口。
type Shape interface {
Area() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14 * c.Radius * c.Radius
}
4. 空接口与类型断言
空接口是指没有任何方法的接口,因此任何类型都实现了空接口。空接口可以用来存储任意类型的值。
var i interface{}
i = 42
i = "hello"
类型断言用于提取接口值的底层值,并检查其类型。
value, ok := i.(int)
if ok {
fmt.Println("Integer value:", value)
} else {
fmt.Println("Not an integer")
}
通过以上学习,你已经了解了方法和接口的基本概念以及在Go语言中的使用方法。方法允许我们在自定义类型上定义行为,而接口则定义了一组方法的集合,提供了一种多态的实现方式。
第八章: 并发编程
在这一章节中,我们将学习关于并发编程的基本概念以及在Go语言中如何实现并发编程。Go语言提供了丰富的并发编程工具,包括goroutine、通道、同步与互斥等机制,让并发编程变得更加简单和高效。
1. Goroutine的创建与调度
Goroutine是Go语言中轻量级的线程,由Go语言的运行时系统进行管理。通过go
关键字可以创建一个新的goroutine。
func sayHello() {
fmt.Println("Hello from goroutine!")
}
func main() {
// 创建并启动goroutine
go sayHello()
// 等待goroutine执行结束
time.Sleep(time.Second)
}
2. 通道的使用
通道(Channel)是一种用来在goroutine之间进行通信的机制。通道可以在goroutine之间传递数据,实现数据的同步和共享。
// 创建一个字符串通道
ch := make(chan string)
// 发送数据到通道
ch <- "Hello"
// 从通道接收数据
msg := <-ch
fmt.Println(msg)
3. 同步与互斥
在并发编程中,需要保证共享数据的安全访问。Go语言提供了同步和互斥机制来实现对共享数据的安全访问。
var counter int
var mu sync.Mutex
// 使用互斥锁保护共享数据
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}
// 使用WaitGroup实现goroutine的同步
var wg sync.WaitGroup
func worker() {
defer wg.Done()
// do something
}
func main() {
for i := 0; i < 5; i++ {
wg.Add(1)
go worker()
}
wg.Wait()
}
4. 常见并发模式
在并发编程中,有一些常见的并发模式被广泛应用,如生产者-消费者模式、worker池模式等。
// 生产者-消费者模式
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) {
for num := range ch {
fmt.Println(num)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
通过以上学习,你已经了解了如何在Go语言中进行并发编程。并发编程可以提高程序的性能和效率,但也需要注意共享数据的安全访问,避免出现竞态条件和数据竞争的问题。
第九章: 包管理与工程组织
在这一章节中,我们将学习如何进行包的导入与使用,以及如何自定义包和组织管理Go语言工程。
1. 包的导入与使用
Go语言通过import
关键字导入外部包,并使用其中的函数、变量或结构体等。
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
2. 自定义包
在Go语言中,可以通过创建自定义包来组织和复用代码。一个包是一组相关的Go源文件的集合,它们在同一个目录下,并且具有相同的包名。
例如,创建一个名为utils
的自定义包:
// utils/math.go
package utils
func Add(x, y int) int {
return x + y
}
在其他文件中导入并使用该包:
// main.go
package main
import (
"fmt"
"your_module_path/utils"
)
func main() {
sum := utils.Add(3, 5)
fmt.Println("Sum:", sum)
}
3. Go语言工程的组织与管理
对于大型项目,合理的组织和管理是非常重要的。可以按照以下结构组织Go语言工程:
project
│
├── cmd
│ └── main.go
│
├── pkg
│ └── utils
│ └── math.go
│
└── internal
└── api
└── api.go
cmd
: 存放可执行程序的入口文件,每个子目录对应一个可执行程序。pkg
: 存放自定义包的源代码文件。internal
: 存放项目内部使用的包,不对外公开。
通过合理的组织和管理,可以使得工程结构清晰、易于维护,并且方便团队协作开发。
通过以上学习,你已经了解了如何进行包的导入与使用,以及如何自定义包和组织管理Go语言工程。合理的包管理和工程组织能够提高代码的复用性和可维护性,是编写高质量Go代码的重要一环。
第十章: 错误处理
在这一章节中,我们将学习如何处理Go语言中的错误。错误处理是编写健壮程序的重要组成部分,它可以帮助我们检测和处理程序中的异常情况,保证程序的稳定性和可靠性。
1. 错误类型与错误处理策略
在Go语言中,错误通常用一个实现了error
接口的类型来表示。error
接口只有一个方法Error() string
,用于返回错误的描述信息。
type error interface {
Error() string
}
错误处理策略通常包括检查函数的返回值、使用错误值进行判断和处理。
func divide(x, y int) (int, error) {
if y == 0 {
return 0, errors.New("division by zero")
}
return x / y, nil
}
2. defer语句
defer
语句用于延迟执行函数调用,它会在函数执行完毕之后执行,无论函数是正常返回还是发生了错误。
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close() // 确保文件在函数返回时关闭
// 处理文件内容
}
3. panic与recover机制
panic
函数用于引发程序中的严重错误,导致程序崩溃。recover
函数用于在发生panic
时进行错误恢复。
func readConfig(filename string) error {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
if _, err := os.Stat(filename); err != nil {
panic("config file not found")
}
// 读取配置文件并进行处理
}
通过以上学习,你已经了解了如何在Go语言中进行错误处理。良好的错误处理策略可以帮助我们更好地应对程序中可能发生的异常情况,保证程序的稳定性和可靠性。
第十一章: 测试与性能优化
在这一章节中,我们将学习如何进行测试以及性能优化。测试是确保代码质量的重要手段之一,而性能优化则是提高程序效率的关键步骤。
1. 单元测试与性能测试
单元测试用于测试程序的各个独立单元(函数、方法、模块等),确保它们的功能正确性。性能测试则用于评估程序的性能表现。
// 单元测试示例
func Add(x, y int) int {
return x + y
}
func TestAdd(t *testing.T) {
result := Add(3, 5)
if result != 8 {
t.Errorf("Add(3, 5) = %d; want 8", result)
}
}
// 性能测试示例
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(3, 5)
}
}
2. 性能优化技巧
性能优化是提高程序效率的关键步骤,常见的性能优化技巧包括使用合适的数据结构、避免不必要的内存分配和拷贝、并发编程等。
// 使用合适的数据结构
var m map[int]string // 不推荐
m := make(map[int]string) // 推荐
// 避免不必要的内存分配和拷贝
var buf bytes.Buffer
for _, item := range items {
buf.WriteString(item)
}
result := buf.String()
// 并发编程
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item string) {
defer wg.Done()
// 处理item
}(item)
}
wg.Wait()
3. 基准测试的使用
基准测试用于评估程序的性能指标,如函数的执行时间、内存占用等。
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(3, 5)
}
}
通过以上学习,你已经了解了如何进行测试以及性能优化。测试是确保代码质量的重要手段之一,它能够帮助我们发现并解决程序中的问题。性能优化则是提高程序效率的关键步骤,通过合理的优化可以提升程序的性能和响应速度。
附录: 实战项目
在这个附录中,我们将介绍三个实战项目示例,分别是构建一个简单的Web应用、使用Go语言编写一个命令行工具以及与数据库交互的示例程序。
1. 构建一个简单的Web应用
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
在命令行中执行go run main.go
,然后打开浏览器访问http://localhost:8080
,即可看到输出Hello, world!
的页面。
2. 使用Go语言编写一个命令行工具
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "world", "name to greet")
flag.Parse()
fmt.Printf("Hello, %s!\n", *name)
}
在命令行中执行go run main.go -name=John
,即可输出Hello, John!
。
3. 与数据库交互的示例程序
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 连接数据库
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
panic(err.Error())
}
defer db.Close()
// 查询数据
rows, err := db.Query("SELECT * FROM users")
if err != nil {
panic(err.Error())
}
defer rows.Close()
// 遍历结果集
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
panic(err.Error())
}
fmt.Println("ID:", id, "Name:", name)
}
}
这是一个与MySQL数据库交互的示例程序,需要将user
、password
和dbname
替换为实际的数据库连接信息。