Go语言进阶学习笔记
一、并发编程
1.Goroutine
Goroutine是Go语言中轻量级的线程实现,可以在程序中创建上千个Goroutine,每个Goroutine都是一个独立的执行单元。通过使用关键字go,可以在函数或方法前面加上go关键字,将其变成一个Goroutine。
例如:
func main() {
go func() {
// do something
}()
// do something else
}
在上面的例子中,匿名函数被创建为一个Goroutine,并在主函数中异步执行。
2.Channel
Channel是Goroutine之间进行通信的重要机制。Channel可以看作是一种特殊的数据类型,可以用来在Goroutine之间传递数据。
创建一个Channel可以使用内置的make函数:
ch := make(chan int)
发送数据到Channel可以使用<-操作符:
ch <- 10
从Channel接收数据可以使用<-操作符:
x := <-ch
如果Channel中没有数据可接收,接收操作将会阻塞,直到有数据可接收为止。同样,如果Channel已满,发送操作将会阻塞,直到有空间可用为止。
3.Select
Select语句用于处理多个Channel的并发操作。它类似于switch语句,但是每个case语句都是一个Channel操作。
例如:
select {
case x := <-ch1:
// do something with x
case y := <-ch2:
// do something with y
default:
// do something else
}
在上面的例子中,select语句会等待ch1和ch2中的数据,如果有数据可接收,就执行相应的case语句。如果所有的Channel都没有数据可接收,就执行default语句。
4.Mutex
Mutex是Go语言中用于实现互斥锁的类型。互斥锁可以用于保护共享资源,防止多个Goroutine同时访问。
使用互斥锁可以通过sync包中的Mutex类型来实现:
var mu sync.Mutex
mu.Lock()
// critical section
mu.Unlock()
在上面的例子中,通过调用Lock方法来获取互斥锁,然后在临界区进行操作,最后调用Unlock方法来释放互斥锁。
二、网络编程
1.TCP
TCP是一种面向连接的协议,它提供可靠的数据传输服务。在Go语言中,可以使用net包来实现TCP网络编程。
创建一个TCP服务器可以使用net包中的Listen函数:
ln, err := net.Listen("tcp", "localhost:8080")
if err != nil {
// handle error
}
defer ln.Close()
在上面的例子中,Listen函数创建了一个TCP监听器,监听本地主机的8080端口。
接受客户端连接可以使用Accept方法:
conn, err := ln.Accept()
if err != nil {
// handle error
}
defer conn.Close()
在上面的例子中,Accept方法会阻塞,直到有客户端连接到达。
2.UDP
UDP是一种无连接的协议,它提供不可靠的数据传输服务。在Go语言中,可以使用net包来实现UDP网络编程。
创建一个UDP连接可以使用net包中的Dial函数:
conn, err := net.Dial("udp", "localhost:8080")
if err != nil {
// handle error
}
defer conn.Close()
在上面的例子中,Dial函数创建了一个UDP连接,连接到本地主机的8080端口。
发送数据可以使用Write方法:
_, err := conn.Write([]byte("Hello, UDP!"))
if err != nil {
// handle error
}
在上面的例子中,Write方法会将数据发送给UDP服务器。
3.HTTP
HTTP是一种基于TCP的协议,它用于在Web浏览器和Web服务器之间传输数据。在Go语言中,可以使用net/http包来实现HTTP网络编程。
创建一个HTTP服务器可以使用http包中的ListenAndServe函数:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, HTTP!")
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
// handle error
}
在上面的例子中,HandleFunc函数将一个处理函数注册到默认的ServeMux中,然后调用ListenAndServe函数来启动HTTP服务器。
发送HTTP请求可以使用http包中的Get函数:
resp, err := http.Get("http://localhost:8080")
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// handle error
}
fmt.Println(string(body))
在上面的例子中,Get函数发送一个GET请求到指定的URL,然后读取响应的内容。
三、数据库编程
1.MySQL
在Go语言中,可以使用第三方的MySQL驱动来实现MySQL数据库的操作。
首先,需要使用go get命令来安装MySQL驱动:
go get github.com/go-sql-driver/mysql
然后,可以使用database/sql包来连接和操作MySQL数据库:
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
if err != nil {
// handle error
}
defer db.Close()
在上面的例子中,Open函数用于连接MySQL数据库,参数是一个DSN(Data Source Name)字符串。
执行SQL查询可以使用Query方法:
rows, err := db.Query("SELECT * FROM table")
if err != nil {
// handle error
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
// handle error
}
// do something with id and name
}
err = rows.Err()
if err != nil {
// handle error
}
在上面的例子中,Query方法执行一个SQL查询,并返回一个Rows结果集。然后,可以使用Scan方法来获取每一行的数据。
2.MongoDB
在Go语言中,可以使用第三方的MongoDB驱动来实现MongoDB数据库的操作。
首先,需要使用go get命令来安装MongoDB驱动:
go get go.mongodb.org/mongo-driver/mongo
然后,可以使用mongo包来连接和操作MongoDB数据库:
import (
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
// handle error
}
defer client.Disconnect(context.TODO())
collection := client.Database("database").Collection("collection")
cursor, err := collection.Find(context.TODO(), bson.M{})
if err != nil {
// handle error
}
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) {
var result bson.M
err := cursor.Decode(&result)
if err != nil {
// handle error
}
// do something with result
}
if err := cursor.Err(); err != nil {
// handle error
}
在上面的例子中,Connect函数用于连接MongoDB数据库,参数是一个URI字符串。
执行查询可以使用Find方法:
cursor, err := collection.Find(context.TODO(), bson.M{"name": "John"})
if err != nil {
// handle error
}
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) {
var result bson.M
err := cursor.Decode(&result)
if err != nil {
// handle error
}
// do something with result
}
if err := cursor.Err(); err != nil {
// handle error
}
在上面的例子中,Find方法执行一个查询,并返回一个Cursor游标。然后,可以使用Decode方法来获取每一行的数据。
四、Web编程
1.HTTP服务器
Go语言内置了一个简单但功能强大的HTTP服务器,可以使用net/http
包来创建和运行HTTP服务器。下面是一个基本的HTTP服务器示例代码:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
// 处理错误
}
}
在上面的代码中,我们使用http.HandleFunc
函数将一个处理函数注册到默认的ServeMux中,然后调用http.ListenAndServe
函数来启动HTTP服务器。当有请求到达时,处理函数会被调用,并向客户端返回"Hello, World!"。
2.路由和处理函数
在Web应用程序中,路由用于将请求映射到相应的处理函数。Go语言的net/http
包提供了http.HandleFunc
和http.HandlerFunc
函数来注册路由和处理函数。
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/about", aboutHandler)
err := http.ListenAndServe(":8080", nil)
if err != nil {
// 处理错误
}
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "This is the about page!")
}
在上面的代码中,我们使用http.HandleFunc
函数将homeHandler
函数注册到根路由"/",将aboutHandler
函数注册到"/about"路由。
3.处理静态文件
在Web应用程序中,通常需要处理静态文件,如HTML、CSS、JavaScript、图像等。Go语言的net/http
包提供了http.FileServer
函数来处理静态文件。
package main
import (
"net/http"
)
func main() {
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
err := http.ListenAndServe(":8080", nil)
if err != nil {
// 处理错误
}
}
在上面的代码中,我们使用http.FileServer
函数创建一个文件服务器,并将其注册到"/static/"路由。然后,我们使用http.StripPrefix
函数将路由前缀"/static/"去除,以便正确地处理静态文件。
4.模板引擎
在Web应用程序中,模板引擎用于生成动态的HTML页面。Go语言的html/template
包提供了一个简单而强大的模板引擎。
package main
import (
"html/template"
"net/http"
)
type Person struct {
Name string
Age int
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("template.html"))
person := Person{Name: "Alice", Age: 25}
err := tmpl.Execute(w, person)
if err != nil {
// 处理错误
}
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
// 处理错误
}
}
在上面的代码中,我们首先定义了一个Person
结构体,然后使用template.ParseFiles
函数解析模板文件。接下来,我们创建一个Person
对象,并使用tmpl.Execute
方法将数据填充到模板中,并将结果写入ResponseWriter
中。
5.数据库操作
在Web应用程序中,经常需要与数据库进行交互。Go语言提供了多个第三方库来操作各种类型的数据库,如MySQL、MongoDB、PostgreSQL等。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
if err != nil {
// 处理错误
}
defer db.Close()
rows, err := db.Query("SELECT * FROM table")
if err != nil {
// 处理错误
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
// 处理错误
}
// 处理数据
}
err = rows.Err()
if err != nil {
// 处理错误
}
}
在上面的代码中,我们首先使用sql.Open
函数连接MySQL数据库,然后使用db.Query
方法执行一个查询,并返回一个Rows
结果集。然后,我们可以使用rows.Scan
方法来获取每一行的数据。