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

194 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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例如`uuid`module的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]`命令行为如下:
- 如果指定目录存在,会为`dir``go.work`文件中添加一条use指令
- 如果指定目录不存在,会删除`go.work`文件中关于目录的use指令
## Gin框架构建restful api
在构建resultful api时通常都会通过json格式来传递数据首先可定义业务实体
```go
// 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.Context``IndentedJSON`方法来向response中写入数据
```go
// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
```
### 解析request中的数据
可以通过`gin.Context``BindJSON`方法来将请求体中的数据解析到对象中。
```go
// 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
```go
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
### 不使用泛型的代码编写
如果不使用泛型,那么对于不同数值类型的求和,需要编写多个版本的代码,示例如下:
```go
// 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`中执行的所有操作。
```go
// 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为`comparable`go中预先声明了该constraint。comparable约束代表其可以类型可以通过`==``!=`符号来进行比较。
golang中要求key类型为comparable。
上述示例中V的类型约束为`float64 | int64`,`|`符号代表取两种类型的并集,实际类型可以为两种类型中的任何一种。
### 泛型方法调用
```go
// 指定类型参数
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的指定那么传递给方法的任何类型参数都要实现该接口包含该接口中所有的方法。
代码示例如下:
```go
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))
```