Files
rikako-note/Golang/Golang Document.md
2025-01-08 12:40:11 +08:00

6.4 KiB
Raw Blame History

Golang

Get Started

Enable dependency tracking

当代码对其他module中包含的package进行了import时在自己的module中来管理依赖。

自己的module通过go.mod文件来定义,go.mod文件中会track项目所需要的依赖。

go mod init

go mod init <module-name>命令会创建一个go.mod文件,其中<module-name>会是module path。

在实际开发中module name通常是source code被保存的repository location例如uuidmodule的module name为github.com/google/uuid

go mod tidy

go mod tidy命令会根据import添加缺失的module并且移除未使用的module。

multi-module workspace

示例目录结构如下所示:

  • workspace
  • workspace/hello
  • workspace/example/hello

go work init

在本示例中为了创建多module的workspace可以执行go work init ./hello,其会创建go.work文件,并将./hello目录下的module包含到go.work文件中。

go.work内容如下:

go 1.18

use ./hello

go work use

通过go work use ./example/hello命令,会将./example/hello中的module加入到go.work文件中。

go.work内容如下:

go 1.18

use (
    ./hello
    ./example/hello
)

go work use [-r] [dir]命令行为如下:

  • 如果指定目录存在,会为dirgo.work文件中添加一条use指令
  • 如果指定目录不存在,会删除go.work文件中关于目录的use指令

Gin框架构建restful api

在构建resultful api时通常都会通过json格式来传递数据首先可定义业务实体

// album represents data about a record album.
type album struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Artist string  `json:"artist"`
    Price  float64 `json:"price"`
}

向response中写入返回数据

可以通过调用gin.ContextIndentedJSON方法来向response中写入数据

// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
    c.IndentedJSON(http.StatusOK, albums)
}

解析request中的数据

可以通过gin.ContextBindJSON方法来将请求体中的数据解析到对象中。

// postAlbums adds an album from JSON received in the request body.
func postAlbums(c *gin.Context) {
    var newAlbum album

    // Call BindJSON to bind the received JSON to
    // newAlbum.
    if err := c.BindJSON(&newAlbum); err != nil {
        return
    }

    // Add the new album to the slice.
    albums = append(albums, newAlbum)
    c.IndentedJSON(http.StatusCreated, newAlbum)
}

将请求的endpoint注册到server中

可以将各个请求的处理handler注册到server中并在指定端口上运行server

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)
    router.POST("/albums", postAlbums)

    router.Run("localhost:8080")
}

上述示例中,分别向/albums路径注册了GET和POST的处理handler并在localhost:8080上对服务进行监听。

golang generic

不使用泛型的代码编写

如果不使用泛型,那么对于不同数值类型的求和,需要编写多个版本的代码,示例如下:

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}

上述针对int64和float64的版本编写了两个独立的函数

使用泛型的代码编写

对于泛型方法的编写,其相对普通方法多了类型参数,在对泛型方法进行调用时,可以传递类型参数和普通参数。

对于每个parameter type,其都有对应的type constraint。每个type constraint都制定了在调用泛型方法时,可以对parameter type指定哪些类型。

type parameter通常都带代表一系列类型的集合但是在编译时type parameter则是代表由调用方传递的type argument类型。如果type argument类型不满足type constraint的要求那么该代码则不会被成功编译。

type parameter必须要支持generic code中执行的所有操作。

// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

comparable

在上述示例中,K的constraint为comparablego中预先声明了该constraint。comparable约束代表其可以类型可以通过==!=符号来进行比较。

golang中要求key类型为comparable。

上述示例中V的类型约束为float64 | int64,|符号代表取两种类型的并集,实际类型可以为两种类型中的任何一种。

泛型方法调用

// 指定类型参数
fmt.Printf("Generic Sums: %v and %v\n",
    SumIntsOrFloats[string, int64](ints),
    SumIntsOrFloats[string, float64](floats))

// 不指定类型参数
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
    SumIntsOrFloats(ints),
    SumIntsOrFloats(floats))

在调用golang的泛型方法时可以省略类型参数此时编译器会推断类型参数类型但是对于部分场景例如没有参数只有返回值的参数func returnObj[V any]() V,此时泛型类型无法被推断,只能手动指定。

type constraint

在golang中支持将泛型约束声明为接口并在多个地方重用该接口。通过将约束声明为接口可以避免复杂泛型约束的重复声明。

可以将泛型constraint声明为接口并且允许任何类型实现该接口将接口用作type constraint的指定那么传递给方法的任何类型参数都要实现该接口包含该接口中所有的方法。

代码示例如下:

type Number interface {
    int64 | float64
}

// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

fmt.Printf("Generic Sums with Constraint: %v and %v\n",
    SumNumbers(ints),
    SumNumbers(floats))