Go语言进阶学习笔记 | 青训营

33 阅读7分钟

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.HandleFunchttp.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方法来获取每一行的数据。