docs: 优化项目文档

This commit is contained in:
kercylan 2024-01-14 13:49:52 +08:00
parent ea1ed6cc20
commit 83beeb43ce
85 changed files with 10959 additions and 266 deletions

View File

@ -187,46 +187,6 @@ func main() {
```
在分布式环境中,如果存在类似于多服务器需要同时间刷新配置时,可使用`Cron`表达式设置定时任务。
### 流操作
可以通过 `stream` 包快速开启对`切片`和`map`的流式操作,例如:
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/utils/stream"
"github.com/kercylan98/minotaur/utils/streams"
)
func main() {
s := stream.WithSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).
Copy().
Shuffle().
Filter(true, func(index int, item int) bool {
return item%2 == 0
}).
Zoom(20).
Each(true, func(index int, item int) bool {
t.Log(index, item)
return false
}).
Chunk(3).
EachT(func(index int, item stream.Slice[int]) bool {
t.Log(item)
return false
}).
Merge().
FillBy(func(index int, value int) int {
if value == 0 {
return 999
}
return value
})
fmt.Println(s)
}
```
### 基于`xlsx`文件的配置导出工具
该导出器的`xlsx`文件配置使用`JSON`语法进行复杂类型配置,具体可参考图例
- **[`planner/pce/exporter`](planner/pce/exporter)** 是实现了基于`xlsx`文件的配置导出工具,可直接编译成可执行文件使用;

77
configuration/README.md Normal file
View File

@ -0,0 +1,77 @@
# Configuration
configuration 基于配置导表功能实现的配置加载及刷新功能
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/configuration)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Init](#Init)|配置初始化
|[Load](#Load)|加载配置
|[Refresh](#Refresh)|刷新配置
|[WithTickerLoad](#WithTickerLoad)|通过定时器加载配置
|[StopTickerLoad](#StopTickerLoad)|停止通过定时器加载配置
|[RegConfigRefreshEvent](#RegConfigRefreshEvent)|当配置刷新时将立即执行被注册的事件处理函数
|[OnConfigRefreshEvent](#OnConfigRefreshEvent)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[RefreshEventHandle](#refresheventhandle)|配置刷新事件处理函数
|[Loader](#loader)|配置加载器
</details>
#### func Init(loader ...Loader)
<span id="Init"></span>
> 配置初始化
> - 在初始化后会立即加载配置
***
#### func Load()
<span id="Load"></span>
> 加载配置
> - 加载后并不会刷新线上配置,需要执行 Refresh 函数对线上配置进行刷新
***
#### func Refresh()
<span id="Refresh"></span>
> 刷新配置
***
#### func WithTickerLoad(ticker *timer.Ticker, interval time.Duration)
<span id="WithTickerLoad"></span>
> 通过定时器加载配置
> - 通过定时器加载配置后,会自动刷新线上配置
> - 调用该函数后不会立即刷新,而是在 interval 后加载并刷新一次配置,之后每隔 interval 加载并刷新一次配置
***
#### func StopTickerLoad()
<span id="StopTickerLoad"></span>
> 停止通过定时器加载配置
***
#### func RegConfigRefreshEvent(handle RefreshEventHandle)
<span id="RegConfigRefreshEvent"></span>
> 当配置刷新时将立即执行被注册的事件处理函数
***
#### func OnConfigRefreshEvent()
<span id="OnConfigRefreshEvent"></span>
***
### RefreshEventHandle
配置刷新事件处理函数
```go
type RefreshEventHandle struct{}
```
### Loader
配置加载器
```go
type Loader struct{}
```

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -1,38 +1,27 @@
# Game
game 目录下包含了各类通用的游戏玩法性内容,其中该目录主要为基础性内容,具体目录将对应不同的游戏功能性内容。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/game)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
Game 包提供了游戏领域中常见的功能实现,例如活动、任务、战斗、房间等实现。
开发者可以使用它来快速构建游戏中的常见功能,例如游戏活动、任务系统、多人房间等。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 目前还在考虑逐步将该包移除,未来项目结构可能会进行调整
## package activity [`活动`](./activity)
提供了通用的活动设计,开发者可以使用它来设计和实现游戏中的活动机制。活动是游戏中重要的激励和玩法设计元素,它可以是一次性的,也可以是周期性的。活动系统框架将包括活动的创建、开启、关闭、奖励等功能,开发者可以根据游戏类型和风格,定制不同类型的活动,并设定相应的奖励机制,以增加游戏的可玩性和挑战性。
> 包级函数定义
活动整体的配置将通过可选项的方式进行配置。
|函数|描述
|:--|:--
> 在 `activity` 包中提供了以下 6 种事件:
> - 即将开始的活动事件
> - 活动开始事件
> - 活动结束事件
> - 活动结束后延长展示开始事件
> - 活动结束后延长展示结束事件
> - 新的一天事件
## package fight [`战斗`](./fight)
`fight` 中目前仅提供了回合制[`TurnBased`](./fight/turn_based.go)的实现。
- [`TurnBased`](./fight/turn_based.go) 仅提供了回合制的基本实现,开发者可以根据自己的需求进行扩展。其中包括:回合切换、回合开始、回合结束、回合超时、根据速度调节下次行动间隔。
> 结构体定义
## package space [`空间`](./space)
计划提供游戏中常见的空间设计,例如房间、地图等。开发者可以使用它来快速构建游戏中的常见空间,例如多人房间、地图等。
> 目前仅提供了房间的基本实现
|结构体|描述
|:--|:--
- [`Room`](./space/room_manager.go) 提供了房间的基本实现,开发者可以根据自己的需求进行扩展。
- 房间通过 [`RoomManager`](./space/room_manager.go) 进行管理,由 [`RoomController`](./space/room_controller.go) 进行控制;
- 实现了加入、退出、事件、查询、销毁、座位、带顺序座位号、密码、人数上限等常用的基础功能。
</details>
## package task [`任务`](./task)
提供了通用的任务设计,开发者可以使用它来设计和实现游戏中的任务机制。任务是游戏中重要的激励和玩法设计元素,它可以是一次性的,也可以是周期性的。任务系统框架将包括任务的创建、开启、关闭、奖励等功能,开发者可以根据游戏类型和风格,定制不同类型的任务,并设定相应的奖励机制,以增加游戏的可玩性和挑战性。
> 该包仅实现了任务基本状态的管理,例如任务类型、分配、事件、状态变化等,开发者可以根据自己的需求进行扩展。

View File

@ -1,12 +1,249 @@
# Activity
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/game/activity)
activity 活动状态管理
`activity` 是为不同类型的活动提供灵活的状态管理实现,支持活动的预告、开始、结束、延长展示等状态。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/activity)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 设计思路
- 为不同类型的活动提供灵活的状态管理框架,支持活动的预告、开始、结束、延长展示等状态。
- 支持事件驱动,根据活动状态变化和时间触发事件。
- 允许活动循环,并支持配置延长展示时间。
- 在多线程环境下使用互斥锁进行同步。
- 使用反射处理不同类型的活动数据。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[SetTicker](#SetTicker)|设置自定义定时器,该方法必须在使用活动系统前调用,且只能调用一次
|[LoadGlobalData](#LoadGlobalData)|加载所有活动全局数据
|[LoadEntityData](#LoadEntityData)|加载所有活动实体数据
|[LoadOrRefreshActivity](#LoadOrRefreshActivity)|加载或刷新活动
|[DefineNoneDataActivity](#DefineNoneDataActivity)|声明无数据的活动类型
|[DefineGlobalDataActivity](#DefineGlobalDataActivity)|声明拥有全局数据的活动类型
|[DefineEntityDataActivity](#DefineEntityDataActivity)|声明拥有实体数据的活动类型
|[DefineGlobalAndEntityDataActivity](#DefineGlobalAndEntityDataActivity)|声明拥有全局数据和实体数据的活动类型
|[RegUpcomingEvent](#RegUpcomingEvent)|注册即将开始的活动事件处理器
|[OnUpcomingEvent](#OnUpcomingEvent)|即将开始的活动事件
|[RegStartedEvent](#RegStartedEvent)|注册活动开始事件处理器
|[OnStartedEvent](#OnStartedEvent)|活动开始事件
|[RegEndedEvent](#RegEndedEvent)|注册活动结束事件处理器
|[OnEndedEvent](#OnEndedEvent)|活动结束事件
|[RegExtendedShowStartedEvent](#RegExtendedShowStartedEvent)|注册活动结束后延长展示开始事件处理器
|[OnExtendedShowStartedEvent](#OnExtendedShowStartedEvent)|活动结束后延长展示开始事件
|[RegExtendedShowEndedEvent](#RegExtendedShowEndedEvent)|注册活动结束后延长展示结束事件处理器
|[OnExtendedShowEndedEvent](#OnExtendedShowEndedEvent)|活动结束后延长展示结束事件
|[RegNewDayEvent](#RegNewDayEvent)|注册新的一天事件处理器
|[OnNewDayEvent](#OnNewDayEvent)|新的一天事件
|[NewOptions](#NewOptions)|创建活动选项
> 结构体定义
|结构体|描述
|:--|:--
|[Activity](#activity)|活动描述
|[Controller](#controller)|活动控制器
|[BasicActivityController](#basicactivitycontroller)|暂无描述...
|[NoneDataActivityController](#nonedataactivitycontroller)|无数据活动控制器
|[GlobalDataActivityController](#globaldataactivitycontroller)|全局数据活动控制器
|[EntityDataActivityController](#entitydataactivitycontroller)|实体数据活动控制器
|[GlobalAndEntityDataActivityController](#globalandentitydataactivitycontroller)|全局数据和实体数据活动控制器
|[DataMeta](#datameta)|全局活动数据
|[EntityDataMeta](#entitydatameta)|活动实体数据
|[UpcomingEventHandler](#upcomingeventhandler)|暂无描述...
|[Options](#options)|活动选项
</details>
#### func SetTicker(size int, options ...timer.Option)
<span id="SetTicker"></span>
> 设置自定义定时器,该方法必须在使用活动系统前调用,且只能调用一次
***
#### func LoadGlobalData(handler func (activityType any))
<span id="LoadGlobalData"></span>
> 加载所有活动全局数据
***
#### func LoadEntityData(handler func (activityType any))
<span id="LoadEntityData"></span>
> 加载所有活动实体数据
***
#### func LoadOrRefreshActivity(activityType Type, activityId ID, options ...*Options) error
<span id="LoadOrRefreshActivity"></span>
> 加载或刷新活动
> - 通常在活动配置刷新时候将活动通过该方法注册或刷新
***
#### func DefineNoneDataActivity(activityType Type) NoneDataActivityController[Type, ID, *none, none, *none]
<span id="DefineNoneDataActivity"></span>
> 声明无数据的活动类型
***
#### func DefineGlobalDataActivity(activityType Type) GlobalDataActivityController[Type, ID, Data, none, *none]
<span id="DefineGlobalDataActivity"></span>
> 声明拥有全局数据的活动类型
***
#### func DefineEntityDataActivity(activityType Type) EntityDataActivityController[Type, ID, *none, EntityID, EntityData]
<span id="DefineEntityDataActivity"></span>
> 声明拥有实体数据的活动类型
***
#### func DefineGlobalAndEntityDataActivity(activityType Type) GlobalAndEntityDataActivityController[Type, ID, Data, EntityID, EntityData]
<span id="DefineGlobalAndEntityDataActivity"></span>
> 声明拥有全局数据和实体数据的活动类型
***
#### func RegUpcomingEvent(activityType Type, handler UpcomingEventHandler[ID], priority ...int)
<span id="RegUpcomingEvent"></span>
> 注册即将开始的活动事件处理器
***
#### func OnUpcomingEvent(activity *Activity[Type, ID])
<span id="OnUpcomingEvent"></span>
> 即将开始的活动事件
***
#### func RegStartedEvent(activityType Type, handler StartedEventHandler[ID], priority ...int)
<span id="RegStartedEvent"></span>
> 注册活动开始事件处理器
***
#### func OnStartedEvent(activity *Activity[Type, ID])
<span id="OnStartedEvent"></span>
> 活动开始事件
***
#### func RegEndedEvent(activityType Type, handler EndedEventHandler[ID], priority ...int)
<span id="RegEndedEvent"></span>
> 注册活动结束事件处理器
***
#### func OnEndedEvent(activity *Activity[Type, ID])
<span id="OnEndedEvent"></span>
> 活动结束事件
***
#### func RegExtendedShowStartedEvent(activityType Type, handler ExtendedShowStartedEventHandler[ID], priority ...int)
<span id="RegExtendedShowStartedEvent"></span>
> 注册活动结束后延长展示开始事件处理器
***
#### func OnExtendedShowStartedEvent(activity *Activity[Type, ID])
<span id="OnExtendedShowStartedEvent"></span>
> 活动结束后延长展示开始事件
***
#### func RegExtendedShowEndedEvent(activityType Type, handler ExtendedShowEndedEventHandler[ID], priority ...int)
<span id="RegExtendedShowEndedEvent"></span>
> 注册活动结束后延长展示结束事件处理器
***
#### func OnExtendedShowEndedEvent(activity *Activity[Type, ID])
<span id="OnExtendedShowEndedEvent"></span>
> 活动结束后延长展示结束事件
***
#### func RegNewDayEvent(activityType Type, handler NewDayEventHandler[ID], priority ...int)
<span id="RegNewDayEvent"></span>
> 注册新的一天事件处理器
***
#### func OnNewDayEvent(activity *Activity[Type, ID])
<span id="OnNewDayEvent"></span>
> 新的一天事件
***
#### func NewOptions() *Options
<span id="NewOptions"></span>
> 创建活动选项
***
### Activity
活动描述
```go
type Activity[Type generic.Basic, ID generic.Basic] struct {
id ID
t Type
options *Options
state byte
lazy bool
tickerKey string
retention time.Duration
retentionKey string
mutex sync.RWMutex
getLastNewDayTime func() time.Time
setLastNewDayTime func(time.Time)
clearData func()
initializeData func()
}
```
### Controller
活动控制器
```go
type Controller[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct {
t Type
activities map[ID]*Activity[Type, ID]
globalData map[ID]*DataMeta[Data]
entityData map[ID]map[EntityID]*EntityDataMeta[EntityData]
entityTof reflect.Type
globalInit func(activityId ID, data *DataMeta[Data])
entityInit func(activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])
mutex sync.RWMutex
}
```
### BasicActivityController
```go
type BasicActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct{}
```
### NoneDataActivityController
无数据活动控制器
```go
type NoneDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct{}
```
### GlobalDataActivityController
全局数据活动控制器
```go
type GlobalDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct{}
```
### EntityDataActivityController
实体数据活动控制器
```go
type EntityDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct{}
```
### GlobalAndEntityDataActivityController
全局数据和实体数据活动控制器
```go
type GlobalAndEntityDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct{}
```
### DataMeta
全局活动数据
```go
type DataMeta[Data any] struct {
once sync.Once
Data Data
LastNewDay time.Time
}
```
### EntityDataMeta
活动实体数据
```go
type EntityDataMeta[Data any] struct {
once sync.Once
Data Data
LastNewDay time.Time
}
```
### UpcomingEventHandler
```go
type UpcomingEventHandler[ID generic.Basic] struct{}
```
### Options
活动选项
```go
type Options struct {
Tl *times.StateLine[byte]
Loop time.Duration
}
```
#### func (*Options) WithUpcomingTime(t time.Time) *Options
> 设置活动预告时间
***
#### func (*Options) WithStartTime(t time.Time) *Options
> 设置活动开始时间
***
#### func (*Options) WithEndTime(t time.Time) *Options
> 设置活动结束时间
***
#### func (*Options) WithExtendedShowTime(t time.Time) *Options
> 设置延长展示时间
***
#### func (*Options) WithLoop(interval time.Duration) *Options
> 设置活动循环,时间间隔小于等于 0 表示不循环
> - 当活动状态展示结束后,会根据该选项设置的时间间隔重新开始
***

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Activities
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/activities)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,27 @@
# Demoactivity
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/demoactivity)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,35 @@
# Types
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/types)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
|[DemoActivityData](#demoactivitydata)|暂无描述...
</details>
### DemoActivityData
```go
type DemoActivityData struct {
LoginNum int
}
```

View File

@ -1,18 +1,84 @@
# Fight
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight)
## TurnBased [`回合制`]((https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased))
### 设计思路
- 在每个回合中计算下一次行动时间间隔。然后,会根据当前行动时间间隔选择下一个行动实体。
- 当选择到下一个行动实体后,进入行动阶段。在行动阶段中,会先触发 [`TurnBasedEntitySwitchEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntitySwitchEvent) 事件,然后开始计时。
- 当计时结束时,如果实体还未完成行动,则会触发 [`TurnBasedEntityActionTimeoutEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionTimeoutEvent) 事件。如果实体已经完成行动,则会触发 [`TurnBasedEntityActionFinishEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionFinishEvent) 事件。
- 当实体完成行动后,会触发 [`TurnBasedEntityActionSubmitEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionSubmitEvent) 事件。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/fight)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
回合制功能的设计思路主要考虑了以下几个方面:
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
* 灵活性:`TurnBased` 类型提供了丰富的属性和方法,可以满足不同游戏的需要。
* 可扩展性:`TurnBased` 类型还提供了 `AddCamp`、`GetCamp`、`SetActionTimeout` 等方法,可以根据需要扩展回合制功能。
* 事件驱动:回合制功能使用事件驱动的方式来通知回合制状态变化。
> 包级函数定义
|函数|描述
|:--|:--
|[NewTurnBased](#NewTurnBased)|创建一个新的回合制
> 结构体定义
|结构体|描述
|:--|:--
|[TurnBased](#turnbased)|回合制
|[TurnBasedControllerInfo](#turnbasedcontrollerinfo)|暂无描述...
|[TurnBasedControllerAction](#turnbasedcontrolleraction)|暂无描述...
|[TurnBasedController](#turnbasedcontroller)|回合制控制器
|[TurnBasedEntitySwitchEventHandler](#turnbasedentityswitcheventhandler)|暂无描述...
</details>
#### func NewTurnBased(calcNextTurnDuration func ( Camp, Entity) time.Duration) *TurnBased[CampID, EntityID, Camp, Entity]
<span id="NewTurnBased"></span>
> 创建一个新的回合制
> - calcNextTurnDuration 将返回下一次行动时间间隔,适用于按照速度计算下一次行动时间间隔的情况。当返回 0 时,将使用默认的行动超时时间
***
### TurnBased
回合制
```go
type TurnBased[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct {
*turnBasedEvents[CampID, EntityID, Camp, Entity]
controller *TurnBasedController[CampID, EntityID, Camp, Entity]
ticker *time.Ticker
actionWaitTicker *time.Ticker
actioning bool
actionMutex sync.RWMutex
entities []Entity
campRel map[EntityID]Camp
calcNextTurnDuration func(Camp, Entity) time.Duration
actionTimeoutHandler func(Camp, Entity) time.Duration
signal chan signal
round int
currCamp Camp
currEntity Entity
currActionTimeout time.Duration
currStart time.Time
closeMutex sync.RWMutex
closed bool
}
```
### TurnBasedControllerInfo
```go
type TurnBasedControllerInfo[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct{}
```
### TurnBasedControllerAction
```go
type TurnBasedControllerAction[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct{}
```
### TurnBasedController
回合制控制器
```go
type TurnBasedController[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct {
tb *TurnBased[CampID, EntityID, Camp, Entity]
}
```
### TurnBasedEntitySwitchEventHandler
```go
type TurnBasedEntitySwitchEventHandler[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct{}
```

View File

@ -1,54 +1,80 @@
# Space
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space)
space 游戏中常见的空间设计,例如房间、地图等
计划提供游戏中常见的空间设计,例如房间、地图等。开发者可以使用它来快速构建游戏中的常见空间,例如多人房间、地图等。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/space)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## Room [`房间`]((https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager))
房间在 `Minotaur` 中仅仅只是一个可以为任意可比较类型的 `ID`,当需要将现有或新设计的房间纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,需要实现 [`Room`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,仅需要实现 [`generic.IdR`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/generic#IdR) 接口即可。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
该功能由
[`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager)、
[`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)
组成。
当创建一个新的房间并纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理后,将会得到一个 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)。通过 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController) 可以对房间进行管理,例如:获取房间信息、加入房间、退出房间等。
> 包级函数定义
### 使用示例
|函数|描述
|:--|:--
|[NewRoomManager](#NewRoomManager)|创建房间管理器 RoomManager 的实例
|[NewRoomControllerOptions](#NewRoomControllerOptions)|创建房间控制器选项
> 结构体定义
|结构体|描述
|:--|:--
|[RoomController](#roomcontroller)|对房间进行操作的控制器,由 RoomManager 接管后返回
|[RoomManager](#roommanager)|房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
|[RoomAssumeControlEventHandle](#roomassumecontroleventhandle)|暂无描述...
|[RoomControllerOptions](#roomcontrolleroptions)|暂无描述...
</details>
#### func NewRoomManager() *RoomManager[EntityID, RoomID, Entity, Room]
<span id="NewRoomManager"></span>
> 创建房间管理器 RoomManager 的实例
***
#### func NewRoomControllerOptions() *RoomControllerOptions[EntityID, RoomID, Entity, Room]
<span id="NewRoomControllerOptions"></span>
> 创建房间控制器选项
***
### RoomController
对房间进行操作的控制器,由 RoomManager 接管后返回
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/game/space"
)
type Room struct {
Id int64
type RoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
manager *RoomManager[EntityID, RoomID, Entity, Room]
options *RoomControllerOptions[EntityID, RoomID, Entity, Room]
room Room
entities map[EntityID]Entity
entitiesRWMutex sync.RWMutex
vacancy []int
seat []*EntityID
owner *EntityID
}
func (r *Room) GetId() int64 {
return r.Id
```
### RoomManager
房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
- 该实例是线程安全的
```go
type RoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
*roomManagerEvents[EntityID, RoomID, Entity, Room]
roomsRWMutex sync.RWMutex
rooms map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
}
```
### RoomAssumeControlEventHandle
type Player struct {
Id string
```go
type RoomAssumeControlEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct{}
```
### RoomControllerOptions
```go
type RoomControllerOptions[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
maxEntityCount *int
password *string
ownerInherit bool
ownerInheritHandler func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID
}
func (p *Player) GetId() string {
return p.Id
}
func main() {
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
var room = &Room{Id: 1}
var controller = rm.AssumeControl(room)
if err := controller.AddEntity(&Player{Id: "1"}); err != nil {
// 房间密码不匹配或者房间已满
panic(err)
}
fmt.Println(controller.GetEntityCount()) // 1
}
```
```

233
game/task/README.md Normal file
View File

@ -0,0 +1,233 @@
# Task
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/task)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Cond](#Cond)|创建任务条件
|[RegisterRefreshTaskCounterEvent](#RegisterRefreshTaskCounterEvent)|注册特定任务类型的刷新任务计数器事件处理函数
|[OnRefreshTaskCounterEvent](#OnRefreshTaskCounterEvent)|触发特定任务类型的刷新任务计数器事件
|[RegisterRefreshTaskConditionEvent](#RegisterRefreshTaskConditionEvent)|注册特定任务类型的刷新任务条件事件处理函数
|[OnRefreshTaskConditionEvent](#OnRefreshTaskConditionEvent)|触发特定任务类型的刷新任务条件事件
|[WithType](#WithType)|设置任务类型
|[WithCondition](#WithCondition)|设置任务完成条件,当满足条件时,任务状态为完成
|[WithCounter](#WithCounter)|设置任务计数器,当计数器达到要求时,任务状态为完成
|[WithOverflowCounter](#WithOverflowCounter)|设置可溢出的任务计数器,当计数器达到要求时,任务状态为完成
|[WithDeadline](#WithDeadline)|设置任务截止时间,超过截至时间并且任务未完成时,任务状态为失败
|[WithLimitedDuration](#WithLimitedDuration)|设置任务限时,超过限时时间并且任务未完成时,任务状态为失败
|[NewTask](#NewTask)|生成任务
> 结构体定义
|结构体|描述
|:--|:--
|[Condition](#condition)|任务条件
|[RefreshTaskCounterEventHandler](#refreshtaskcountereventhandler)|暂无描述...
|[Option](#option)|任务选项
|[Status](#status)|暂无描述...
|[Task](#task)|是对任务信息进行描述和处理的结构体
</details>
#### func Cond(k any, v any) Condition
<span id="Cond"></span>
> 创建任务条件
***
#### func RegisterRefreshTaskCounterEvent(taskType string, handler RefreshTaskCounterEventHandler[Trigger])
<span id="RegisterRefreshTaskCounterEvent"></span>
> 注册特定任务类型的刷新任务计数器事件处理函数
***
#### func OnRefreshTaskCounterEvent(taskType string, trigger any, count int64)
<span id="OnRefreshTaskCounterEvent"></span>
> 触发特定任务类型的刷新任务计数器事件
***
#### func RegisterRefreshTaskConditionEvent(taskType string, handler RefreshTaskConditionEventHandler[Trigger])
<span id="RegisterRefreshTaskConditionEvent"></span>
> 注册特定任务类型的刷新任务条件事件处理函数
***
#### func OnRefreshTaskConditionEvent(taskType string, trigger any, condition Condition)
<span id="OnRefreshTaskConditionEvent"></span>
> 触发特定任务类型的刷新任务条件事件
***
#### func WithType(taskType string) Option
<span id="WithType"></span>
> 设置任务类型
***
#### func WithCondition(condition Condition) Option
<span id="WithCondition"></span>
> 设置任务完成条件,当满足条件时,任务状态为完成
> - 任务条件值需要变更时可通过 Task.AssignConditionValueAndRefresh 方法变更
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
***
#### func WithCounter(counter int64, initCount ...int64) Option
<span id="WithCounter"></span>
> 设置任务计数器,当计数器达到要求时,任务状态为完成
> - 一些场景下,任务计数器可能会溢出,此时可通过 WithOverflowCounter 设置可溢出的任务计数器
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
> - 如果需要初始化计数器的值,可通过 initCount 参数设置
***
#### func WithOverflowCounter(counter int64, initCount ...int64) Option
<span id="WithOverflowCounter"></span>
> 设置可溢出的任务计数器,当计数器达到要求时,任务状态为完成
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
> - 如果需要初始化计数器的值,可通过 initCount 参数设置
***
#### func WithDeadline(deadline time.Time) Option
<span id="WithDeadline"></span>
> 设置任务截止时间,超过截至时间并且任务未完成时,任务状态为失败
***
#### func WithLimitedDuration(start time.Time, duration time.Duration) Option
<span id="WithLimitedDuration"></span>
> 设置任务限时,超过限时时间并且任务未完成时,任务状态为失败
***
#### func NewTask(options ...Option) *Task
<span id="NewTask"></span>
> 生成任务
***
### Condition
任务条件
```go
type Condition struct{}
```
#### func (Condition) Cond(k any, v any) Condition
> 创建任务条件
***
#### func (Condition) GetString(key any) string
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetInt(key any) int
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetInt8(key any) int8
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetInt16(key any) int16
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetInt32(key any) int32
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetInt64(key any) int64
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetUint(key any) uint
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetUint8(key any) uint8
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetUint16(key any) uint16
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetUint32(key any) uint32
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetUint64(key any) uint64
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetFloat32(key any) float32
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetFloat64(key any) float64
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetBool(key any) bool
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetTime(key any) time.Time
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetDuration(key any) time.Duration
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetByte(key any) byte
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetBytes(key any) []byte
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetRune(key any) rune
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetRunes(key any) []rune
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
#### func (Condition) GetAny(key any) any
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
***
### RefreshTaskCounterEventHandler
```go
type RefreshTaskCounterEventHandler[Trigger any] struct{}
```
### Option
任务选项
```go
type Option struct{}
```
### Status
```go
type Status struct{}
```
#### func (Status) String() string
***
### Task
是对任务信息进行描述和处理的结构体
```go
type Task struct {
Type string
Status Status
Cond Condition
CondValue map[any]any
Counter int64
CurrCount int64
CurrOverflow bool
Deadline time.Time
StartTime time.Time
LimitedDuration time.Duration
}
```
#### func (*Task) IsComplete() bool
> 判断任务是否已完成
***
#### func (*Task) IsFailed() bool
> 判断任务是否已失败
***
#### func (*Task) IsReward() bool
> 判断任务是否已领取奖励
***
#### func (*Task) ReceiveReward() bool
> 领取任务奖励,当任务状态为已完成时,才能领取奖励,此时返回 true并且任务状态变更为已领取奖励
***
#### func (*Task) IncrementCounter(incr int64) *Task
> 增加计数器的值,当 incr 为负数时,计数器的值不会发生变化
> - 如果需要溢出计数器,可通过 WithOverflowCounter 设置可溢出的任务计数器
***
#### func (*Task) DecrementCounter(decr int64) *Task
> 减少计数器的值,当 decr 为负数时,计数器的值不会发生变化
***
#### func (*Task) AssignConditionValueAndRefresh(key any, value any) *Task
> 分配条件值并刷新任务状态
***
#### func (*Task) AssignConditionValueAndRefreshByCondition(condition Condition) *Task
> 分配条件值并刷新任务状态
***
#### func (*Task) ResetStatus() *Task
> 重置任务状态
> - 该函数会将任务状态重置为已接受状态后,再刷新任务状态
> - 当任务条件变更,例如任务计数要求为 10已经完成的情况下将任务计数要求变更为 5 或 20此时任务状态由于是已完成或已领取状态不会自动刷新需要调用该函数刷新任务状态
***

60
notify/README.md Normal file
View File

@ -0,0 +1,60 @@
# Notify
notify 包含了对外部第三方通知的实现,如机器人消息等
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/notify)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewManager](#NewManager)|通过指定的 Sender 创建一个通知管理器, senders 包中提供了一些内置的 Sender
> 结构体定义
|结构体|描述
|:--|:--
|[Manager](#manager)|通知管理器,可用于将通知同时发送至多个渠道
|[Notify](#notify)|通用通知接口定义
|[Sender](#sender)|通知发送器接口声明
</details>
#### func NewManager(senders ...Sender) *Manager
<span id="NewManager"></span>
> 通过指定的 Sender 创建一个通知管理器, senders 包中提供了一些内置的 Sender
***
### Manager
通知管理器,可用于将通知同时发送至多个渠道
```go
type Manager struct {
senders []Sender
notifyChannel chan Notify
closeChannel chan struct{}
}
```
#### func (*Manager) PushNotify(notify Notify)
> 推送通知
***
#### func (*Manager) Release()
> 释放通知管理器
***
### Notify
通用通知接口定义
```go
type Notify struct{}
```
### Sender
通知发送器接口声明
```go
type Sender struct{}
```

210
notify/notifies/README.md Normal file
View File

@ -0,0 +1,210 @@
# Notifies
notifies 包含了内置通知内容的实现
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/notifies)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewFeiShu](#NewFeiShu)|创建飞书通知消息
|[FeiShuMessageWithText](#FeiShuMessageWithText)|飞书文本消息
|[FeiShuMessageWithRichText](#FeiShuMessageWithRichText)|飞书富文本消息
|[FeiShuMessageWithImage](#FeiShuMessageWithImage)|飞书图片消息
|[FeiShuMessageWithInteractive](#FeiShuMessageWithInteractive)|飞书卡片消息
|[FeiShuMessageWithShareChat](#FeiShuMessageWithShareChat)|飞书分享群名片
|[FeiShuMessageWithShareUser](#FeiShuMessageWithShareUser)|飞书分享个人名片
|[FeiShuMessageWithAudio](#FeiShuMessageWithAudio)|飞书语音消息
|[FeiShuMessageWithMedia](#FeiShuMessageWithMedia)|飞书视频消息
|[FeiShuMessageWithMediaAndCover](#FeiShuMessageWithMediaAndCover)|飞书带封面的视频消息
|[FeiShuMessageWithFile](#FeiShuMessageWithFile)|飞书文件消息
|[FeiShuMessageWithSticker](#FeiShuMessageWithSticker)|飞书表情包消息
|[NewFeiShuRichText](#NewFeiShuRichText)|创建一个飞书富文本
> 结构体定义
|结构体|描述
|:--|:--
|[FeiShu](#feishu)|飞书通知消息
|[FeiShuMessage](#feishumessage)|暂无描述...
|[FeiShuRichText](#feishurichtext)|飞书富文本结构
|[FeiShuRichTextContent](#feishurichtextcontent)|飞书富文本内容体
</details>
#### func NewFeiShu(message FeiShuMessage) *FeiShu
<span id="NewFeiShu"></span>
> 创建飞书通知消息
***
#### func FeiShuMessageWithText(text string) FeiShuMessage
<span id="FeiShuMessageWithText"></span>
> 飞书文本消息
> - 支持通过换行符进行消息换行
> - 支持通过 <at user_id="OpenID">名字</at> 进行@用户
> - 支持通过 <at user_id="all">所有人</at> 进行@所有人(必须满足所在群开启@所有人功能。)
>
> 支持加粗、斜体、下划线、删除线四种样式,可嵌套使用:
> - 加粗: <b>文本示例</b>
> - 斜体: <i>文本示例</i>
> - 下划线 : <u>文本示例</u>
> - 删除线: <s>文本示例</s>
>
> 超链接使用说明
> - 超链接的使用格式为[文本](链接) 如[Feishu Open Platform](https://open.feishu.cn) 。
> - 请确保链接是合法的,否则会以原始内容发送消息。
***
#### func FeiShuMessageWithRichText(richText *FeiShuRichText) FeiShuMessage
<span id="FeiShuMessageWithRichText"></span>
> 飞书富文本消息
***
#### func FeiShuMessageWithImage(imageKey string) FeiShuMessage
<span id="FeiShuMessageWithImage"></span>
> 飞书图片消息
> - imageKey 可通过上传图片接口获取
***
#### func FeiShuMessageWithInteractive(json string) FeiShuMessage
<span id="FeiShuMessageWithInteractive"></span>
> 飞书卡片消息
> - json 表示卡片的 json 数据或者消息模板的 json 数据
***
#### func FeiShuMessageWithShareChat(chatId string) FeiShuMessage
<span id="FeiShuMessageWithShareChat"></span>
> 飞书分享群名片
> - chatId 群ID获取方式请参见群ID说明
>
> 群ID说明https://open.feishu.cn/document/server-docs/group/chat/chat-id-description
***
#### func FeiShuMessageWithShareUser(userId string) FeiShuMessage
<span id="FeiShuMessageWithShareUser"></span>
> 飞书分享个人名片
> - userId 表示用户的 OpenID 获取方式请参见了解更多:如何获取 Open ID
>
> 如何获取 Open IDhttps://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid
***
#### func FeiShuMessageWithAudio(fileKey string) FeiShuMessage
<span id="FeiShuMessageWithAudio"></span>
> 飞书语音消息
> - fileKey 语音文件Key可通过上传文件接口获取
>
> 上传文件https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
***
#### func FeiShuMessageWithMedia(fileKey string) FeiShuMessage
<span id="FeiShuMessageWithMedia"></span>
> 飞书视频消息
> - fileKey 视频文件Key可通过上传文件接口获取
>
> 上传文件https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
***
#### func FeiShuMessageWithMediaAndCover(fileKey string, imageKey string) FeiShuMessage
<span id="FeiShuMessageWithMediaAndCover"></span>
> 飞书带封面的视频消息
> - fileKey 视频文件Key可通过上传文件接口获取
> - imageKey 图片文件Key可通过上传文件接口获取
>
> 上传文件https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
***
#### func FeiShuMessageWithFile(fileKey string) FeiShuMessage
<span id="FeiShuMessageWithFile"></span>
> 飞书文件消息
> - fileKey 文件Key可通过上传文件接口获取
>
> 上传文件https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
***
#### func FeiShuMessageWithSticker(fileKey string) FeiShuMessage
<span id="FeiShuMessageWithSticker"></span>
> 飞书表情包消息
> - fileKey 表情包文件Key目前仅支持发送机器人收到的表情包可通过接收消息事件的推送获取表情包 file_key。
>
> 接收消息事件https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive
***
#### func NewFeiShuRichText() *FeiShuRichText
<span id="NewFeiShuRichText"></span>
> 创建一个飞书富文本
***
### FeiShu
飞书通知消息
```go
type FeiShu struct {
Content any
MsgType string
}
```
#### func (*FeiShu) Format() string, error
> 格式化通知内容
***
### FeiShuMessage
```go
type FeiShuMessage struct{}
```
### FeiShuRichText
飞书富文本结构
```go
type FeiShuRichText struct {
content map[string]*FeiShuRichTextContent
}
```
#### func (*FeiShuRichText) Create(lang string, title string) *FeiShuRichTextContent
> 创建一个特定语言和标题的富文本内容
***
### FeiShuRichTextContent
飞书富文本内容体
```go
type FeiShuRichTextContent struct {
richText *FeiShuRichText
Title string
Content [][]map[string]any
}
```
#### func (*FeiShuRichTextContent) AddText(text string, styles ...string) *FeiShuRichTextContent
> 添加文本
***
#### func (*FeiShuRichTextContent) AddUnescapeText(text string, styles ...string) *FeiShuRichTextContent
> 添加 unescape 解码的文本
***
#### func (*FeiShuRichTextContent) AddLink(text string, href string, styles ...string) *FeiShuRichTextContent
> 添加超链接文本
> - 请确保链接地址的合法性,否则消息会发送失败
***
#### func (*FeiShuRichTextContent) AddAt(userId string, styles ...string) *FeiShuRichTextContent
> 添加@的用户
> - @单个用户时userId 字段必须是有效值
> - @所有人填"all"。
***
#### func (*FeiShuRichTextContent) AddAtWithUsername(userId string, username string, styles ...string) *FeiShuRichTextContent
> 添加包含用户名的@用户
> - @单个用户时userId 字段必须是有效值
> - @所有人填"all"。
***
#### func (*FeiShuRichTextContent) AddImg(imageKey string) *FeiShuRichTextContent
> 添加图片
> - imageKey 表示图片的唯一标识,可通过上传图片接口获取
***
#### func (*FeiShuRichTextContent) AddMedia(fileKey string) *FeiShuRichTextContent
> 添加视频
> - fileKey 表示视频文件的唯一标识,可通过上传文件接口获取
***
#### func (*FeiShuRichTextContent) AddMediaWithCover(fileKey string, imageKey string) *FeiShuRichTextContent
> 添加包含封面的视频
> - fileKey 表示视频文件的唯一标识,可通过上传文件接口获取
> - imageKey 表示图片的唯一标识,可通过上传图片接口获取
***
#### func (*FeiShuRichTextContent) AddEmotion(emojiType string) *FeiShuRichTextContent
> 添加表情
> - emojiType 表示表情类型,部分可选值请参见表情文案。
>
> 表情文案https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
***
#### func (*FeiShuRichTextContent) Ok() *FeiShuRichText
> 确认完成,将返回 FeiShuRichText 可继续创建多语言富文本
***

44
notify/senders/README.md Normal file
View File

@ -0,0 +1,44 @@
# Senders
senders Package 包含了内置通知发送器的实现
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/senders)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewFeiShu](#NewFeiShu)|根据特定的 webhook 地址创建飞书发送器
> 结构体定义
|结构体|描述
|:--|:--
|[FeiShu](#feishu)|飞书发送器
</details>
#### func NewFeiShu(webhook string) *FeiShu
<span id="NewFeiShu"></span>
> 根据特定的 webhook 地址创建飞书发送器
***
### FeiShu
飞书发送器
```go
type FeiShu struct {
client *resty.Client
webhook string
}
```
#### func (*FeiShu) Push(notify notify.Notify) error
> 推送通知
***

27
planner/README.md Normal file
View File

@ -0,0 +1,27 @@
# Planner
planner 包含了策划工具相关的内容
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/planner)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

482
planner/pce/README.md Normal file
View File

@ -0,0 +1,482 @@
# Pce
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/pce)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewExporter](#NewExporter)|创建导出器
|[GetFieldGolangType](#GetFieldGolangType)|获取字段的 Golang 类型
|[GetFields](#GetFields)|获取所有内置支持的字段
|[NewLoader](#NewLoader)|创建加载器
> 结构体定义
|结构体|描述
|:--|:--
|[Config](#config)|配置解析接口
|[DataTmpl](#datatmpl)|数据导出模板
|[Exporter](#exporter)|导出器
|[Field](#field)|基本字段类型接口
|[Int](#int)|暂无描述...
|[Int8](#int8)|暂无描述...
|[Int16](#int16)|暂无描述...
|[Int32](#int32)|暂无描述...
|[Int64](#int64)|暂无描述...
|[Uint](#uint)|暂无描述...
|[Uint8](#uint8)|暂无描述...
|[Uint16](#uint16)|暂无描述...
|[Uint32](#uint32)|暂无描述...
|[Uint64](#uint64)|暂无描述...
|[Float32](#float32)|暂无描述...
|[Float64](#float64)|暂无描述...
|[String](#string)|暂无描述...
|[Bool](#bool)|暂无描述...
|[Byte](#byte)|暂无描述...
|[Rune](#rune)|暂无描述...
|[Complex64](#complex64)|暂无描述...
|[Complex128](#complex128)|暂无描述...
|[Uintptr](#uintptr)|暂无描述...
|[Double](#double)|暂无描述...
|[Float](#float)|暂无描述...
|[Long](#long)|暂无描述...
|[Short](#short)|暂无描述...
|[Char](#char)|暂无描述...
|[Number](#number)|暂无描述...
|[Integer](#integer)|暂无描述...
|[Boolean](#boolean)|暂无描述...
|[Loader](#loader)|配置加载器
|[DataInfo](#datainfo)|配置数据
|[DataField](#datafield)|配置数据字段
|[Tmpl](#tmpl)|配置结构模板接口
|[TmplField](#tmplfield)|模板字段
|[TmplStruct](#tmplstruct)|模板结构
</details>
#### func NewExporter() *Exporter
<span id="NewExporter"></span>
> 创建导出器
***
#### func GetFieldGolangType(field Field) string
<span id="GetFieldGolangType"></span>
> 获取字段的 Golang 类型
***
#### func GetFields() []Field
<span id="GetFields"></span>
> 获取所有内置支持的字段
***
#### func NewLoader(fields []Field) *Loader
<span id="NewLoader"></span>
> 创建加载器
> - 加载器被用于加载配置表的数据和结构信息
***
### Config
配置解析接口
- 用于将配置文件解析为可供分析的数据结构
- 可以在 cs 包中找到内置提供的实现及其模板,例如 cs.XlsxIndexConfig
```go
type Config struct{}
```
### DataTmpl
数据导出模板
```go
type DataTmpl struct{}
```
### Exporter
导出器
```go
type Exporter struct{}
```
#### func (*Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) []byte, error
> 导出结构
***
#### func (*Exporter) ExportData(tmpl DataTmpl, data map[any]any) []byte, error
> 导出数据
***
### Field
基本字段类型接口
```go
type Field struct{}
```
### Int
```go
type Int struct{}
```
#### func (Int) TypeName() string
***
#### func (Int) Zero() any
***
#### func (Int) Parse(value string) any
***
### Int8
```go
type Int8 struct{}
```
#### func (Int8) TypeName() string
***
#### func (Int8) Zero() any
***
#### func (Int8) Parse(value string) any
***
### Int16
```go
type Int16 struct{}
```
#### func (Int16) TypeName() string
***
#### func (Int16) Zero() any
***
#### func (Int16) Parse(value string) any
***
### Int32
```go
type Int32 struct{}
```
#### func (Int32) TypeName() string
***
#### func (Int32) Zero() any
***
#### func (Int32) Parse(value string) any
***
### Int64
```go
type Int64 struct{}
```
#### func (Int64) TypeName() string
***
#### func (Int64) Zero() any
***
#### func (Int64) Parse(value string) any
***
### Uint
```go
type Uint struct{}
```
#### func (Uint) TypeName() string
***
#### func (Uint) Zero() any
***
#### func (Uint) Parse(value string) any
***
### Uint8
```go
type Uint8 struct{}
```
#### func (Uint8) TypeName() string
***
#### func (Uint8) Zero() any
***
#### func (Uint8) Parse(value string) any
***
### Uint16
```go
type Uint16 struct{}
```
#### func (Uint16) TypeName() string
***
#### func (Uint16) Zero() any
***
#### func (Uint16) Parse(value string) any
***
### Uint32
```go
type Uint32 struct{}
```
#### func (Uint32) TypeName() string
***
#### func (Uint32) Zero() any
***
#### func (Uint32) Parse(value string) any
***
### Uint64
```go
type Uint64 struct{}
```
#### func (Uint64) TypeName() string
***
#### func (Uint64) Zero() any
***
#### func (Uint64) Parse(value string) any
***
### Float32
```go
type Float32 struct{}
```
#### func (Float32) TypeName() string
***
#### func (Float32) Zero() any
***
#### func (Float32) Parse(value string) any
***
### Float64
```go
type Float64 struct{}
```
#### func (Float64) TypeName() string
***
#### func (Float64) Zero() any
***
#### func (Float64) Parse(value string) any
***
### String
```go
type String struct{}
```
#### func (String) TypeName() string
***
#### func (String) Zero() any
***
#### func (String) Parse(value string) any
***
### Bool
```go
type Bool struct{}
```
#### func (Bool) TypeName() string
***
#### func (Bool) Zero() any
***
#### func (Bool) Parse(value string) any
***
### Byte
```go
type Byte struct{}
```
#### func (Byte) TypeName() string
***
#### func (Byte) Zero() any
***
#### func (Byte) Parse(value string) any
***
### Rune
```go
type Rune struct{}
```
#### func (Rune) TypeName() string
***
#### func (Rune) Zero() any
***
#### func (Rune) Parse(value string) any
***
### Complex64
```go
type Complex64 struct{}
```
#### func (Complex64) TypeName() string
***
#### func (Complex64) Zero() any
***
#### func (Complex64) Parse(value string) any
***
### Complex128
```go
type Complex128 struct{}
```
#### func (Complex128) TypeName() string
***
#### func (Complex128) Zero() any
***
#### func (Complex128) Parse(value string) any
***
### Uintptr
```go
type Uintptr struct{}
```
#### func (Uintptr) TypeName() string
***
#### func (Uintptr) Zero() any
***
#### func (Uintptr) Parse(value string) any
***
### Double
```go
type Double struct{}
```
#### func (Double) TypeName() string
***
#### func (Double) Zero() any
***
#### func (Double) Parse(value string) any
***
### Float
```go
type Float struct{}
```
#### func (Float) TypeName() string
***
#### func (Float) Zero() any
***
#### func (Float) Parse(value string) any
***
### Long
```go
type Long struct{}
```
#### func (Long) TypeName() string
***
#### func (Long) Zero() any
***
#### func (Long) Parse(value string) any
***
### Short
```go
type Short struct{}
```
#### func (Short) TypeName() string
***
#### func (Short) Zero() any
***
#### func (Short) Parse(value string) any
***
### Char
```go
type Char struct{}
```
#### func (Char) TypeName() string
***
#### func (Char) Zero() any
***
#### func (Char) Parse(value string) any
***
### Number
```go
type Number struct{}
```
#### func (Number) TypeName() string
***
#### func (Number) Zero() any
***
#### func (Number) Parse(value string) any
***
### Integer
```go
type Integer struct{}
```
#### func (Integer) TypeName() string
***
#### func (Integer) Zero() any
***
#### func (Integer) Parse(value string) any
***
### Boolean
```go
type Boolean struct{}
```
#### func (Boolean) TypeName() string
***
#### func (Boolean) Zero() any
***
#### func (Boolean) Parse(value string) any
***
### Loader
配置加载器
```go
type Loader struct {
fields map[string]Field
}
```
#### func (*Loader) LoadStruct(config Config) *TmplStruct
> 加载结构
***
#### func (*Loader) LoadData(config Config) map[any]any
> 加载配置并得到配置数据
***
### DataInfo
配置数据
```go
type DataInfo struct {
DataField
Value string
}
```
### DataField
配置数据字段
```go
type DataField struct {
Index int
Name string
Desc string
Type string
ExportType string
}
```
### Tmpl
配置结构模板接口
```go
type Tmpl struct{}
```
### TmplField
模板字段
```go
type TmplField struct {
Name string
Desc string
Type string
Struct *TmplStruct
Index int
slice bool
isIndex bool
}
```
#### func (*TmplField) IsIndex() bool
> 是否是索引字段
***
#### func (*TmplField) IsStruct() bool
> 是否是结构类型
***
#### func (*TmplField) IsSlice() bool
> 是否是切片类型
***
### TmplStruct
模板结构
```go
type TmplStruct struct {
Name string
Desc string
Fields []*TmplField
IndexCount int
}
```
#### func (*TmplStruct) AllChildren() []*TmplStruct
> 获取所有子结构
***

58
planner/pce/cs/README.md Normal file
View File

@ -0,0 +1,58 @@
# Cs
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/cs)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewXlsx](#NewXlsx)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[XlsxExportType](#xlsxexporttype)|暂无描述...
|[Xlsx](#xlsx)|内置的 Xlsx 配置
</details>
#### func NewXlsx(sheet *xlsx.Sheet, exportType XlsxExportType) *Xlsx
<span id="NewXlsx"></span>
***
### XlsxExportType
```go
type XlsxExportType struct{}
```
### Xlsx
内置的 Xlsx 配置
```go
type Xlsx struct {
sheet *xlsx.Sheet
exportType XlsxExportType
}
```
#### func (*Xlsx) GetConfigName() string
***
#### func (*Xlsx) GetDisplayName() string
***
#### func (*Xlsx) GetDescription() string
***
#### func (*Xlsx) GetIndexCount() int
***
#### func (*Xlsx) GetFields() []pce.DataField
***
#### func (*Xlsx) GetData() [][]pce.DataInfo
***

View File

@ -0,0 +1,27 @@
# Main
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/main)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -0,0 +1,32 @@
# Cmd
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/cmd)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Execute](#Execute)|将所有子命令添加到根命令并适当设置标志。这是由 main.main() 调用的。 rootCmd 只需要发生一次
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func Execute()
<span id="Execute"></span>
> 将所有子命令添加到根命令并适当设置标志。这是由 main.main() 调用的。 rootCmd 只需要发生一次
***

View File

@ -0,0 +1,63 @@
# Tmpls
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/tmpls)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewGolang](#NewGolang)|创建一个 Golang 配置导出模板
|[NewJSON](#NewJSON)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[Golang](#golang)|配置导出模板
|[JSON](#json)|暂无描述...
</details>
#### func NewGolang(packageName string) *Golang
<span id="NewGolang"></span>
> 创建一个 Golang 配置导出模板
***
#### func NewJSON() *JSON
<span id="NewJSON"></span>
***
### Golang
配置导出模板
```go
type Golang struct {
Package string
Templates []*pce.TmplStruct
}
```
#### func (*Golang) Render(templates ...*pce.TmplStruct) string, error
***
#### func (*Golang) GetVariable(config *pce.TmplStruct) string
***
#### func (*Golang) GetConfigName(config *pce.TmplStruct) string
***
#### func (*Golang) HasIndex(config *pce.TmplStruct) bool
***
### JSON
```go
type JSON struct {
jsonIter.API
}
```
#### func (*JSON) Render(data map[any]any) string, error
***

807
server/README.md Normal file
View File

@ -0,0 +1,807 @@
# Server
server 提供了包含多种网络类型的服务器实现
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/server)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewBot](#NewBot)|创建一个机器人,目前仅支持 Socket 服务器
|[WithBotNetworkDelay](#WithBotNetworkDelay)|设置机器人网络延迟及波动范围
|[WithBotWriter](#WithBotWriter)|设置机器人写入器,默认为 os.Stdout
|[DefaultWebsocketUpgrader](#DefaultWebsocketUpgrader)|暂无描述...
|[NewHttpHandleWrapper](#NewHttpHandleWrapper)|创建一个新的 http 处理程序包装器
|[NewHttpContext](#NewHttpContext)|基于 gin.Context 创建一个新的 HttpContext
|[NewGinWrapper](#NewGinWrapper)|创建 gin 包装器,用于对 NewHttpWrapper 函数的替代
|[HasMessageType](#HasMessageType)|检查是否存在指定的消息类型
|[NewMultipleServer](#NewMultipleServer)|暂无描述...
|[GetNetworks](#GetNetworks)|获取所有支持的网络模式
|[WithLowMessageDuration](#WithLowMessageDuration)|通过指定慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|[WithAsyncLowMessageDuration](#WithAsyncLowMessageDuration)|通过指定异步消息的慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|[WithWebsocketConnInitializer](#WithWebsocketConnInitializer)|通过 websocket 连接初始化的方式创建服务器,当 initializer 返回错误时,服务器将不会处理该连接的后续逻辑
|[WithWebsocketUpgrade](#WithWebsocketUpgrade)|通过指定 websocket.Upgrader 的方式创建服务器
|[WithConnWriteBufferSize](#WithConnWriteBufferSize)|通过连接写入缓冲区大小的方式创建服务器
|[WithDispatcherBufferSize](#WithDispatcherBufferSize)|通过消息分发器缓冲区大小的方式创建服务器
|[WithMessageStatistics](#WithMessageStatistics)|通过消息统计的方式创建服务器
|[WithPacketWarnSize](#WithPacketWarnSize)|通过数据包大小警告的方式创建服务器,当数据包大小超过指定大小时,将会输出 WARN 类型的日志
|[WithLimitLife](#WithLimitLife)|通过限制最大生命周期的方式创建服务器
|[WithWebsocketWriteCompression](#WithWebsocketWriteCompression)|通过数据写入压缩的方式创建Websocket服务器
|[WithWebsocketCompression](#WithWebsocketCompression)|通过数据压缩的方式创建Websocket服务器
|[WithDeadlockDetect](#WithDeadlockDetect)|通过死锁、死循环、永久阻塞检测的方式创建服务器
|[WithDisableAsyncMessage](#WithDisableAsyncMessage)|通过禁用异步消息的方式创建服务器
|[WithAsyncPoolSize](#WithAsyncPoolSize)|通过指定异步消息池大小的方式创建服务器
|[WithWebsocketReadDeadline](#WithWebsocketReadDeadline)|设置 Websocket 读取超时时间
|[WithTicker](#WithTicker)|通过定时器创建服务器,为服务器添加定时器功能
|[WithTLS](#WithTLS)|通过安全传输层协议TLS创建服务器
|[WithGRPCServerOptions](#WithGRPCServerOptions)|通过GRPC的可选项创建GRPC服务器
|[WithWebsocketMessageType](#WithWebsocketMessageType)|设置仅支持特定类型的Websocket消息
|[WithPProf](#WithPProf)|通过性能分析工具PProf创建服务器
|[New](#New)|根据特定网络类型创建一个服务器
|[BindService](#BindService)|绑定服务到特定 Server被绑定的服务将会在 Server 初始化时执行 Service.OnInit 方法
> 结构体定义
|结构体|描述
|:--|:--
|[Bot](#bot)|暂无描述...
|[BotOption](#botoption)|暂无描述...
|[Conn](#conn)|服务器连接单次消息的包装
|[ConsoleParams](#consoleparams)|控制台参数
|[MessageReadyEventHandler](#messagereadyeventhandler)|暂无描述...
|[Http](#http)|基于 gin.Engine 包装的 http 服务器
|[HttpContext](#httpcontext)|基于 gin.Context 的 http 请求上下文
|[HandlerFunc](#handlerfunc)|暂无描述...
|[ContextPacker](#contextpacker)|暂无描述...
|[HttpRouter](#httprouter)|暂无描述...
|[HttpWrapperHandleFunc](#httpwrapperhandlefunc)|暂无描述...
|[HttpWrapper](#httpwrapper)|http 包装器
|[HttpWrapperGroup](#httpwrappergroup)|http 包装器
|[MessageType](#messagetype)|暂无描述...
|[Message](#message)|服务器消息
|[MultipleServer](#multipleserver)|暂无描述...
|[Network](#network)|暂无描述...
|[Option](#option)|暂无描述...
|[Server](#server)|网络服务器
|[Service](#service)|兼容传统 service 设计模式的接口
</details>
#### func NewBot(srv *Server, options ...BotOption) *Bot
<span id="NewBot"></span>
> 创建一个机器人,目前仅支持 Socket 服务器
***
#### func WithBotNetworkDelay(delay time.Duration, fluctuation time.Duration) BotOption
<span id="WithBotNetworkDelay"></span>
> 设置机器人网络延迟及波动范围
> - delay 延迟
> - fluctuation 波动范围
***
#### func WithBotWriter(construction func (bot *Bot) io.Writer) BotOption
<span id="WithBotWriter"></span>
> 设置机器人写入器,默认为 os.Stdout
***
#### func DefaultWebsocketUpgrader() *websocket.Upgrader
<span id="DefaultWebsocketUpgrader"></span>
***
#### func NewHttpHandleWrapper(srv *Server, packer ContextPacker[Context]) *Http[Context]
<span id="NewHttpHandleWrapper"></span>
> 创建一个新的 http 处理程序包装器
> - 默认使用 server.HttpContext 作为上下文,如果需要依赖其作为新的上下文,可以通过 NewHttpContext 创建
***
#### func NewHttpContext(ctx *gin.Context) *HttpContext
<span id="NewHttpContext"></span>
> 基于 gin.Context 创建一个新的 HttpContext
***
#### func NewGinWrapper(server *gin.Engine, pack func (ctx *gin.Context) CTX) *HttpWrapper[CTX]
<span id="NewGinWrapper"></span>
> 创建 gin 包装器,用于对 NewHttpWrapper 函数的替代
***
#### func HasMessageType(mt MessageType) bool
<span id="HasMessageType"></span>
> 检查是否存在指定的消息类型
***
#### func NewMultipleServer(serverHandle ...func () (addr string, srv *Server)) *MultipleServer
<span id="NewMultipleServer"></span>
***
#### func GetNetworks() []Network
<span id="GetNetworks"></span>
> 获取所有支持的网络模式
***
#### func WithLowMessageDuration(duration time.Duration) Option
<span id="WithLowMessageDuration"></span>
> 通过指定慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
> - 默认值为 DefaultLowMessageDuration
> - 当 duration <= 0 时,表示关闭慢消息检测
***
#### func WithAsyncLowMessageDuration(duration time.Duration) Option
<span id="WithAsyncLowMessageDuration"></span>
> 通过指定异步消息的慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
> - 默认值为 DefaultAsyncLowMessageDuration
> - 当 duration <= 0 时,表示关闭慢消息检测
***
#### func WithWebsocketConnInitializer(initializer func (writer http.ResponseWriter, request *http.Request, conn *websocket.Conn) error) Option
<span id="WithWebsocketConnInitializer"></span>
> 通过 websocket 连接初始化的方式创建服务器,当 initializer 返回错误时,服务器将不会处理该连接的后续逻辑
> - 该选项仅在创建 NetworkWebsocket 服务器时有效
***
#### func WithWebsocketUpgrade(upgrader *websocket.Upgrader) Option
<span id="WithWebsocketUpgrade"></span>
> 通过指定 websocket.Upgrader 的方式创建服务器
> - 默认值为 DefaultWebsocketUpgrader
> - 该选项仅在创建 NetworkWebsocket 服务器时有效
***
#### func WithConnWriteBufferSize(size int) Option
<span id="WithConnWriteBufferSize"></span>
> 通过连接写入缓冲区大小的方式创建服务器
> - 默认值为 DefaultConnWriteBufferSize
> - 设置合适的缓冲区大小可以提高服务器性能,但是会占用更多的内存
***
#### func WithDispatcherBufferSize(size int) Option
<span id="WithDispatcherBufferSize"></span>
> 通过消息分发器缓冲区大小的方式创建服务器
> - 默认值为 DefaultDispatcherBufferSize
> - 设置合适的缓冲区大小可以提高服务器性能,但是会占用更多的内存
***
#### func WithMessageStatistics(duration time.Duration, limit int) Option
<span id="WithMessageStatistics"></span>
> 通过消息统计的方式创建服务器
> - 默认不开启,当 duration 和 limit 均大于 0 的时候,服务器将记录每 duration 期间的消息数量,并保留最多 limit 条
***
#### func WithPacketWarnSize(size int) Option
<span id="WithPacketWarnSize"></span>
> 通过数据包大小警告的方式创建服务器,当数据包大小超过指定大小时,将会输出 WARN 类型的日志
> - 默认值为 DefaultPacketWarnSize
> - 当 size <= 0 时,表示不设置警告
***
#### func WithLimitLife(t time.Duration) Option
<span id="WithLimitLife"></span>
> 通过限制最大生命周期的方式创建服务器
> - 通常用于测试服务器,服务器将在到达最大生命周期时自动关闭
***
#### func WithWebsocketWriteCompression() Option
<span id="WithWebsocketWriteCompression"></span>
> 通过数据写入压缩的方式创建Websocket服务器
> - 默认不开启数据压缩
***
#### func WithWebsocketCompression(level int) Option
<span id="WithWebsocketCompression"></span>
> 通过数据压缩的方式创建Websocket服务器
> - 默认不开启数据压缩
***
#### func WithDeadlockDetect(t time.Duration) Option
<span id="WithDeadlockDetect"></span>
> 通过死锁、死循环、永久阻塞检测的方式创建服务器
> - 当检测到死锁、死循环、永久阻塞时,服务器将会生成 WARN 类型的日志,关键字为 "SuspectedDeadlock"
> - 默认不开启死锁检测
***
#### func WithDisableAsyncMessage() Option
<span id="WithDisableAsyncMessage"></span>
> 通过禁用异步消息的方式创建服务器
***
#### func WithAsyncPoolSize(size int) Option
<span id="WithAsyncPoolSize"></span>
> 通过指定异步消息池大小的方式创建服务器
> - 当通过 WithDisableAsyncMessage 禁用异步消息时,此选项无效
> - 默认值为 DefaultAsyncPoolSize
***
#### func WithWebsocketReadDeadline(t time.Duration) Option
<span id="WithWebsocketReadDeadline"></span>
> 设置 Websocket 读取超时时间
> - 默认: DefaultWebsocketReadDeadline
> - 当 t <= 0 时,表示不设置超时时间
***
#### func WithTicker(poolSize int, size int, connSize int, autonomy bool) Option
<span id="WithTicker"></span>
> 通过定时器创建服务器,为服务器添加定时器功能
> - poolSize指定服务器定时器池大小当池子内的定时器数量超出该值后多余的定时器在释放时将被回收该值小于等于 0 时将使用 timer.DefaultTickerPoolSize
> - size服务器定时器时间轮大小
> - connSize服务器连接定时器时间轮大小当该值小于等于 0 的时候,在新连接建立时将不再为其创建定时器
> - autonomy定时器是否独立运行独立运行的情况下不会作为服务器消息运行会导致并发问题
***
#### func WithTLS(certFile string, keyFile string) Option
<span id="WithTLS"></span>
> 通过安全传输层协议TLS创建服务器
> - 支持Http、Websocket
***
#### func WithGRPCServerOptions(options ...grpc.ServerOption) Option
<span id="WithGRPCServerOptions"></span>
> 通过GRPC的可选项创建GRPC服务器
***
#### func WithWebsocketMessageType(messageTypes ...int) Option
<span id="WithWebsocketMessageType"></span>
> 设置仅支持特定类型的Websocket消息
***
#### func WithPProf(pattern ...string) Option
<span id="WithPProf"></span>
> 通过性能分析工具PProf创建服务器
***
#### func New(network Network, options ...Option) *Server
<span id="New"></span>
> 根据特定网络类型创建一个服务器
***
#### func BindService(srv *Server, services ...Service)
<span id="BindService"></span>
> 绑定服务到特定 Server被绑定的服务将会在 Server 初始化时执行 Service.OnInit 方法
***
### Bot
```go
type Bot struct {
conn *Conn
joined atomic.Bool
}
```
#### func (*Bot) JoinServer()
> 加入服务器
***
#### func (*Bot) LeaveServer()
> 离开服务器
***
#### func (*Bot) SetNetworkDelay(delay time.Duration, fluctuation time.Duration)
> 设置网络延迟和波动范围
> - delay 延迟
> - fluctuation 波动范围
***
#### func (*Bot) SetWriter(writer io.Writer)
> 设置写入器
***
#### func (*Bot) SendPacket(packet []byte)
> 发送数据包到服务器
***
#### func (*Bot) SendWSPacket(wst int, packet []byte)
> 发送 WebSocket 数据包到服务器
***
### BotOption
```go
type BotOption struct{}
```
### Conn
服务器连接单次消息的包装
```go
type Conn struct {
*connection
wst int
ctx context.Context
}
```
#### func (*Conn) Ticker() *timer.Ticker
> 获取定时器
***
#### func (*Conn) GetServer() *Server
> 获取服务器
***
#### func (*Conn) GetOpenTime() time.Time
> 获取连接打开时间
***
#### func (*Conn) GetOnlineTime() time.Duration
> 获取连接在线时长
***
#### func (*Conn) GetWebsocketRequest() *http.Request
> 获取websocket请求
***
#### func (*Conn) IsBot() bool
> 是否是机器人连接
***
#### func (*Conn) RemoteAddr() net.Addr
> 获取远程地址
***
#### func (*Conn) GetID() string
> 获取连接ID
> - 为远程地址的字符串形式
***
#### func (*Conn) GetIP() string
> 获取连接IP
***
#### func (*Conn) IsClosed() bool
> 是否已经关闭
***
#### func (*Conn) SetData(key any, value any) *Conn
> 设置连接数据,该数据将在连接关闭前始终存在
***
#### func (*Conn) GetData(key any) any
> 获取连接数据
***
#### func (*Conn) ViewData() map[any]any
> 查看只读的连接数据
***
#### func (*Conn) SetMessageData(key any, value any) *Conn
> 设置消息数据,该数据将在消息处理完成后释放
***
#### func (*Conn) GetMessageData(key any) any
> 获取消息数据
***
#### func (*Conn) ReleaseData() *Conn
> 释放数据
***
#### func (*Conn) IsWebsocket() bool
> 是否是websocket连接
***
#### func (*Conn) GetWST() int
> 获取本次 websocket 消息类型
> - 默认将与发送类型相同
***
#### func (*Conn) SetWST(wst int) *Conn
> 设置本次 websocket 消息类型
***
#### func (*Conn) PushAsyncMessage(caller func () error, callback func (err error), mark ...log.Field)
> 推送异步消息,该消息将通过 Server.PushShuntAsyncMessage 函数推送
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Conn) PushUniqueAsyncMessage(name string, caller func () error, callback func (err error), mark ...log.Field)
> 推送唯一异步消息,该消息将通过 Server.PushUniqueShuntAsyncMessage 函数推送
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
***
#### func (*Conn) Write(packet []byte, callback ...func (err error))
> 向连接中写入数据
***
#### func (*Conn) Close(err ...error)
> 关闭连接
***
### ConsoleParams
控制台参数
```go
type ConsoleParams struct{}
```
#### func (ConsoleParams) Get(key string) string
> 获取参数值
***
#### func (ConsoleParams) GetValues(key string) []string
> 获取参数值
***
#### func (ConsoleParams) GetValueNum(key string) int
> 获取参数值数量
***
#### func (ConsoleParams) Has(key string) bool
> 是否存在参数
***
#### func (ConsoleParams) Add(key string, value string)
> 添加参数
***
#### func (ConsoleParams) Del(key string)
> 删除参数
***
#### func (ConsoleParams) Clear()
> 清空参数
***
### MessageReadyEventHandler
```go
type MessageReadyEventHandler struct{}
```
### Http
基于 gin.Engine 包装的 http 服务器
```go
type Http[Context any] struct {
srv *Server
*gin.Engine
*HttpRouter[Context]
}
```
#### func (*Http) Gin() *gin.Engine
***
### HttpContext
基于 gin.Context 的 http 请求上下文
```go
type HttpContext struct {
*gin.Context
}
```
#### func (*HttpContext) Gin() *gin.Context
> 获取 gin.Context
***
#### func (*HttpContext) ReadTo(dest any) error
> 读取请求数据到指定结构体,如果失败则返回错误
***
### HandlerFunc
```go
type HandlerFunc[Context any] struct{}
```
### ContextPacker
```go
type ContextPacker[Context any] struct{}
```
### HttpRouter
```go
type HttpRouter[Context any] struct {
srv *Server
group gin.IRouter
packer ContextPacker[Context]
}
```
#### func (*HttpRouter) Handle(httpMethod string, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 使用给定的路径和方法注册新的请求句柄和中间件
> - 最后一个处理程序应该是真正的处理程序,其他处理程序应该是可以而且应该在不同路由之间共享的中间件。
***
#### func (*HttpRouter) POST(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("POST", path, handlers) 的快捷方式
***
#### func (*HttpRouter) GET(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("GET", path, handlers) 的快捷方式
***
#### func (*HttpRouter) DELETE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("DELETE", path, handlers) 的快捷方式
***
#### func (*HttpRouter) PATCH(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("PATCH", path, handlers) 的快捷方式
***
#### func (*HttpRouter) PUT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("PUT", path, handlers) 的快捷方式
***
#### func (*HttpRouter) OPTIONS(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("OPTIONS", path, handlers) 的快捷方式
***
#### func (*HttpRouter) HEAD(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("HEAD", path, handlers) 的快捷方式
***
#### func (*HttpRouter) CONNECT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("CONNECT", path, handlers) 的快捷方式
***
#### func (*HttpRouter) TRACE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 是 Handle("TRACE", path, handlers) 的快捷方式
***
#### func (*HttpRouter) Any(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 注册一个匹配所有 HTTP 方法的路由
> - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
***
#### func (*HttpRouter) Match(methods []string, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 注册一个匹配指定 HTTP 方法的路由
> - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
***
#### func (*HttpRouter) StaticFile(relativePath string, filepath string) *HttpRouter[Context]
> 注册单个路由以便为本地文件系统的单个文件提供服务。
> - 例如: StaticFile("favicon.ico", "./resources/favicon.ico")
***
#### func (*HttpRouter) StaticFileFS(relativePath string, filepath string, fs http.FileSystem) *HttpRouter[Context]
> 与 `StaticFile` 类似,但可以使用自定义的 `http.FileSystem` 代替。
> - 例如: StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
> - 由于依赖于 gin.Engine 默认情况下使用gin.Dir
***
#### func (*HttpRouter) Static(relativePath string, root string) *HttpRouter[Context]
> 提供来自给定文件系统根目录的文件。
> - 例如: Static("/static", "/var/www")
***
#### func (*HttpRouter) StaticFS(relativePath string, fs http.FileSystem) *HttpRouter[Context]
> 与 `Static` 类似,但可以使用自定义的 `http.FileSystem` 代替。
> - 例如: StaticFS("/static", Dir{"/var/www", false})
> - 由于依赖于 gin.Engine 默认情况下使用gin.Dir
***
#### func (*HttpRouter) Group(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
> 创建一个新的路由组。您应该添加所有具有共同中间件的路由。
> - 例如: v1 := slf.Group("/v1")
***
#### func (*HttpRouter) Use(middleware ...HandlerFunc[Context]) *HttpRouter[Context]
> 将中间件附加到路由组。
***
### HttpWrapperHandleFunc
```go
type HttpWrapperHandleFunc[CTX any] struct{}
```
### HttpWrapper
http 包装器
```go
type HttpWrapper[CTX any] struct {
server *gin.Engine
packHandle func(ctx *gin.Context) CTX
}
```
#### func (*HttpWrapper) Handle(httpMethod string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 处理请求
***
#### func (*HttpWrapper) Use(middleware ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 使用中间件
***
#### func (*HttpWrapper) GET(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 GET 请求
***
#### func (*HttpWrapper) POST(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 POST 请求
***
#### func (*HttpWrapper) DELETE(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 DELETE 请求
***
#### func (*HttpWrapper) PATCH(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 PATCH 请求
***
#### func (*HttpWrapper) PUT(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 PUT 请求
***
#### func (*HttpWrapper) OPTIONS(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 OPTIONS 请求
***
#### func (*HttpWrapper) HEAD(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 HEAD 请求
***
#### func (*HttpWrapper) Trace(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 Trace 请求
***
#### func (*HttpWrapper) Connect(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 Connect 请求
***
#### func (*HttpWrapper) Any(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册 Any 请求
***
#### func (*HttpWrapper) Match(methods []string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
> 注册与您声明的指定方法相匹配的路由。
***
#### func (*HttpWrapper) StaticFile(relativePath string, filepath string) *HttpWrapper[CTX]
> 注册 StaticFile 请求
***
#### func (*HttpWrapper) Static(relativePath string, root string) *HttpWrapper[CTX]
> 注册 Static 请求
***
#### func (*HttpWrapper) StaticFS(relativePath string, fs http.FileSystem) *HttpWrapper[CTX]
> 注册 StaticFS 请求
***
#### func (*HttpWrapper) Group(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 创建一个新的路由组。您应该添加所有具有共同中间件的路由。
***
### HttpWrapperGroup
http 包装器
```go
type HttpWrapperGroup[CTX any] struct {
wrapper *HttpWrapper[CTX]
group *gin.RouterGroup
}
```
#### func (*HttpWrapperGroup) Handle(httpMethod string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 处理请求
***
#### func (*HttpWrapperGroup) Use(middleware ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 使用中间件
***
#### func (*HttpWrapperGroup) GET(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 GET 请求
***
#### func (*HttpWrapperGroup) POST(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 POST 请求
***
#### func (*HttpWrapperGroup) DELETE(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 DELETE 请求
***
#### func (*HttpWrapperGroup) PATCH(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 PATCH 请求
***
#### func (*HttpWrapperGroup) PUT(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 PUT 请求
***
#### func (*HttpWrapperGroup) OPTIONS(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 注册 OPTIONS 请求
***
#### func (*HttpWrapperGroup) Group(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
> 创建分组
***
### MessageType
```go
type MessageType struct{}
```
#### func (MessageType) String() string
> 返回消息类型的字符串表示
***
### Message
服务器消息
```go
type Message struct {
dis *dispatcher.Dispatcher[string, *Message]
conn *Conn
err error
ordinaryHandler func()
exceptionHandler func() error
errHandler func(err error)
marks []log.Field
packet []byte
producer string
name string
t MessageType
}
```
#### func (*Message) GetProducer() string
***
#### func (*Message) MessageType() MessageType
> 返回消息类型
***
#### func (*Message) String() string
> 返回消息的字符串表示
***
### MultipleServer
```go
type MultipleServer struct {
servers []*Server
addresses []string
exitEventHandles []func()
}
```
#### func (*MultipleServer) Run()
***
#### func (*MultipleServer) RegExitEvent(handle func ())
> 注册退出事件
***
#### func (*MultipleServer) OnExitEvent()
***
### Network
```go
type Network struct{}
```
#### func (Network) IsSocket() bool
> 返回当前服务器的网络模式是否为 Socket 模式
***
### Option
```go
type Option struct{}
```
### Server
网络服务器
```go
type Server struct {
*event
*runtime
*option
*connMgr
dispatcherMgr *dispatcher.Manager[string, *Message]
ginServer *gin.Engine
httpServer *http.Server
grpcServer *grpc.Server
gServer *gNet
multiple *MultipleServer
ants *ants.Pool
messagePool *hub.ObjectPool[*Message]
ctx context.Context
cancel context.CancelFunc
systemSignal chan os.Signal
closeChannel chan struct{}
multipleRuntimeErrorChan chan error
messageCounter atomic.Int64
addr string
network Network
closed uint32
services []func()
}
```
#### func (*Server) Run(addr string) (err error)
> 使用特定地址运行服务器
> - server.NetworkTcp (addr:":8888")
> - server.NetworkTcp4 (addr:":8888")
> - server.NetworkTcp6 (addr:":8888")
> - server.NetworkUdp (addr:":8888")
> - server.NetworkUdp4 (addr:":8888")
> - server.NetworkUdp6 (addr:":8888")
> - server.NetworkUnix (addr:"socketPath")
> - server.NetworkHttp (addr:":8888")
> - server.NetworkWebsocket (addr:":8888/ws")
> - server.NetworkKcp (addr:":8888")
> - server.NetworkNone (addr:"")
***
#### func (*Server) IsSocket() bool
> 是否是 Socket 模式
***
#### func (*Server) RunNone() error
> 是 Run("") 的简写,仅适用于运行 NetworkNone 服务器
***
#### func (*Server) Context() context.Context
> 获取服务器上下文
***
#### func (*Server) TimeoutContext(timeout time.Duration) context.Context, context.CancelFunc
> 获取服务器超时上下文context.WithTimeout 的简写
***
#### func (*Server) Ticker() *timer.Ticker
> 获取服务器定时器
***
#### func (*Server) Shutdown()
> 主动停止运行服务器
***
#### func (*Server) GRPCServer() *grpc.Server
> 当网络类型为 NetworkGRPC 时将被允许获取 grpc 服务器,否则将会发生 panic
***
#### func (*Server) HttpRouter() gin.IRouter
> 当网络类型为 NetworkHttp 时将被允许获取路由器进行路由注册,否则将会发生 panic
> - 通过该函数注册的路由将无法在服务器关闭时正常等待请求结束
>
> Deprecated: 从 Minotaur 0.0.29 开始,由于设计原因已弃用,该函数将直接返回 *gin.Server 对象,导致无法正常的对请求结束时进行处理
***
#### func (*Server) HttpServer() *Http[*HttpContext]
> 替代 HttpRouter 的函数,返回一个 *Http[*HttpContext] 对象
> - 通过该函数注册的路由将在服务器关闭时正常等待请求结束
> - 如果需要自行包装 Context 对象,可以使用 NewHttpHandleWrapper 方法
***
#### func (*Server) GetMessageCount() int64
> 获取当前服务器中消息的数量
***
#### func (*Server) UseShunt(conn *Conn, name string)
> 切换连接所使用的消息分流渠道,当分流渠道 name 不存在时将会创建一个新的分流渠道,否则将会加入已存在的分流渠道
> - 默认情况下,所有连接都使用系统通道进行消息分发,当指定消息分流渠道且为分流消息类型时,将会使用指定的消息分流渠道进行消息分发
> - 分流渠道会在连接断开时标记为驱逐状态,当分流渠道中的所有消息处理完毕且没有新连接使用时,将会被清除
***
#### func (*Server) HasShunt(name string) bool
> 检查特定消息分流渠道是否存在
***
#### func (*Server) GetConnCurrShunt(conn *Conn) string
> 获取连接当前所使用的消息分流渠道
***
#### func (*Server) GetShuntNum() int
> 获取消息分流渠道数量
***
#### func (*Server) PushSystemMessage(handler func (), mark ...log.Field)
> 向服务器中推送 MessageTypeSystem 消息
> - 系统消息仅包含一个可执行函数,将在系统分发器中执行
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Server) PushAsyncMessage(caller func () error, callback func (err error), mark ...log.Field)
> 向服务器中推送 MessageTypeAsync 消息
> - 异步消息将在服务器的异步消息队列中进行处理,处理完成 caller 的阻塞操作后,将会通过系统消息执行 callback 函数
> - callback 函数将在异步消息处理完成后进行调用,无论过程是否产生 err都将被执行允许为 nil
> - 需要注意的是为了避免并发问题caller 函数请仅处理阻塞操作,其他操作应该在 callback 函数中进行
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Server) PushShuntAsyncMessage(conn *Conn, caller func () error, callback func (err error), mark ...log.Field)
> 向特定分发器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
> - 需要注意的是,当未指定 UseShunt 时,将会通过 PushAsyncMessage 进行转发
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Server) PushPacketMessage(conn *Conn, wst int, packet []byte, mark ...log.Field)
> 向服务器中推送 MessageTypePacket 消息
> - 当存在 UseShunt 的选项时,将会根据选项中的 shuntMatcher 进行分发,否则将在系统分发器中处理消息
***
#### func (*Server) PushTickerMessage(name string, caller func (), mark ...log.Field)
> 向服务器中推送 MessageTypeTicker 消息
> - 通过该函数推送定时消息,当消息触发时将在系统分发器中处理消息
> - 可通过 timer.Ticker 或第三方定时器将执行函数(caller)推送到该消息中进行处理,可有效的避免线程安全问题
> - 参数 name 仅用作标识该定时器名称
>
> 定时消息执行不会有特殊的处理,仅标记为定时任务,也就是允许将各类函数通过该消息发送处理,但是并不建议
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Server) PushShuntTickerMessage(conn *Conn, name string, caller func (), mark ...log.Field)
> 向特定分发器中推送 MessageTypeTicker 消息,消息执行与 MessageTypeTicker 一致
> - 需要注意的是,当未指定 UseShunt 时,将会通过 PushTickerMessage 进行转发
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
***
#### func (*Server) PushUniqueAsyncMessage(unique string, caller func () error, callback func (err error), mark ...log.Field)
> 向服务器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
***
#### func (*Server) PushUniqueShuntAsyncMessage(conn *Conn, unique string, caller func () error, callback func (err error), mark ...log.Field)
> 向特定分发器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
> - 需要注意的是,当未指定 UseShunt 时,将会通过系统分流渠道进行转发
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
***
#### func (*Server) PushShuntMessage(conn *Conn, caller func (), mark ...log.Field)
> 向特定分发器中推送 MessageTypeShunt 消息,消息执行与 MessageTypeSystem 一致,不同的是将会在特定分发器中执行
***
#### func (*Server) GetDurationMessageCount() int64
> 获取当前 WithMessageStatistics 设置的 duration 期间的消息量
***
#### func (*Server) GetDurationMessageCountByOffset(offset int) int64
> 获取特定偏移次数的 WithMessageStatistics 设置的 duration 期间的消息量
> - 该值小于 0 时,将与 GetDurationMessageCount 无异,否则将返回 +n 个期间的消息量,例如 duration 为 1 分钟limit 为 10那么 offset 为 1 的情况下,获取的则是上一分钟消息量
***
#### func (*Server) GetAllDurationMessageCount() []int64
> 获取所有 WithMessageStatistics 设置的 duration 期间的消息量
***
#### func (*Server) HasMessageStatistics() bool
> 是否了开启消息统计
***
### Service
兼容传统 service 设计模式的接口
```go
type Service struct{}
```

172
server/client/README.md Normal file
View File

@ -0,0 +1,172 @@
# Client
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/client)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewClient](#NewClient)|创建客户端
|[CloneClient](#CloneClient)|克隆客户端
|[NewTCP](#NewTCP)|暂无描述...
|[NewUnixDomainSocket](#NewUnixDomainSocket)|暂无描述...
|[NewWebsocket](#NewWebsocket)|创建 websocket 客户端
> 结构体定义
|结构体|描述
|:--|:--
|[Client](#client)|客户端
|[Core](#core)|暂无描述...
|[ConnectionClosedEventHandle](#connectionclosedeventhandle)|暂无描述...
|[Packet](#packet)|暂无描述...
|[TCP](#tcp)|暂无描述...
|[UnixDomainSocket](#unixdomainsocket)|暂无描述...
|[Websocket](#websocket)|websocket 客户端
</details>
#### func NewClient(core Core) *Client
<span id="NewClient"></span>
> 创建客户端
***
#### func CloneClient(client *Client) *Client
<span id="CloneClient"></span>
> 克隆客户端
***
#### func NewTCP(addr string) *Client
<span id="NewTCP"></span>
***
#### func NewUnixDomainSocket(addr string) *Client
<span id="NewUnixDomainSocket"></span>
***
#### func NewWebsocket(addr string) *Client
<span id="NewWebsocket"></span>
> 创建 websocket 客户端
***
### Client
客户端
```go
type Client struct {
*events
core Core
mutex sync.Mutex
closed bool
pool *hub.ObjectPool[*Packet]
loop *writeloop.Channel[*Packet]
loopBufferSize int
block chan struct{}
}
```
#### func (*Client) Run(block ...bool) error
> 运行客户端,当客户端已运行时,会先关闭客户端再重新运行
> - block 以阻塞方式运行
***
#### func (*Client) RunByBufferSize(size int, block ...bool) error
> 指定写入循环缓冲区大小运行客户端,当客户端已运行时,会先关闭客户端再重新运行
> - block 以阻塞方式运行
***
#### func (*Client) IsConnected() bool
> 是否已连接
***
#### func (*Client) Close(err ...error)
> 关闭
***
#### func (*Client) WriteWS(wst int, packet []byte, callback ...func (err error))
> 向连接中写入指定 websocket 数据类型
> - wst: websocket模式中指定消息类型
***
#### func (*Client) Write(packet []byte, callback ...func (err error))
> 向连接中写入数据
***
#### func (*Client) GetServerAddr() string
> 获取服务器地址
***
### Core
```go
type Core struct{}
```
### ConnectionClosedEventHandle
```go
type ConnectionClosedEventHandle struct{}
```
### Packet
```go
type Packet struct {
wst int
data []byte
callback func(err error)
}
```
### TCP
```go
type TCP struct {
conn net.Conn
addr string
closed bool
}
```
#### func (*TCP) Run(runState chan error, receive func (wst int, packet []byte))
***
#### func (*TCP) Write(packet *Packet) error
***
#### func (*TCP) Close()
***
#### func (*TCP) GetServerAddr() string
***
#### func (*TCP) Clone() Core
***
### UnixDomainSocket
```go
type UnixDomainSocket struct {
conn net.Conn
addr string
closed bool
}
```
#### func (*UnixDomainSocket) Run(runState chan error, receive func (wst int, packet []byte))
***
#### func (*UnixDomainSocket) Write(packet *Packet) error
***
#### func (*UnixDomainSocket) Close()
***
#### func (*UnixDomainSocket) GetServerAddr() string
***
#### func (*UnixDomainSocket) Clone() Core
***
### Websocket
websocket 客户端
```go
type Websocket struct {
addr string
conn *websocket.Conn
closed bool
mu sync.Mutex
}
```
#### func (*Websocket) Run(runState chan error, receive func (wst int, packet []byte))
***
#### func (*Websocket) Write(packet *Packet) error
***
#### func (*Websocket) Close()
***
#### func (*Websocket) GetServerAddr() string
***
#### func (*Websocket) Clone() Core
***

205
server/gateway/README.md Normal file
View File

@ -0,0 +1,205 @@
# Gateway
gateway 是用于处理服务器消息的网关模块,适用于对客户端消息进行处理、转发的情况。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/gateway)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewEndpoint](#NewEndpoint)|创建网关端点
|[WithEndpointStateEvaluator](#WithEndpointStateEvaluator)|设置端点健康值评估函数
|[WithEndpointConnectionPoolSize](#WithEndpointConnectionPoolSize)|设置端点连接池大小
|[WithEndpointReconnectInterval](#WithEndpointReconnectInterval)|设置端点重连间隔
|[NewGateway](#NewGateway)|基于 server.Server 创建 Gateway 网关服务器
|[WithEndpointSelector](#WithEndpointSelector)|设置端点选择器
|[MarshalGatewayOutPacket](#MarshalGatewayOutPacket)|将数据包转换为网关出网数据包
|[UnmarshalGatewayOutPacket](#UnmarshalGatewayOutPacket)|将网关出网数据包转换为数据包
|[MarshalGatewayInPacket](#MarshalGatewayInPacket)|将数据包转换为网关入网数据包
|[UnmarshalGatewayInPacket](#UnmarshalGatewayInPacket)|将网关入网数据包转换为数据包
> 结构体定义
|结构体|描述
|:--|:--
|[Endpoint](#endpoint)|网关端点
|[EndpointOption](#endpointoption)|网关端点选项
|[ConnectionOpenedEventHandle](#connectionopenedeventhandle)|暂无描述...
|[EndpointSelector](#endpointselector)|暂无描述...
|[Gateway](#gateway)|基于 server.Server 实现的网关服务器
|[Option](#option)|网关选项
|[Scanner](#scanner)|端点扫描器
</details>
#### func NewEndpoint(name string, cli *client.Client, options ...EndpointOption) *Endpoint
<span id="NewEndpoint"></span>
> 创建网关端点
***
#### func WithEndpointStateEvaluator(evaluator func (costUnixNano float64) float64) EndpointOption
<span id="WithEndpointStateEvaluator"></span>
> 设置端点健康值评估函数
***
#### func WithEndpointConnectionPoolSize(size int) EndpointOption
<span id="WithEndpointConnectionPoolSize"></span>
> 设置端点连接池大小
> - 默认为 DefaultEndpointConnectionPoolSize
> - 端点连接池大小决定了网关服务器与端点服务器建立的连接数,如果 <= 0 则会使用默认值
> - 在网关服务器中,多个客户端在发送消息到端点服务器时,会共用一个连接,适当的增大连接池大小可以提高网关服务器的承载能力
***
#### func WithEndpointReconnectInterval(interval time.Duration) EndpointOption
<span id="WithEndpointReconnectInterval"></span>
> 设置端点重连间隔
> - 默认为 DefaultEndpointReconnectInterval
> - 端点在连接失败后会在该间隔后重连,如果 <= 0 则不会重连
***
#### func NewGateway(srv *server.Server, scanner Scanner, options ...Option) *Gateway
<span id="NewGateway"></span>
> 基于 server.Server 创建 Gateway 网关服务器
***
#### func WithEndpointSelector(selector EndpointSelector) Option
<span id="WithEndpointSelector"></span>
> 设置端点选择器
> - 默认情况下,网关会随机选择一个端点作为目标,如果需要自定义端点选择器,可以通过该选项设置
***
#### func MarshalGatewayOutPacket(addr string, packet []byte) []byte, error
<span id="MarshalGatewayOutPacket"></span>
> 将数据包转换为网关出网数据包
> - | identifier(4) | ipv4(4) | port(2) | packet |
***
#### func UnmarshalGatewayOutPacket(data []byte) (addr string, packet []byte, err error)
<span id="UnmarshalGatewayOutPacket"></span>
> 将网关出网数据包转换为数据包
> - | identifier(4) | ipv4(4) | port(2) | packet |
***
#### func MarshalGatewayInPacket(addr string, currentTime int64, packet []byte) []byte, error
<span id="MarshalGatewayInPacket"></span>
> 将数据包转换为网关入网数据包
> - | ipv4(4) | port(2) | cost(4) | packet |
***
#### func UnmarshalGatewayInPacket(data []byte) (addr string, sendTime int64, packet []byte, err error)
<span id="UnmarshalGatewayInPacket"></span>
> 将网关入网数据包转换为数据包
> - | ipv4(4) | port(2) | cost(4) | packet |
***
### Endpoint
网关端点
- 每一个端点均表示了一个目标服务,网关会将数据包转发到该端点,由该端点负责将数据包转发到目标服务。
- 每个端点会建立一个连接池,默认大小为 DefaultEndpointConnectionPoolSize可通过 WithEndpointConnectionPoolSize 进行设置。
- 网关在转发数据包时会自行根据延迟维护端点健康值,端点健康值越高,网关越倾向于将数据包转发到该端点。
- 端点支持连接未中断前始终将数据包转发到特定端点,这样可以保证连接的状态维持。
连接池:
- 连接池大小决定了网关服务器与端点服务器建立的连接数,例如当连接池大小为 1 时,那么所有连接到该端点的客户端都会共用一个连接。
- 连接池的设计可以突破单机理论 65535 个 WebSocket 客户端的限制,适当的增大连接池大小可以提高网关服务器的承载能力。
```go
type Endpoint struct {
gateway *Gateway
client []*client.Client
name string
address string
state atomic.Float64
evaluator func(costUnixNano float64) float64
connections *haxmap.Map[string, *server.Conn]
rci time.Duration
cps int
}
```
#### func (*Endpoint) GetName() string
> 获取端点名称
***
#### func (*Endpoint) GetAddress() string
> 获取端点地址
***
#### func (*Endpoint) GetState() float64
> 获取端点健康值
***
#### func (*Endpoint) Forward(conn *server.Conn, packet []byte, callback ...func (err error))
> 转发数据包到该端点
> - 端点在处理数据包时,应区分数据包为普通直连数据包还是网关数据包。可通过 UnmarshalGatewayOutPacket 进行数据包解析,当解析失败且无其他数据包协议时,可认为该数据包为普通直连数据包。
***
### EndpointOption
网关端点选项
```go
type EndpointOption struct{}
```
### ConnectionOpenedEventHandle
```go
type ConnectionOpenedEventHandle struct{}
```
### EndpointSelector
```go
type EndpointSelector struct{}
```
### Gateway
基于 server.Server 实现的网关服务器
- 网关服务器是一个特殊的服务器,它会通过扫描器扫描端点列表,然后连接到端点列表中的所有端点,当端点连接成功后,网关服务器会将客户端的连接数据转发到端点服务器
- 由于该网关为多个客户端共享一个端点的连接,所以不会受限于单机 65535 个端口的限制
- 需要注意的是,网关可以通过扫描器得到每个端点需要建立多少个连接,该连接总数将受限与 65535 个端口的限制
一些特性:
- 支持 server.Server 所支持的所有 Socket 网络类型
- 支持将客户端网络类型进行不同的转换,例如:客户端使用 Websocket 连接,但是网关服务器可以将其转换为 TCP 端点的连接
- 支持客户端消息绑定,在客户端未断开连接的情况下,可以将客户端的连接绑定到某个端点,这样该客户端的所有消息都会转发到该端点
- 根据端点延迟实时调整端点状态评分根据评分选择最优的端点默认评分算法为1 / (1 + 1.5 * ${DelaySeconds})
```go
type Gateway struct {
*events
srv *server.Server
scanner Scanner
es map[string]map[string]*Endpoint
esm sync.Mutex
ess EndpointSelector
closed bool
running bool
cce map[string]*Endpoint
cceLock sync.RWMutex
}
```
#### func (*Gateway) Run(addr string) error
> 运行网关
***
#### func (*Gateway) Shutdown()
> 关闭网关
***
#### func (*Gateway) Server() *server.Server
> 获取网关服务器核心
***
#### func (*Gateway) GetEndpoint(name string) *Endpoint, error
> 获取一个可用的端点
> - name: 端点名称
***
#### func (*Gateway) GetConnEndpoint(name string, conn *server.Conn) *Endpoint, error
> 获取一个可用的端点,如果客户端已经连接到了某个端点,将优先返回该端点
> - 当连接到的端点不可用或没有连接记录时,效果同 GetEndpoint 相同
> - 当连接行为为有状态时,推荐使用该方法
***
#### func (*Gateway) SwitchEndpoint(source *Endpoint, dest *Endpoint)
> 将端点端点的所有连接切换到另一个端点
***
### Option
网关选项
```go
type Option struct{}
```
### Scanner
端点扫描器
```go
type Scanner struct{}
```
#### func (*Scanner) GetEndpoints() []*gateway.Endpoint, error
***
#### func (*Scanner) GetInterval() time.Duration
***

View File

@ -0,0 +1,111 @@
# Dispatcher
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/dispatcher)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewDispatcher](#NewDispatcher)|创建一个新的消息分发器 Dispatcher 实例
|[NewManager](#NewManager)|生成消息分发器管理器
> 结构体定义
|结构体|描述
|:--|:--
|[Action](#action)|消息分发器操作器,用于暴露外部可操作的消息分发器函数
|[Handler](#handler)|消息处理器
|[Dispatcher](#dispatcher)|用于服务器消息处理的消息分发器
|[Manager](#manager)|消息分发器管理器
|[Message](#message)|暂无描述...
|[Producer](#producer)|暂无描述...
</details>
#### func NewDispatcher(bufferSize int, name string, handler Handler[P, M]) *Dispatcher[P, M]
<span id="NewDispatcher"></span>
> 创建一个新的消息分发器 Dispatcher 实例
***
#### func NewManager(bufferSize int, handler Handler[P, M]) *Manager[P, M]
<span id="NewManager"></span>
> 生成消息分发器管理器
***
### Action
消息分发器操作器,用于暴露外部可操作的消息分发器函数
```go
type Action[P Producer, M Message[P]] struct {
unlock bool
d *Dispatcher[P, M]
}
```
### Handler
消息处理器
```go
type Handler[P Producer, M Message[P]] struct{}
```
### Dispatcher
用于服务器消息处理的消息分发器
这个消息分发器为并发安全的生产者和消费者模型,生产者可以是任意类型,消费者必须是 Message 接口的实现。
生产者可以通过 Put 方法并发安全地将消息放入消息分发器,消息执行过程不会阻塞到 Put 方法,同时允许在 Start 方法之前调用 Put 方法。
在执行 Start 方法后,消息分发器会阻塞地从消息缓冲区中读取消息,然后执行消息处理器,消息处理器的执行过程不会阻塞到消息的生产。
为了保证消息不丢失,内部采用了 buffer.RingUnbounded 作为缓冲区实现,并且消息分发器不提供 Close 方法。
如果需要关闭消息分发器,可以通过 Expel 方法设置驱逐计划,当消息分发器中没有任何消息时,将会被释放。
同时,也可以使用 UnExpel 方法取消驱逐计划。
为什么提供 Expel 和 UnExpel 方法:
- 在连接断开时,当需要执行一系列消息处理时,如果直接关闭消息分发器,可能会导致消息丢失。所以提供了 Expel 方法,可以在消息处理完成后再关闭消息分发器。
- 当消息还未处理完成时连接重连,如果没有取消驱逐计划,可能会导致消息分发器被关闭。所以提供了 UnExpel 方法,可以在连接重连后取消驱逐计划。
```go
type Dispatcher[P Producer, M Message[P]] struct {
buf *buffer.RingUnbounded[M]
uniques *haxmap.Map[string, struct{}]
handler Handler[P, M]
expel bool
mc int64
pmc map[P]int64
pmcF map[P]func(p P, dispatcher *Action[P, M])
lock sync.RWMutex
name string
closedHandler atomic.Pointer[func(dispatcher *Action[P, M])]
abort chan struct{}
}
```
### Manager
消息分发器管理器
```go
type Manager[P Producer, M Message[P]] struct {
handler Handler[P, M]
sys *Dispatcher[P, M]
dispatchers map[string]*Dispatcher[P, M]
member map[string]map[P]struct{}
curr map[P]*Dispatcher[P, M]
lock sync.RWMutex
w sync.WaitGroup
size int
closedHandler func(name string)
createdHandler func(name string)
}
```
### Message
```go
type Message[P comparable] struct{}
```
### Producer
```go
type Producer struct{}
```

View File

@ -0,0 +1,51 @@
# Logger
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/logger)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
|[Ants](#ants)|暂无描述...
|[GNet](#gnet)|暂无描述...
</details>
### Ants
```go
type Ants struct{}
```
#### func (*Ants) Printf(format string, args ...interface {})
***
### GNet
```go
type GNet struct{}
```
#### func (*GNet) Debugf(format string, args ...interface {})
***
#### func (*GNet) Infof(format string, args ...interface {})
***
#### func (*GNet) Warnf(format string, args ...interface {})
***
#### func (*GNet) Errorf(format string, args ...interface {})
***
#### func (*GNet) Fatalf(format string, args ...interface {})
***

View File

@ -1,9 +1,109 @@
# Lockstep [`锁步(帧)同步`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep#Lockstep)
# Lockstep
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep)
> 它是一个不限制网络类型的实现,仅需要对应连接实现 [`lockstep.Client`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep#Client) 接口即可。
该包提供了一个并发安全的锁步(帧)同步实现,其中内置了频率设置、帧上限、序列化、初始帧、追帧等功能。可使用其来快速构建和管理锁步(帧)同步。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/lockstep)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
锁步(帧)同步是一种特殊的同步,它可以并发安全地将数据同步到底层连接。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewLockstep](#NewLockstep)|创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
|[WithFrameLimit](#WithFrameLimit)|通过特定逻辑帧上限创建锁步(帧)同步组件
|[WithFrameRate](#WithFrameRate)|通过特定逻辑帧率创建锁步(帧)同步组件
|[WithSerialization](#WithSerialization)|通过特定的序列化方式将每一帧的数据进行序列化
|[WithInitFrame](#WithInitFrame)|通过特定的初始帧创建锁步(帧)同步组件
> 结构体定义
|结构体|描述
|:--|:--
|[Client](#client)|帧同步客户端接口定义
|[StoppedEventHandle](#stoppedeventhandle)|暂无描述...
|[Lockstep](#lockstep)|锁步(帧)同步默认实现
|[Option](#option)|暂无描述...
</details>
#### func NewLockstep(options ...Option[ClientID, Command]) *Lockstep[ClientID, Command]
<span id="NewLockstep"></span>
> 创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
***
#### func WithFrameLimit(frameLimit int64) Option[ClientID, Command]
<span id="WithFrameLimit"></span>
> 通过特定逻辑帧上限创建锁步(帧)同步组件
> - 当达到上限时将停止广播
***
#### func WithFrameRate(frameRate int64) Option[ClientID, Command]
<span id="WithFrameRate"></span>
> 通过特定逻辑帧率创建锁步(帧)同步组件
> - 默认情况下为 15/s
***
#### func WithSerialization(handle func (frame int64, commands []Command) []byte) Option[ClientID, Command]
<span id="WithSerialization"></span>
> 通过特定的序列化方式将每一帧的数据进行序列化
>
> - 默认情况下为将被序列化为以下结构体的JSON字符串
>
> type Frame struct {
> Frame int `json:"frame"`
> Commands []Command `json:"commands"`
> }
***
#### func WithInitFrame(initFrame int64) Option[ClientID, Command]
<span id="WithInitFrame"></span>
> 通过特定的初始帧创建锁步(帧)同步组件
> - 默认情况下为 0即第一帧索引为 0
***
### Client
帧同步客户端接口定义
- 客户端应该具备ID及写入数据包的实现
```go
type Client[ID comparable] struct{}
```
### StoppedEventHandle
```go
type StoppedEventHandle[ClientID comparable, Command any] struct{}
```
### Lockstep
锁步(帧)同步默认实现
- 支持最大帧上限 WithFrameLimit
- 自定逻辑帧频率默认为每秒15帧(帧/66ms) WithFrameRate
- 自定帧序列化方式 WithSerialization
- 从特定帧开始追帧
- 兼容各种基于TCP/UDP/Unix的网络类型可通过客户端实现其他网络类型同步
```go
type Lockstep[ClientID comparable, Command any] struct {
running bool
runningLock sync.RWMutex
initFrame int64
frameRate int64
frameLimit int64
serialization func(frame int64, commands []Command) []byte
clients map[ClientID]Client[ClientID]
clientFrame map[ClientID]int64
clientLock sync.RWMutex
currentFrame int64
currentCommands []Command
currentFrameLock sync.RWMutex
frameCache map[int64][]byte
frameCacheLock sync.RWMutex
ticker *time.Ticker
lockstepStoppedEventHandles []StoppedEventHandle[ClientID, Command]
}
```
### Option
```go
type Option[ClientID comparable, Command any] struct{}
```

78
server/router/README.md Normal file
View File

@ -0,0 +1,78 @@
# Router
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/router)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewMultistage](#NewMultistage)|创建一个支持多级分类的路由器
|[WithRouteTrim](#WithRouteTrim)|路由修剪选项
> 结构体定义
|结构体|描述
|:--|:--
|[MultistageBind](#multistagebind)|多级分类路由绑定函数
|[Multistage](#multistage)|支持多级分类的路由器
|[MultistageOption](#multistageoption)|路由器选项
</details>
#### func NewMultistage(options ...MultistageOption[HandleFunc]) *Multistage[HandleFunc]
<span id="NewMultistage"></span>
> 创建一个支持多级分类的路由器
***
#### func WithRouteTrim(handle func (route any) any) MultistageOption[HandleFunc]
<span id="WithRouteTrim"></span>
> 路由修剪选项
> - 将在路由注册前对路由进行对应处理
***
### MultistageBind
多级分类路由绑定函数
```go
type MultistageBind[HandleFunc any] struct{}
```
#### func (MultistageBind) Bind(handleFunc HandleFunc)
> 将处理函数绑定到预设的路由中
***
### Multistage
支持多级分类的路由器
```go
type Multistage[HandleFunc any] struct {
routes map[any]HandleFunc
subs map[any]*Multistage[HandleFunc]
tag any
trim func(route any) any
}
```
#### func (*Multistage) Register(routes ...any) MultistageBind[HandleFunc]
> 注册路由是结合 Sub 和 Route 的快捷方式,用于一次性注册多级路由
> - 该函数将返回一个注册函数可通过调用其将路由绑定到特定处理函数例如router.Register("a", "b").Bind(onExec())
***
#### func (*Multistage) Route(route any, handleFunc HandleFunc)
> 为特定路由绑定处理函数,被绑定的处理函数将可以通过 Match 函数进行匹配
***
#### func (*Multistage) Match(routes ...any) HandleFunc
> 匹配已绑定处理函数的路由,返回处理函数
> - 如果未找到将会返回空指针
***
#### func (*Multistage) Sub(route any) *Multistage[HandleFunc]
> 获取子路由器
***
### MultistageOption
路由器选项
```go
type MultistageOption[HandleFunc any] struct{}
```

View File

@ -1,64 +1,83 @@
# WriteLoop
# Writeloop
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop)
该包提供了一个并发安全的写循环实现。开发者可以使用它来快速构建和管理写入操作。
写循环是一种特殊的循环,它可以并发安全地将数据写入到底层连接。写循环在 `Minotaur` 中是一个泛型类型,可以处理任意类型的消息。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/writeloop)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## Unbounded [`基于无界缓冲区的写循环`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
基于无界缓冲区的写循环实现,它可以处理任意数量的消息。它使用 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 来管理消息对象,使用 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded) 来管理消息队列。
> [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 使用了 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 和 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded) 进行实现。
> 通过 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 创建的消息对象无需手动释放,它会在写循环处理完消息后自动回收。
> 包级函数定义
## Channel [`基于 chan 的写循环`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel)
|函数|描述
|:--|:--
|[NewChannel](#NewChannel)|创建基于 Channel 的写循环
|[NewUnbounded](#NewUnbounded)|创建写循环
基于 [`chan`](https://pkg.go.dev/builtin#chan) 的写循环实现,拥有极高的吞吐量。它使用 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 来管理消息对象,使用 [`Channel`](https://pkg.go.dev/builtin#chan) 来管理消息队列。
## 如何选择
- [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 适用于消息体较小、消息量庞大、消息处理时间较慢的场景,由于没有消息数量限制,所以它可以处理任意数量的消息,但是它的吞吐量较低,并且会占用大量的内存。
- [`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 适用于消息体较大、消息量较小、消息处理时间较快的场景,由于使用了 [`Channel`](https://pkg.go.dev/builtin#chan) 来管理消息队列,所以它的吞吐量较高,但是它的消息数量是有限制的,如果消息数量超过了限制,那么写循环会阻塞,造成无法及时响应消息(例如心跳中断等)。
> 结构体定义
> 通常来说,建议使用 [`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 来实现写循环,因为它的吞吐量更高,并且绝大多数情况是很难达到阻塞的。
### 使用示例
> 该示例由 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 实现,[`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 的使用方法与之类似。
|结构体|描述
|:--|:--
|[Channel](#channel)|基于 chan 的写循环,与 Unbounded 相同,但是使用 Channel 实现
|[Unbounded](#unbounded)|写循环
|[WriteLoop](#writeloop)|暂无描述...
</details>
#### func NewChannel(pool *hub.ObjectPool[Message], channelSize int, writeHandler func (message Message) error, errorHandler func (err any)) *Channel[Message]
<span id="NewChannel"></span>
> 创建基于 Channel 的写循环
> - pool 用于管理 Message 对象的缓冲池,在创建 Message 对象时也应该使用该缓冲池,以便复用 Message 对象。 Channel 会在写入完成后将 Message 对象放回缓冲池
> - channelSize Channel 的大小
> - writeHandler 写入处理函数
> - errorHandler 错误处理函数
>
> 传入 writeHandler 的消息对象是从 Channel 中获取的,因此 writeHandler 不应该持有消息对象的引用,同时也不应该主动释放消息对象
***
#### func NewUnbounded(pool *hub.ObjectPool[Message], writeHandler func (message Message) error, errorHandler func (err any)) *Unbounded[Message]
<span id="NewUnbounded"></span>
> 创建写循环
> - pool 用于管理 Message 对象的缓冲池,在创建 Message 对象时也应该使用该缓冲池,以便复用 Message 对象。 Unbounded 会在写入完成后将 Message 对象放回缓冲池
> - writeHandler 写入处理函数
> - errorHandler 错误处理函数
>
> 传入 writeHandler 的消息对象是从 pool 中获取的,并且在 writeHandler 执行完成后会被放回 pool 中,因此 writeHandler 不应该持有消息对象的引用,同时也不应该主动释放消息对象
***
### Channel
基于 chan 的写循环,与 Unbounded 相同,但是使用 Channel 实现
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/server/writeloop"
"github.com/kercylan98/minotaur/utils/hub"
)
func main() {
pool := concurrent.NewPool[Message](func() *Message {
return &Message{}
}, func(data *Message) {
data.ID = 0
})
var wait sync.WaitGroup
wait.Add(10)
wl := writeloop.NewUnbounded(pool, func(message *Message) error {
fmt.Println(message.ID)
wait.Done()
return nil
}, func(err any) {
fmt.Println(err)
})
for i := 0; i < 10; i++ {
m := pool.Get()
m.ID = i
wl.Put(m)
}
wait.Wait()
wl.Close()
type Channel[T any] struct {
c chan T
}
```
#### func (*Channel) Put(message T)
> 将数据放入写循环message 应该来源于 hub.ObjectPool
***
#### func (*Channel) Close()
> 关闭写循环
***
### Unbounded
写循环
- 用于将数据并发安全的写入到底层连接
```go
type Unbounded[Message any] struct {
buf *buffer.Unbounded[Message]
}
```
#### func (*Unbounded) Put(message Message)
> 将数据放入写循环message 应该来源于 hub.ObjectPool
***
#### func (*Unbounded) Close()
> 关闭写循环
***
### WriteLoop
在这个示例中,我们创建了一个写循环,然后将一些消息放入写循环。每个消息都会被 `writeHandle` 函数处理,如果在处理过程中发生错误,`errorHandle` 函数会被调用。在使用完写循环后,我们需要关闭它。
```go
type WriteLoop[Message any] struct{}
```

32
utils/README.md Normal file
View File

@ -0,0 +1,32 @@
# Utils
utils 旨在提供一组用于处理通用功能的函数和数据结构。该包旨在简化通用功能的实现,并提供一致的接口和易于使用的功能。
主要特性:
- 通用功能utils 包支持处理各种通用功能,如字符串处理、日期时间操作和文件操作等。您可以使用这些功能来解决各种通用问题,并提高代码的复用性和可维护性。
- 数据结构:该包提供了一系列通用的数据结构,如栈、队列、链表和哈希表等。这些数据结构可以用于存储和操作各种类型的数据,并提供高效的访问和操作能力。
- 算法实现utils 包还提供了一些常用的算法实现,如排序算法、搜索算法和图算法等。这些算法可以用于解决各种问题,并提供高效的计算和处理能力。
- 工具函数:该包还提供了一些通用的工具函数,如字符串处理、日期时间操作和文件操作等。这些工具函数可以帮助您简化代码编写,处理文本数据,操作日期时间,读写文件等。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
> 结构体定义
|结构体|描述
|:--|:--
</details>

View File

@ -1,10 +1,67 @@
# AOI (Area of Interest)
# Aoi
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi)
aoi 提供了一种有效的方法来处理 AOIArea of Interest问题。
AOI (Area of Interest) 是一种常见的游戏服务器技术,用于处理大量玩家在同一空间内的交互问题。在 `Minotaur` 中,我们提供了一个基于 Go 语言的 AOI 实现。
AOI 问题是在大规模多人在线游戏中常见的问题,它涉及到确定哪些对象对玩家来说是“感兴趣的”,
也就是说,哪些对象在玩家的视野范围内。
## TwoDimensional [`二维AOI`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensional)
这个包提供了一种数据结构和一些方法来有效地解决这个问题。
[`TwoDimensional`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensional)
是一个二维 AOI 的实现。它提供了添加实体、删除实体、刷新实体、获取焦点实体等方法。每个实体需要实现 [`TwoDimensionalEntity`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensionalEntity) 接口,该接口包含了获取实体 ID、获取实体坐标、获取实体视野半径等方法。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/aoi)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewTwoDimensional](#NewTwoDimensional)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[TwoDimensional](#twodimensional)|暂无描述...
|[TwoDimensionalEntity](#twodimensionalentity)|基于2D定义的AOI对象功能接口
|[EntityJoinVisionEventHandle](#entityjoinvisioneventhandle)|暂无描述...
</details>
#### func NewTwoDimensional(width int, height int, areaWidth int, areaHeight int) *TwoDimensional[EID, PosType, E]
<span id="NewTwoDimensional"></span>
***
### TwoDimensional
```go
type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber, E TwoDimensionalEntity[EID, PosType]] struct {
*event[EID, PosType, E]
rw sync.RWMutex
width float64
height float64
areaWidth float64
areaHeight float64
areaWidthLimit int
areaHeightLimit int
areas [][]map[EID]E
focus map[EID]map[EID]E
repartitionQueue []func()
}
```
### TwoDimensionalEntity
基于2D定义的AOI对象功能接口
- AOI 对象提供了 AOI 系统中常用的属性,诸如位置坐标和视野范围等
```go
type TwoDimensionalEntity[EID generic.Basic, PosType generic.SignedNumber] struct{}
```
### EntityJoinVisionEventHandle
```go
type EntityJoinVisionEventHandle[EID generic.Basic, PosType generic.SignedNumber, E TwoDimensionalEntity[EID, PosType]] struct{}
```

View File

@ -1,17 +1,178 @@
# Arrangement
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement)
arrangement 包提供了一些有用的函数来处理数组的排列。
`Arrangement`包提供了一种灵活的方式来管理和操作编排区域。它包含了一些用于处理编排区域和编排选项的函数和类型
更多的详细信息和使用示例,可以参考每个函数的文档
## Area [`编排区域`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#Area)
`Area`类型代表一个编排区域,它包含了一些方法,如`GetAreaInfo`、`GetItems`、`IsAllow`、`IsConflict`、`GetConflictItems`和`GetScore`,这些方法可以用来获取区域信息、获取区域中的所有成员、检查一个成员是否可以被添加到该区域中、检查一个成员是否会造成冲突、获取与一个成员产生冲突的所有其他成员以及获取该区域的评估分数。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/arrangement)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## Option [`编排选项`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#Option)
`Option`类型代表一个编排选项,它是一个函数,可以用来修改编排的行为。例如,`WithRetryThreshold`、`WithConstraintHandle`和`WithConflictHandle`函数可以用来设置编排时的重试阈值、约束处理函数和冲突处理函数。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
## AreaOption [`编排区域选项`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#AreaOption)
`AreaOption`类型代表一个编排区域选项,它是一个函数,可以用来修改编排区域的行为。例如,`WithAreaConstraint`、`WithAreaConflict`和`WithAreaEvaluate`函数可以用来设置编排区域的约束条件、冲突条件和评估函数。
## 示例代码
[点击查看](./arrangement_test.go)
> 包级函数定义
|函数|描述
|:--|:--
|[WithAreaConstraint](#WithAreaConstraint)|设置编排区域的约束条件
|[WithAreaConflict](#WithAreaConflict)|设置编排区域的冲突条件,冲突处理函数需要返回造成冲突的成员列表
|[WithAreaEvaluate](#WithAreaEvaluate)|设置编排区域的评估函数
|[NewArrangement](#NewArrangement)|创建一个新的编排
|[WithItemFixed](#WithItemFixed)|设置成员的固定编排区域
|[WithItemPriority](#WithItemPriority)|设置成员的优先级
|[WithItemNotAllow](#WithItemNotAllow)|设置成员不允许的编排区域
|[WithRetryThreshold](#WithRetryThreshold)|设置编排时的重试阈值
|[WithConstraintHandle](#WithConstraintHandle)|设置编排时触发约束时的处理函数
|[WithConflictHandle](#WithConflictHandle)|设置编排时触发冲突时的处理函数
> 结构体定义
|结构体|描述
|:--|:--
|[Area](#area)|编排区域
|[AreaOption](#areaoption)|编排区域选项
|[AreaConstraintHandle](#areaconstrainthandle)|暂无描述...
|[Arrangement](#arrangement)|用于针对多条数据进行合理编排的数据结构
|[Editor](#editor)|提供了大量辅助函数的编辑器
|[Item](#item)|编排成员
|[ItemOption](#itemoption)|编排成员选项
|[ItemFixedAreaHandle](#itemfixedareahandle)|暂无描述...
|[Option](#option)|编排选项
|[ConstraintHandle](#constrainthandle)|暂无描述...
</details>
#### func WithAreaConstraint(constraint AreaConstraintHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
<span id="WithAreaConstraint"></span>
> 设置编排区域的约束条件
> - 该约束用于判断一个成员是否可以被添加到该编排区域中
> - 与 WithAreaConflict 不同的是,约束通常用于非成员关系导致的硬性约束,例如:成员的等级过滤、成员的性别等
***
#### func WithAreaConflict(conflict AreaConflictHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
<span id="WithAreaConflict"></span>
> 设置编排区域的冲突条件,冲突处理函数需要返回造成冲突的成员列表
> - 该冲突用于判断一个成员是否可以被添加到该编排区域中
> - 与 WithAreaConstraint 不同的是,冲突通常用于成员关系导致的软性约束,例如:成员的职业唯一性、成员的种族唯一性等
***
#### func WithAreaEvaluate(evaluate AreaEvaluateHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
<span id="WithAreaEvaluate"></span>
> 设置编排区域的评估函数
> - 该评估函数将影响成员被编入区域的优先级
***
#### func NewArrangement(options ...Option[ID, AreaInfo]) *Arrangement[ID, AreaInfo]
<span id="NewArrangement"></span>
> 创建一个新的编排
***
#### func WithItemFixed(matcher ItemFixedAreaHandle[AreaInfo]) ItemOption[ID, AreaInfo]
<span id="WithItemFixed"></span>
> 设置成员的固定编排区域
***
#### func WithItemPriority(priority ItemPriorityHandle[ID, AreaInfo]) ItemOption[ID, AreaInfo]
<span id="WithItemPriority"></span>
> 设置成员的优先级
***
#### func WithItemNotAllow(verify ItemNotAllowVerifyHandle[ID, AreaInfo]) ItemOption[ID, AreaInfo]
<span id="WithItemNotAllow"></span>
> 设置成员不允许的编排区域
***
#### func WithRetryThreshold(threshold int) Option[ID, AreaInfo]
<span id="WithRetryThreshold"></span>
> 设置编排时的重试阈值
> - 当每一轮编排结束任有成员未被编排时,将会进行下一轮编排,直到编排次数达到该阈值
> - 默认的阈值为 10 次
***
#### func WithConstraintHandle(handle ConstraintHandle[ID, AreaInfo]) Option[ID, AreaInfo]
<span id="WithConstraintHandle"></span>
> 设置编排时触发约束时的处理函数
> - 当约束条件触发时,将会调用该函数。如果无法在该函数中处理约束,应该继续返回 err尝试进行下一层的约束处理
> - 当该函数的返回值为 nil 时,表示约束已经被处理,将会命中当前的编排区域
> - 当所有的约束处理函数都无法处理约束时,将会进入下一个编排区域的尝试,如果均无法完成,将会将该成员加入到编排队列的末端,等待下一次编排
>
> 有意思的是,硬性约束应该永远是无解的,而当需要进行一些打破规则的操作时,则可以透过该函数传入的 editor 进行操作
***
#### func WithConflictHandle(handle ConflictHandle[ID, AreaInfo]) Option[ID, AreaInfo]
<span id="WithConflictHandle"></span>
> 设置编排时触发冲突时的处理函数
> - 当冲突条件触发时,将会调用该函数。如果无法在该函数中处理冲突,应该继续返回这一批成员,尝试进行下一层的冲突处理
> - 当该函数的返回值长度为 0 时,表示冲突已经被处理,将会命中当前的编排区域
> - 当所有的冲突处理函数都无法处理冲突时,将会进入下一个编排区域的尝试,如果均无法完成,将会将该成员加入到编排队列的末端,等待下一次编排
***
### Area
编排区域
```go
type Area[ID comparable, AreaInfo any] struct {
info AreaInfo
items map[ID]Item[ID]
constraints []AreaConstraintHandle[ID, AreaInfo]
conflicts []AreaConflictHandle[ID, AreaInfo]
evaluate AreaEvaluateHandle[ID, AreaInfo]
}
```
### AreaOption
编排区域选项
```go
type AreaOption[ID comparable, AreaInfo any] struct{}
```
### AreaConstraintHandle
```go
type AreaConstraintHandle[ID comparable, AreaInfo any] struct{}
```
### Arrangement
用于针对多条数据进行合理编排的数据结构
- 我不知道这个数据结构的具体用途,但是我觉得这个数据结构应该是有用的
- 目前我能想到的用途只有我的过往经历:排课
- 如果是在游戏领域,或许适用于多人小队匹配编排等类似情况
```go
type Arrangement[ID comparable, AreaInfo any] struct {
areas []*Area[ID, AreaInfo]
items map[ID]Item[ID]
fixed map[ID]ItemFixedAreaHandle[AreaInfo]
priority map[ID][]ItemPriorityHandle[ID, AreaInfo]
itemNotAllow map[ID][]ItemNotAllowVerifyHandle[ID, AreaInfo]
threshold int
constraintHandles []ConstraintHandle[ID, AreaInfo]
conflictHandles []ConflictHandle[ID, AreaInfo]
}
```
### Editor
提供了大量辅助函数的编辑器
```go
type Editor[ID comparable, AreaInfo any] struct {
a *Arrangement[ID, AreaInfo]
pending []Item[ID]
fails []Item[ID]
falls map[ID]struct{}
retryCount int
}
```
### Item
编排成员
```go
type Item[ID comparable] struct{}
```
### ItemOption
编排成员选项
```go
type ItemOption[ID comparable, AreaInfo any] struct{}
```
### ItemFixedAreaHandle
```go
type ItemFixedAreaHandle[AreaInfo any] struct{}
```
### Option
编排选项
```go
type Option[ID comparable, AreaInfo any] struct{}
```
### ConstraintHandle
```go
type ConstraintHandle[ID comparable, AreaInfo any] struct{}
```

View File

@ -1,71 +1,144 @@
# Buffer
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer)
buffer 提供了缓冲区相关的实用程序。
该包提供了多种缓冲区实现,包括环形缓冲区和无界缓冲区。开发者可以使用它来快速构建和管理缓冲区
包括创建、读取和写入缓冲区的函数
## Ring [`环形缓冲区`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Ring)
这个包还提供了一个无界缓冲区的实现,可以在不使用额外 goroutine 的情况下实现无界缓冲区。
环形缓冲区是一种特殊的缓冲区,它的头尾是相连的。当缓冲区满时,新的元素会覆盖旧的元素。环形缓冲区在 `Minotaur` 中是一个泛型类型,可以容纳任意类型的元素
无界缓冲区的所有方法都是线程安全的,除了用于同步的互斥锁外,不会阻塞任何东西
## Unbounded [`无界缓冲区`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded)
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/buffer)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
该缓冲区来源于 gRPC 的实现,用于在不使用额外 goroutine 的情况下实现无界缓冲区。无界缓冲区是一种特殊的缓冲区,它的大小可以动态扩展,不会出现溢出的情况。无界缓冲区在 `Minotaur` 中也是一个泛型类型,可以容纳任意类型的元素。
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
### 使用示例
环形缓冲区:
> 包级函数定义
|函数|描述
|:--|:--
|[NewRing](#NewRing)|创建一个并发不安全的环形缓冲区
|[NewRingUnbounded](#NewRingUnbounded)|创建一个并发安全的基于环形缓冲区实现的无界缓冲区
|[NewUnbounded](#NewUnbounded)|创建一个无界缓冲区
> 结构体定义
|结构体|描述
|:--|:--
|[Ring](#ring)|环形缓冲区
|[RingUnbounded](#ringunbounded)|基于环形缓冲区实现的无界缓冲区
|[Unbounded](#unbounded)|是无界缓冲区的实现
</details>
#### func NewRing(initSize ...int) *Ring[T]
<span id="NewRing"></span>
> 创建一个并发不安全的环形缓冲区
> - initSize: 初始容量
>
> 当初始容量小于 2 或未设置时,将会使用默认容量 2
***
#### func NewRingUnbounded(bufferSize int) *RingUnbounded[T]
<span id="NewRingUnbounded"></span>
> 创建一个并发安全的基于环形缓冲区实现的无界缓冲区
***
#### func NewUnbounded() *Unbounded[V]
<span id="NewUnbounded"></span>
> 创建一个无界缓冲区
> - generateNil: 生成空值的函数,该函数仅需始终返回 nil 即可
>
> 该缓冲区来源于 gRPC 的实现,用于在不使用额外 goroutine 的情况下实现无界缓冲区
> - 该缓冲区的所有方法都是线程安全的,除了用于同步的互斥锁外,不会阻塞任何东西
***
### Ring
环形缓冲区
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/utils/buffer"
)
func main() {
ring := buffer.NewRing[int](5)
for i := 0; i < 5; i++ {
ring.Write(i)
}
for i := 0; i < 5; i++ {
v, _ := ring.Read()
fmt.Println(v) // 0 1 2 3 4
}
type Ring[T any] struct {
buf []T
initSize int
size int
r int
w int
}
```
无界缓冲区:
#### func (*Ring) Read() T, error
> 读取数据
***
#### func (*Ring) ReadAll() []T
> 读取所有数据
***
#### func (*Ring) Peek() (t T, err error)
> 查看数据
***
#### func (*Ring) Write(v T)
> 写入数据
***
#### func (*Ring) IsEmpty() bool
> 是否为空
***
#### func (*Ring) Cap() int
> 返回缓冲区容量
***
#### func (*Ring) Len() int
> 返回缓冲区长度
***
#### func (*Ring) Reset()
> 重置缓冲区
***
### RingUnbounded
基于环形缓冲区实现的无界缓冲区
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/utils/buffer"
)
func main() {
unbounded := buffer.NewUnbounded[int]()
for i := 0; i < 10; i++ {
unbounded.Put(i)
}
for {
select {
case v, ok := <-unbounded.Get():
if !ok {
return
}
unbounded.Load()
fmt.Println(v) // 0 1 2 3 4 5 6 7 8 9
if v == 9 {
unbounded.Close()
return
}
}
}
type RingUnbounded[T any] struct {
ring *Ring[T]
rrm sync.Mutex
cond *sync.Cond
rc chan T
closed bool
closedMutex sync.RWMutex
closedSignal chan struct{}
}
```
```
#### func (*RingUnbounded) Write(v T)
> 写入数据
***
#### func (*RingUnbounded) Read() chan T
> 读取数据
***
#### func (*RingUnbounded) Closed() bool
> 判断缓冲区是否已关闭
***
#### func (*RingUnbounded) Close() chan struct {}
> 关闭缓冲区,关闭后将不再接收新数据,但是已有数据仍然可以读取
***
### Unbounded
是无界缓冲区的实现
```go
type Unbounded[V any] struct {
c chan V
closed bool
mu sync.Mutex
backlog []V
}
```
#### func (*Unbounded) Put(t V)
> 将数据放入缓冲区
***
#### func (*Unbounded) Load()
> 将缓冲区中的数据发送到读取通道中,如果缓冲区中没有数据,则不会发送
> - 在每次 Get 后都应该执行该函数
***
#### func (*Unbounded) Get() chan V
> 获取读取通道
***
#### func (*Unbounded) Close()
> 关闭
***
#### func (*Unbounded) IsClosed() bool
> 是否已关闭
***

628
utils/collection/README.md Normal file
View File

@ -0,0 +1,628 @@
# Collection
collection 用于对 input 和 map 操作的工具函数
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/collection)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[CloneSlice](#CloneSlice)|克隆切片,该函数是 slices.Clone 的快捷方式
|[CloneMap](#CloneMap)|克隆 map
|[CloneSliceN](#CloneSliceN)|克隆 slice 为 n 个切片进行返回
|[CloneMapN](#CloneMapN)|克隆 map 为 n 个 map 进行返回
|[CloneSlices](#CloneSlices)|克隆多个切片
|[CloneMaps](#CloneMaps)|克隆多个 map
|[InSlice](#InSlice)|检查 v 是否被包含在 slice 中,当 handler 返回 true 时,表示 v 和 slice 中的某个元素相匹配
|[InComparableSlice](#InComparableSlice)|检查 v 是否被包含在 slice 中
|[AllInSlice](#AllInSlice)|检查 values 中的所有元素是否均被包含在 slice 中,当 handler 返回 true 时,表示 values 中的某个元素和 slice 中的某个元素相匹配
|[AllInComparableSlice](#AllInComparableSlice)|检查 values 中的所有元素是否均被包含在 slice 中
|[AnyInSlice](#AnyInSlice)|检查 values 中的任意一个元素是否被包含在 slice 中,当 handler 返回 true 时,表示 value 中的某个元素和 slice 中的某个元素相匹配
|[AnyInComparableSlice](#AnyInComparableSlice)|检查 values 中的任意一个元素是否被包含在 slice 中
|[InSlices](#InSlices)|通过将多个切片合并后检查 v 是否被包含在 slices 中,当 handler 返回 true 时,表示 v 和 slices 中的某个元素相匹配
|[InComparableSlices](#InComparableSlices)|通过将多个切片合并后检查 v 是否被包含在 slices 中
|[AllInSlices](#AllInSlices)|通过将多个切片合并后检查 values 中的所有元素是否被包含在 slices 中,当 handler 返回 true 时,表示 values 中的某个元素和 slices 中的某个元素相匹配
|[AllInComparableSlices](#AllInComparableSlices)|通过将多个切片合并后检查 values 中的所有元素是否被包含在 slices 中
|[AnyInSlices](#AnyInSlices)|通过将多个切片合并后检查 values 中的任意一个元素是否被包含在 slices 中,当 handler 返回 true 时,表示 values 中的某个元素和 slices 中的某个元素相匹配
|[AnyInComparableSlices](#AnyInComparableSlices)|通过将多个切片合并后检查 values 中的任意一个元素是否被包含在 slices 中
|[InAllSlices](#InAllSlices)|检查 v 是否被包含在 slices 的每一项元素中,当 handler 返回 true 时,表示 v 和 slices 中的某个元素相匹配
|[InAllComparableSlices](#InAllComparableSlices)|检查 v 是否被包含在 slices 的每一项元素中
|[AnyInAllSlices](#AnyInAllSlices)|检查 slices 中的每一个元素是否均包含至少任意一个 values 中的元素,当 handler 返回 true 时,表示 value 中的某个元素和 slices 中的某个元素相匹配
|[AnyInAllComparableSlices](#AnyInAllComparableSlices)|检查 slices 中的每一个元素是否均包含至少任意一个 values 中的元素
|[KeyInMap](#KeyInMap)|检查 m 中是否包含特定 key
|[ValueInMap](#ValueInMap)|检查 m 中是否包含特定 value当 handler 返回 true 时,表示 value 和 m 中的某个元素相匹配
|[AllKeyInMap](#AllKeyInMap)|检查 m 中是否包含 keys 中所有的元素
|[AllValueInMap](#AllValueInMap)|检查 m 中是否包含 values 中所有的元素,当 handler 返回 true 时,表示 values 中的某个元素和 m 中的某个元素相匹配
|[AnyKeyInMap](#AnyKeyInMap)|检查 m 中是否包含 keys 中任意一个元素
|[AnyValueInMap](#AnyValueInMap)|检查 m 中是否包含 values 中任意一个元素,当 handler 返回 true 时,表示 values 中的某个元素和 m 中的某个元素相匹配
|[AllKeyInMaps](#AllKeyInMaps)|检查 maps 中的每一个元素是否均包含 keys 中所有的元素
|[AllValueInMaps](#AllValueInMaps)|检查 maps 中的每一个元素是否均包含 value 中所有的元素,当 handler 返回 true 时,表示 value 中的某个元素和 maps 中的某个元素相匹配
|[AnyKeyInMaps](#AnyKeyInMaps)|检查 keys 中的任意一个元素是否被包含在 maps 中的任意一个元素中
|[AnyValueInMaps](#AnyValueInMaps)|检查 maps 中的任意一个元素是否包含 value 中的任意一个元素,当 handler 返回 true 时,表示 value 中的某个元素和 maps 中的某个元素相匹配
|[KeyInAllMaps](#KeyInAllMaps)|检查 key 是否被包含在 maps 的每一个元素中
|[AnyKeyInAllMaps](#AnyKeyInAllMaps)|检查 maps 中的每一个元素是否均包含 keys 中任意一个元素
|[ConvertSliceToAny](#ConvertSliceToAny)|将切片转换为任意类型的切片
|[ConvertSliceToIndexMap](#ConvertSliceToIndexMap)|将切片转换为索引为键的映射
|[ConvertSliceToIndexOnlyMap](#ConvertSliceToIndexOnlyMap)|将切片转换为索引为键的映射
|[ConvertSliceToMap](#ConvertSliceToMap)|将切片转换为值为键的映射
|[ConvertSliceToBoolMap](#ConvertSliceToBoolMap)|将切片转换为值为键的映射
|[ConvertMapKeysToSlice](#ConvertMapKeysToSlice)|将映射的键转换为切片
|[ConvertMapValuesToSlice](#ConvertMapValuesToSlice)|将映射的值转换为切片
|[InvertMap](#InvertMap)|将映射的键和值互换
|[ConvertMapValuesToBool](#ConvertMapValuesToBool)|将映射的值转换为布尔值
|[ReverseSlice](#ReverseSlice)|将切片反转
|[ClearSlice](#ClearSlice)|清空切片
|[ClearMap](#ClearMap)|清空 map
|[DropSliceByIndices](#DropSliceByIndices)|删除切片中特定索引的元素
|[DropSliceByCondition](#DropSliceByCondition)|删除切片中符合条件的元素
|[DropSliceOverlappingElements](#DropSliceOverlappingElements)|删除切片中与另一个切片重叠的元素
|[DeduplicateSliceInPlace](#DeduplicateSliceInPlace)|去除切片中的重复元素
|[DeduplicateSlice](#DeduplicateSlice)|去除切片中的重复元素,返回新切片
|[DeduplicateSliceInPlaceWithCompare](#DeduplicateSliceInPlaceWithCompare)|去除切片中的重复元素,使用自定义的比较函数
|[DeduplicateSliceWithCompare](#DeduplicateSliceWithCompare)|去除切片中的重复元素,使用自定义的比较函数,返回新的切片
|[FilterOutByIndices](#FilterOutByIndices)|过滤切片中特定索引的元素,返回过滤后的切片
|[FilterOutByCondition](#FilterOutByCondition)|过滤切片中符合条件的元素,返回过滤后的切片
|[FilterOutByKey](#FilterOutByKey)|过滤 map 中特定的 key返回过滤后的 map
|[FilterOutByValue](#FilterOutByValue)|过滤 map 中特定的 value返回过滤后的 map
|[FilterOutByKeys](#FilterOutByKeys)|过滤 map 中多个 key返回过滤后的 map
|[FilterOutByValues](#FilterOutByValues)|过滤 map 中多个 values返回过滤后的 map
|[FilterOutByMap](#FilterOutByMap)|过滤 map 中符合条件的元素,返回过滤后的 map
|[FindLoopedNextInSlice](#FindLoopedNextInSlice)|返回 i 的下一个数组成员,当 i 达到数组长度时从 0 开始
|[FindLoopedPrevInSlice](#FindLoopedPrevInSlice)|返回 i 的上一个数组成员,当 i 为 0 时从数组末尾开始
|[FindCombinationsInSliceByRange](#FindCombinationsInSliceByRange)|获取给定数组的所有组合,且每个组合的成员数量限制在指定范围内
|[FindFirstOrDefaultInSlice](#FindFirstOrDefaultInSlice)|判断切片中是否存在元素,返回第一个元素,不存在则返回默认值
|[FindOrDefaultInSlice](#FindOrDefaultInSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则返回默认值
|[FindOrDefaultInComparableSlice](#FindOrDefaultInComparableSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则返回默认值
|[FindInSlice](#FindInSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则索引返回 -1
|[FindIndexInSlice](#FindIndexInSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引,不存在则索引返回 -1
|[FindInComparableSlice](#FindInComparableSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则索引返回 -1
|[FindIndexInComparableSlice](#FindIndexInComparableSlice)|判断切片中是否存在某个元素,返回第一个匹配的索引,不存在则索引返回 -1
|[FindMinimumInComparableSlice](#FindMinimumInComparableSlice)|获取切片中的最小值
|[FindMinimumInSlice](#FindMinimumInSlice)|获取切片中的最小值
|[FindMaximumInComparableSlice](#FindMaximumInComparableSlice)|获取切片中的最大值
|[FindMaximumInSlice](#FindMaximumInSlice)|获取切片中的最大值
|[FindMin2MaxInComparableSlice](#FindMin2MaxInComparableSlice)|获取切片中的最小值和最大值
|[FindMin2MaxInSlice](#FindMin2MaxInSlice)|获取切片中的最小值和最大值
|[FindMinFromComparableMap](#FindMinFromComparableMap)|获取 map 中的最小值
|[FindMinFromMap](#FindMinFromMap)|获取 map 中的最小值
|[FindMaxFromComparableMap](#FindMaxFromComparableMap)|获取 map 中的最大值
|[FindMaxFromMap](#FindMaxFromMap)|获取 map 中的最大值
|[FindMin2MaxFromComparableMap](#FindMin2MaxFromComparableMap)|获取 map 中的最小值和最大值
|[FindMin2MaxFromMap](#FindMin2MaxFromMap)|获取 map 中的最小值和最大值
|[SwapSlice](#SwapSlice)|将切片中的两个元素进行交换
|[MappingFromSlice](#MappingFromSlice)|将切片中的元素进行转换
|[MappingFromMap](#MappingFromMap)|将 map 中的元素进行转换
|[MergeSlices](#MergeSlices)|合并切片
|[MergeMaps](#MergeMaps)|合并 map当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会覆盖前面的 map 中的 key
|[MergeMapsWithSkip](#MergeMapsWithSkip)|合并 map当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会被跳过
|[ChooseRandomSliceElementRepeatN](#ChooseRandomSliceElementRepeatN)|返回 slice 中的 n 个可重复随机元素
|[ChooseRandomIndexRepeatN](#ChooseRandomIndexRepeatN)|返回 slice 中的 n 个可重复随机元素的索引
|[ChooseRandomSliceElement](#ChooseRandomSliceElement)|返回 slice 中随机一个元素,当 slice 长度为 0 时将会得到 V 的零值
|[ChooseRandomIndex](#ChooseRandomIndex)|返回 slice 中随机一个元素的索引,当 slice 长度为 0 时将会得到 -1
|[ChooseRandomSliceElementN](#ChooseRandomSliceElementN)|返回 slice 中的 n 个不可重复的随机元素
|[ChooseRandomIndexN](#ChooseRandomIndexN)|获取切片中的 n 个随机元素的索引
|[ChooseRandomMapKeyRepeatN](#ChooseRandomMapKeyRepeatN)|获取 map 中的 n 个随机 key允许重复
|[ChooseRandomMapValueRepeatN](#ChooseRandomMapValueRepeatN)|获取 map 中的 n 个随机 n允许重复
|[ChooseRandomMapKeyAndValueRepeatN](#ChooseRandomMapKeyAndValueRepeatN)|获取 map 中的 n 个随机 key 和 v允许重复
|[ChooseRandomMapKey](#ChooseRandomMapKey)|获取 map 中的随机 key
|[ChooseRandomMapValue](#ChooseRandomMapValue)|获取 map 中的随机 value
|[ChooseRandomMapKeyN](#ChooseRandomMapKeyN)|获取 map 中的 inputN 个随机 key
|[ChooseRandomMapValueN](#ChooseRandomMapValueN)|获取 map 中的 n 个随机 value
|[ChooseRandomMapKeyAndValue](#ChooseRandomMapKeyAndValue)|获取 map 中的随机 key 和 v
|[ChooseRandomMapKeyAndValueN](#ChooseRandomMapKeyAndValueN)|获取 map 中的 inputN 个随机 key 和 v
|[DescBy](#DescBy)|返回降序比较结果
|[AscBy](#AscBy)|返回升序比较结果
|[Desc](#Desc)|对切片进行降序排序
|[DescByClone](#DescByClone)|对切片进行降序排序,返回排序后的切片
|[Asc](#Asc)|对切片进行升序排序
|[AscByClone](#AscByClone)|对切片进行升序排序,返回排序后的切片
|[Shuffle](#Shuffle)|对切片进行随机排序
|[ShuffleByClone](#ShuffleByClone)|对切片进行随机排序,返回排序后的切片
> 结构体定义
|结构体|描述
|:--|:--
|[ComparisonHandler](#comparisonhandler)|暂无描述...
|[OrderedValueGetter](#orderedvaluegetter)|暂无描述...
</details>
#### func CloneSlice(slice S) S
<span id="CloneSlice"></span>
> 克隆切片,该函数是 slices.Clone 的快捷方式
***
#### func CloneMap(m M) M
<span id="CloneMap"></span>
> 克隆 map
***
#### func CloneSliceN(slice S, n int) []S
<span id="CloneSliceN"></span>
> 克隆 slice 为 n 个切片进行返回
***
#### func CloneMapN(m M, n int) []M
<span id="CloneMapN"></span>
> 克隆 map 为 n 个 map 进行返回
***
#### func CloneSlices(slices ...S) []S
<span id="CloneSlices"></span>
> 克隆多个切片
***
#### func CloneMaps(maps ...M) []M
<span id="CloneMaps"></span>
> 克隆多个 map
***
#### func InSlice(slice S, v V, handler ComparisonHandler[V]) bool
<span id="InSlice"></span>
> 检查 v 是否被包含在 slice 中,当 handler 返回 true 时,表示 v 和 slice 中的某个元素相匹配
***
#### func InComparableSlice(slice S, v V) bool
<span id="InComparableSlice"></span>
> 检查 v 是否被包含在 slice 中
***
#### func AllInSlice(slice S, values []V, handler ComparisonHandler[V]) bool
<span id="AllInSlice"></span>
> 检查 values 中的所有元素是否均被包含在 slice 中,当 handler 返回 true 时,表示 values 中的某个元素和 slice 中的某个元素相匹配
> - 在所有 values 中的元素都被包含在 slice 中时,返回 true
> - 当 values 长度为 0 或为 nil 时,将返回 true
***
#### func AllInComparableSlice(slice S, values []V) bool
<span id="AllInComparableSlice"></span>
> 检查 values 中的所有元素是否均被包含在 slice 中
> - 在所有 values 中的元素都被包含在 slice 中时,返回 true
> - 当 values 长度为 0 或为 nil 时,将返回 true
***
#### func AnyInSlice(slice S, values []V, handler ComparisonHandler[V]) bool
<span id="AnyInSlice"></span>
> 检查 values 中的任意一个元素是否被包含在 slice 中,当 handler 返回 true 时,表示 value 中的某个元素和 slice 中的某个元素相匹配
> - 当 values 中的任意一个元素被包含在 slice 中时,返回 true
***
#### func AnyInComparableSlice(slice S, values []V) bool
<span id="AnyInComparableSlice"></span>
> 检查 values 中的任意一个元素是否被包含在 slice 中
> - 当 values 中的任意一个元素被包含在 slice 中时,返回 true
***
#### func InSlices(slices []S, v V, handler ComparisonHandler[V]) bool
<span id="InSlices"></span>
> 通过将多个切片合并后检查 v 是否被包含在 slices 中,当 handler 返回 true 时,表示 v 和 slices 中的某个元素相匹配
> - 当传入的 v 被包含在 slices 的任一成员中时,返回 true
***
#### func InComparableSlices(slices []S, v V) bool
<span id="InComparableSlices"></span>
> 通过将多个切片合并后检查 v 是否被包含在 slices 中
> - 当传入的 v 被包含在 slices 的任一成员中时,返回 true
***
#### func AllInSlices(slices []S, values []V, handler ComparisonHandler[V]) bool
<span id="AllInSlices"></span>
> 通过将多个切片合并后检查 values 中的所有元素是否被包含在 slices 中,当 handler 返回 true 时,表示 values 中的某个元素和 slices 中的某个元素相匹配
> - 当 values 中的所有元素都被包含在 slices 的任一成员中时,返回 true
***
#### func AllInComparableSlices(slices []S, values []V) bool
<span id="AllInComparableSlices"></span>
> 通过将多个切片合并后检查 values 中的所有元素是否被包含在 slices 中
> - 当 values 中的所有元素都被包含在 slices 的任一成员中时,返回 true
***
#### func AnyInSlices(slices []S, values []V, handler ComparisonHandler[V]) bool
<span id="AnyInSlices"></span>
> 通过将多个切片合并后检查 values 中的任意一个元素是否被包含在 slices 中,当 handler 返回 true 时,表示 values 中的某个元素和 slices 中的某个元素相匹配
> - 当 values 中的任意一个元素被包含在 slices 的任一成员中时,返回 true
***
#### func AnyInComparableSlices(slices []S, values []V) bool
<span id="AnyInComparableSlices"></span>
> 通过将多个切片合并后检查 values 中的任意一个元素是否被包含在 slices 中
> - 当 values 中的任意一个元素被包含在 slices 的任一成员中时,返回 true
***
#### func InAllSlices(slices []S, v V, handler ComparisonHandler[V]) bool
<span id="InAllSlices"></span>
> 检查 v 是否被包含在 slices 的每一项元素中,当 handler 返回 true 时,表示 v 和 slices 中的某个元素相匹配
> - 当 v 被包含在 slices 的每一项元素中时,返回 true
***
#### func InAllComparableSlices(slices []S, v V) bool
<span id="InAllComparableSlices"></span>
> 检查 v 是否被包含在 slices 的每一项元素中
> - 当 v 被包含在 slices 的每一项元素中时,返回 true
***
#### func AnyInAllSlices(slices []S, values []V, handler ComparisonHandler[V]) bool
<span id="AnyInAllSlices"></span>
> 检查 slices 中的每一个元素是否均包含至少任意一个 values 中的元素,当 handler 返回 true 时,表示 value 中的某个元素和 slices 中的某个元素相匹配
> - 当 slices 中的每一个元素均包含至少任意一个 values 中的元素时,返回 true
***
#### func AnyInAllComparableSlices(slices []S, values []V) bool
<span id="AnyInAllComparableSlices"></span>
> 检查 slices 中的每一个元素是否均包含至少任意一个 values 中的元素
> - 当 slices 中的每一个元素均包含至少任意一个 values 中的元素时,返回 true
***
#### func KeyInMap(m M, key K) bool
<span id="KeyInMap"></span>
> 检查 m 中是否包含特定 key
***
#### func ValueInMap(m M, value V, handler ComparisonHandler[V]) bool
<span id="ValueInMap"></span>
> 检查 m 中是否包含特定 value当 handler 返回 true 时,表示 value 和 m 中的某个元素相匹配
***
#### func AllKeyInMap(m M, keys ...K) bool
<span id="AllKeyInMap"></span>
> 检查 m 中是否包含 keys 中所有的元素
***
#### func AllValueInMap(m M, values []V, handler ComparisonHandler[V]) bool
<span id="AllValueInMap"></span>
> 检查 m 中是否包含 values 中所有的元素,当 handler 返回 true 时,表示 values 中的某个元素和 m 中的某个元素相匹配
***
#### func AnyKeyInMap(m M, keys ...K) bool
<span id="AnyKeyInMap"></span>
> 检查 m 中是否包含 keys 中任意一个元素
***
#### func AnyValueInMap(m M, values []V, handler ComparisonHandler[V]) bool
<span id="AnyValueInMap"></span>
> 检查 m 中是否包含 values 中任意一个元素,当 handler 返回 true 时,表示 values 中的某个元素和 m 中的某个元素相匹配
***
#### func AllKeyInMaps(maps []M, keys ...K) bool
<span id="AllKeyInMaps"></span>
> 检查 maps 中的每一个元素是否均包含 keys 中所有的元素
***
#### func AllValueInMaps(maps []M, values []V, handler ComparisonHandler[V]) bool
<span id="AllValueInMaps"></span>
> 检查 maps 中的每一个元素是否均包含 value 中所有的元素,当 handler 返回 true 时,表示 value 中的某个元素和 maps 中的某个元素相匹配
***
#### func AnyKeyInMaps(maps []M, keys ...K) bool
<span id="AnyKeyInMaps"></span>
> 检查 keys 中的任意一个元素是否被包含在 maps 中的任意一个元素中
> - 当 keys 中的任意一个元素被包含在 maps 中的任意一个元素中时,返回 true
***
#### func AnyValueInMaps(maps []M, values []V, handler ComparisonHandler[V]) bool
<span id="AnyValueInMaps"></span>
> 检查 maps 中的任意一个元素是否包含 value 中的任意一个元素,当 handler 返回 true 时,表示 value 中的某个元素和 maps 中的某个元素相匹配
> - 当 maps 中的任意一个元素包含 value 中的任意一个元素时,返回 true
***
#### func KeyInAllMaps(maps []M, key K) bool
<span id="KeyInAllMaps"></span>
> 检查 key 是否被包含在 maps 的每一个元素中
***
#### func AnyKeyInAllMaps(maps []M, keys []K) bool
<span id="AnyKeyInAllMaps"></span>
> 检查 maps 中的每一个元素是否均包含 keys 中任意一个元素
> - 当 maps 中的每一个元素均包含 keys 中任意一个元素时,返回 true
***
#### func ConvertSliceToAny(s S) []any
<span id="ConvertSliceToAny"></span>
> 将切片转换为任意类型的切片
***
#### func ConvertSliceToIndexMap(s S) map[int]V
<span id="ConvertSliceToIndexMap"></span>
> 将切片转换为索引为键的映射
***
#### func ConvertSliceToIndexOnlyMap(s S) map[int]struct {}
<span id="ConvertSliceToIndexOnlyMap"></span>
> 将切片转换为索引为键的映射
***
#### func ConvertSliceToMap(s S) map[V]struct {}
<span id="ConvertSliceToMap"></span>
> 将切片转换为值为键的映射
***
#### func ConvertSliceToBoolMap(s S) map[V]bool
<span id="ConvertSliceToBoolMap"></span>
> 将切片转换为值为键的映射
***
#### func ConvertMapKeysToSlice(m M) []K
<span id="ConvertMapKeysToSlice"></span>
> 将映射的键转换为切片
***
#### func ConvertMapValuesToSlice(m M) []V
<span id="ConvertMapValuesToSlice"></span>
> 将映射的值转换为切片
***
#### func InvertMap(m M) N
<span id="InvertMap"></span>
> 将映射的键和值互换
***
#### func ConvertMapValuesToBool(m M) N
<span id="ConvertMapValuesToBool"></span>
> 将映射的值转换为布尔值
***
#### func ReverseSlice(s *S)
<span id="ReverseSlice"></span>
> 将切片反转
***
#### func ClearSlice(slice *S)
<span id="ClearSlice"></span>
> 清空切片
***
#### func ClearMap(m M)
<span id="ClearMap"></span>
> 清空 map
***
#### func DropSliceByIndices(slice *S, indices ...int)
<span id="DropSliceByIndices"></span>
> 删除切片中特定索引的元素
***
#### func DropSliceByCondition(slice *S, condition func (v V) bool)
<span id="DropSliceByCondition"></span>
> 删除切片中符合条件的元素
> - condition 的返回值为 true 时,将会删除该元素
***
#### func DropSliceOverlappingElements(slice *S, anotherSlice []V, comparisonHandler ComparisonHandler[V])
<span id="DropSliceOverlappingElements"></span>
> 删除切片中与另一个切片重叠的元素
***
#### func DeduplicateSliceInPlace(s *S)
<span id="DeduplicateSliceInPlace"></span>
> 去除切片中的重复元素
***
#### func DeduplicateSlice(s S) S
<span id="DeduplicateSlice"></span>
> 去除切片中的重复元素,返回新切片
***
#### func DeduplicateSliceInPlaceWithCompare(s *S, compare func (a V) bool)
<span id="DeduplicateSliceInPlaceWithCompare"></span>
> 去除切片中的重复元素,使用自定义的比较函数
***
#### func DeduplicateSliceWithCompare(s S, compare func (a V) bool) S
<span id="DeduplicateSliceWithCompare"></span>
> 去除切片中的重复元素,使用自定义的比较函数,返回新的切片
***
#### func FilterOutByIndices(slice S, indices ...int) S
<span id="FilterOutByIndices"></span>
> 过滤切片中特定索引的元素,返回过滤后的切片
***
#### func FilterOutByCondition(slice S, condition func (v V) bool) S
<span id="FilterOutByCondition"></span>
> 过滤切片中符合条件的元素,返回过滤后的切片
> - condition 的返回值为 true 时,将会过滤掉该元素
***
#### func FilterOutByKey(m M, key K) M
<span id="FilterOutByKey"></span>
> 过滤 map 中特定的 key返回过滤后的 map
***
#### func FilterOutByValue(m M, value V, handler ComparisonHandler[V]) M
<span id="FilterOutByValue"></span>
> 过滤 map 中特定的 value返回过滤后的 map
***
#### func FilterOutByKeys(m M, keys ...K) M
<span id="FilterOutByKeys"></span>
> 过滤 map 中多个 key返回过滤后的 map
***
#### func FilterOutByValues(m M, values []V, handler ComparisonHandler[V]) M
<span id="FilterOutByValues"></span>
> 过滤 map 中多个 values返回过滤后的 map
***
#### func FilterOutByMap(m M, condition func (k K, v V) bool) M
<span id="FilterOutByMap"></span>
> 过滤 map 中符合条件的元素,返回过滤后的 map
> - condition 的返回值为 true 时,将会过滤掉该元素
***
#### func FindLoopedNextInSlice(slice S, i int) (next int, value V)
<span id="FindLoopedNextInSlice"></span>
> 返回 i 的下一个数组成员,当 i 达到数组长度时从 0 开始
> - 当 i 为负数时将返回第一个元素
***
#### func FindLoopedPrevInSlice(slice S, i int) (prev int, value V)
<span id="FindLoopedPrevInSlice"></span>
> 返回 i 的上一个数组成员,当 i 为 0 时从数组末尾开始
> - 当 i 为负数时将返回最后一个元素
***
#### func FindCombinationsInSliceByRange(s S, minSize int, maxSize int) []S
<span id="FindCombinationsInSliceByRange"></span>
> 获取给定数组的所有组合,且每个组合的成员数量限制在指定范围内
***
#### func FindFirstOrDefaultInSlice(slice S, defaultValue V) V
<span id="FindFirstOrDefaultInSlice"></span>
> 判断切片中是否存在元素,返回第一个元素,不存在则返回默认值
***
#### func FindOrDefaultInSlice(slice S, defaultValue V, handler func (v V) bool) (t V)
<span id="FindOrDefaultInSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则返回默认值
***
#### func FindOrDefaultInComparableSlice(slice S, v V, defaultValue V) (t V)
<span id="FindOrDefaultInComparableSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则返回默认值
***
#### func FindInSlice(slice S, handler func (v V) bool) (i int, t V)
<span id="FindInSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则索引返回 -1
***
#### func FindIndexInSlice(slice S, handler func (v V) bool) int
<span id="FindIndexInSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引,不存在则索引返回 -1
***
#### func FindInComparableSlice(slice S, v V) (i int, t V)
<span id="FindInComparableSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引和元素,不存在则索引返回 -1
***
#### func FindIndexInComparableSlice(slice S, v V) int
<span id="FindIndexInComparableSlice"></span>
> 判断切片中是否存在某个元素,返回第一个匹配的索引,不存在则索引返回 -1
***
#### func FindMinimumInComparableSlice(slice S) (result V)
<span id="FindMinimumInComparableSlice"></span>
> 获取切片中的最小值
***
#### func FindMinimumInSlice(slice S, handler OrderedValueGetter[V, N]) (result V)
<span id="FindMinimumInSlice"></span>
> 获取切片中的最小值
***
#### func FindMaximumInComparableSlice(slice S) (result V)
<span id="FindMaximumInComparableSlice"></span>
> 获取切片中的最大值
***
#### func FindMaximumInSlice(slice S, handler OrderedValueGetter[V, N]) (result V)
<span id="FindMaximumInSlice"></span>
> 获取切片中的最大值
***
#### func FindMin2MaxInComparableSlice(slice S) (min V, max V)
<span id="FindMin2MaxInComparableSlice"></span>
> 获取切片中的最小值和最大值
***
#### func FindMin2MaxInSlice(slice S, handler OrderedValueGetter[V, N]) (min V, max V)
<span id="FindMin2MaxInSlice"></span>
> 获取切片中的最小值和最大值
***
#### func FindMinFromComparableMap(m M) (result V)
<span id="FindMinFromComparableMap"></span>
> 获取 map 中的最小值
***
#### func FindMinFromMap(m M, handler OrderedValueGetter[V, N]) (result V)
<span id="FindMinFromMap"></span>
> 获取 map 中的最小值
***
#### func FindMaxFromComparableMap(m M) (result V)
<span id="FindMaxFromComparableMap"></span>
> 获取 map 中的最大值
***
#### func FindMaxFromMap(m M, handler OrderedValueGetter[V, N]) (result V)
<span id="FindMaxFromMap"></span>
> 获取 map 中的最大值
***
#### func FindMin2MaxFromComparableMap(m M) (min V, max V)
<span id="FindMin2MaxFromComparableMap"></span>
> 获取 map 中的最小值和最大值
***
#### func FindMin2MaxFromMap(m M) (min V, max V)
<span id="FindMin2MaxFromMap"></span>
> 获取 map 中的最小值和最大值
***
#### func SwapSlice(slice *S, i int, j int)
<span id="SwapSlice"></span>
> 将切片中的两个元素进行交换
***
#### func MappingFromSlice(slice S, handler func (value V) N) NS
<span id="MappingFromSlice"></span>
> 将切片中的元素进行转换
***
#### func MappingFromMap(m M, handler func (value V) N) NM
<span id="MappingFromMap"></span>
> 将 map 中的元素进行转换
***
#### func MergeSlices(slices ...S) (result S)
<span id="MergeSlices"></span>
> 合并切片
***
#### func MergeMaps(maps ...M) (result M)
<span id="MergeMaps"></span>
> 合并 map当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会覆盖前面的 map 中的 key
***
#### func MergeMapsWithSkip(maps ...M) (result M)
<span id="MergeMapsWithSkip"></span>
> 合并 map当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会被跳过
***
#### func ChooseRandomSliceElementRepeatN(slice S, n int) (result []V)
<span id="ChooseRandomSliceElementRepeatN"></span>
> 返回 slice 中的 n 个可重复随机元素
> - 当 slice 长度为 0 或 n 小于等于 0 时将会返回 nil
***
#### func ChooseRandomIndexRepeatN(slice S, n int) (result []int)
<span id="ChooseRandomIndexRepeatN"></span>
> 返回 slice 中的 n 个可重复随机元素的索引
> - 当 slice 长度为 0 或 n 小于等于 0 时将会返回 nil
***
#### func ChooseRandomSliceElement(slice S) (v V)
<span id="ChooseRandomSliceElement"></span>
> 返回 slice 中随机一个元素,当 slice 长度为 0 时将会得到 V 的零值
***
#### func ChooseRandomIndex(slice S) (index int)
<span id="ChooseRandomIndex"></span>
> 返回 slice 中随机一个元素的索引,当 slice 长度为 0 时将会得到 -1
***
#### func ChooseRandomSliceElementN(slice S, n int) (result []V)
<span id="ChooseRandomSliceElementN"></span>
> 返回 slice 中的 n 个不可重复的随机元素
> - 当 slice 长度为 0 或 n 大于 slice 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomIndexN(slice S, n int) (result []int)
<span id="ChooseRandomIndexN"></span>
> 获取切片中的 n 个随机元素的索引
> - 如果 n 大于切片长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapKeyRepeatN(m M, n int) (result []K)
<span id="ChooseRandomMapKeyRepeatN"></span>
> 获取 map 中的 n 个随机 key允许重复
> - 如果 n 大于 map 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapValueRepeatN(m M, n int) (result []V)
<span id="ChooseRandomMapValueRepeatN"></span>
> 获取 map 中的 n 个随机 n允许重复
> - 如果 n 大于 map 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapKeyAndValueRepeatN(m M, n int) M
<span id="ChooseRandomMapKeyAndValueRepeatN"></span>
> 获取 map 中的 n 个随机 key 和 v允许重复
> - 如果 n 大于 map 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapKey(m M) (k K)
<span id="ChooseRandomMapKey"></span>
> 获取 map 中的随机 key
***
#### func ChooseRandomMapValue(m M) (v V)
<span id="ChooseRandomMapValue"></span>
> 获取 map 中的随机 value
***
#### func ChooseRandomMapKeyN(m M, n int) (result []K)
<span id="ChooseRandomMapKeyN"></span>
> 获取 map 中的 inputN 个随机 key
> - 如果 inputN 大于 map 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapValueN(m M, n int) (result []V)
<span id="ChooseRandomMapValueN"></span>
> 获取 map 中的 n 个随机 value
> - 如果 n 大于 map 长度或小于 0 时将会发生 panic
***
#### func ChooseRandomMapKeyAndValue(m M) (k K, v V)
<span id="ChooseRandomMapKeyAndValue"></span>
> 获取 map 中的随机 key 和 v
***
#### func ChooseRandomMapKeyAndValueN(m M, n int) M
<span id="ChooseRandomMapKeyAndValueN"></span>
> 获取 map 中的 inputN 个随机 key 和 v
> - 如果 n 大于 map 长度或小于 0 时将会发生 panic
***
#### func DescBy(a Sort, b Sort) bool
<span id="DescBy"></span>
> 返回降序比较结果
***
#### func AscBy(a Sort, b Sort) bool
<span id="AscBy"></span>
> 返回升序比较结果
***
#### func Desc(slice *S, getter func (index int) Sort)
<span id="Desc"></span>
> 对切片进行降序排序
***
#### func DescByClone(slice S, getter func (index int) Sort) S
<span id="DescByClone"></span>
> 对切片进行降序排序,返回排序后的切片
***
#### func Asc(slice *S, getter func (index int) Sort)
<span id="Asc"></span>
> 对切片进行升序排序
***
#### func AscByClone(slice S, getter func (index int) Sort) S
<span id="AscByClone"></span>
> 对切片进行升序排序,返回排序后的切片
***
#### func Shuffle(slice *S)
<span id="Shuffle"></span>
> 对切片进行随机排序
***
#### func ShuffleByClone(slice S) S
<span id="ShuffleByClone"></span>
> 对切片进行随机排序,返回排序后的切片
***
### ComparisonHandler
```go
type ComparisonHandler[V any] struct{}
```
### OrderedValueGetter
```go
type OrderedValueGetter[V any, N generic.Ordered] struct{}
```

View File

@ -0,0 +1,179 @@
# Listings
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/listings)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewMatrix](#NewMatrix)|创建一个新的 Matrix 实例。
|[NewPagedSlice](#NewPagedSlice)|创建一个新的 PagedSlice 实例。
|[NewPrioritySlice](#NewPrioritySlice)|创建一个优先级切片
|[NewSyncSlice](#NewSyncSlice)|创建一个 SyncSlice
> 结构体定义
|结构体|描述
|:--|:--
|[Matrix](#matrix)|暂无描述...
|[PagedSlice](#pagedslice)|是一个高效的动态数组,它通过分页管理内存并减少频繁的内存分配来提高性能。
|[PrioritySlice](#priorityslice)|是一个优先级切片
|[SyncSlice](#syncslice)|是基于 sync.RWMutex 实现的线程安全的 slice
</details>
#### func NewMatrix(dimensions ...int) *Matrix[V]
<span id="NewMatrix"></span>
> 创建一个新的 Matrix 实例。
***
#### func NewPagedSlice(pageSize int) *PagedSlice[T]
<span id="NewPagedSlice"></span>
> 创建一个新的 PagedSlice 实例。
***
#### func NewPrioritySlice(lengthAndCap ...int) *PrioritySlice[V]
<span id="NewPrioritySlice"></span>
> 创建一个优先级切片
***
#### func NewSyncSlice(length int, cap int) *SyncSlice[V]
<span id="NewSyncSlice"></span>
> 创建一个 SyncSlice
***
### Matrix
```go
type Matrix[V any] struct {
dimensions []int
data []V
}
```
#### func (*Matrix) Get(index ...int) *V
> 获取矩阵中给定索引的元素。
***
#### func (*Matrix) Set(index []int, value V)
> 设置矩阵中给定索引的元素。
***
#### func (*Matrix) Dimensions() []int
> 返回矩阵的维度大小。
***
#### func (*Matrix) Clear()
> 清空矩阵。
***
### PagedSlice
是一个高效的动态数组,它通过分页管理内存并减少频繁的内存分配来提高性能。
```go
type PagedSlice[T any] struct {
pages [][]T
pageSize int
len int
lenLast int
}
```
#### func (*PagedSlice) Add(value T)
> 添加一个元素到 PagedSlice 中。
***
#### func (*PagedSlice) Get(index int) *T
> 获取 PagedSlice 中给定索引的元素。
***
#### func (*PagedSlice) Set(index int, value T)
> 设置 PagedSlice 中给定索引的元素。
***
#### func (*PagedSlice) Len() int
> 返回 PagedSlice 中元素的数量。
***
#### func (*PagedSlice) Clear()
> 清空 PagedSlice。
***
#### func (*PagedSlice) Range(f func (index int, value T) bool)
> 迭代 PagedSlice 中的所有元素。
***
### PrioritySlice
是一个优先级切片
```go
type PrioritySlice[V any] struct {
items []*priorityItem[V]
}
```
#### func (*PrioritySlice) Len() int
> 返回切片长度
***
#### func (*PrioritySlice) Cap() int
> 返回切片容量
***
#### func (*PrioritySlice) Clear()
> 清空切片
***
#### func (*PrioritySlice) Append(v V, p int)
> 添加元素
***
#### func (*PrioritySlice) Appends(priority int, vs ...V)
> 添加元素
***
#### func (*PrioritySlice) Get(index int) V, int
> 获取元素
***
#### func (*PrioritySlice) GetValue(index int) V
> 获取元素值
***
#### func (*PrioritySlice) GetPriority(index int) int
> 获取元素优先级
***
#### func (*PrioritySlice) Set(index int, value V, priority int)
> 设置元素
***
#### func (*PrioritySlice) SetValue(index int, value V)
> 设置元素值
***
#### func (*PrioritySlice) SetPriority(index int, priority int)
> 设置元素优先级
***
#### func (*PrioritySlice) Action(action func (items []*priorityItem[V]) []*priorityItem[V])
> 直接操作切片,如果返回值不为 nil则替换切片
***
#### func (*PrioritySlice) Range(action func (index int, item *priorityItem[V]) bool)
> 遍历切片,如果返回值为 false则停止遍历
***
#### func (*PrioritySlice) RangeValue(action func (index int, value V) bool)
> 遍历切片值,如果返回值为 false则停止遍历
***
#### func (*PrioritySlice) RangePriority(action func (index int, priority int) bool)
> 遍历切片优先级,如果返回值为 false则停止遍历
***
#### func (*PrioritySlice) Slice() []V
> 返回切片
***
#### func (*PrioritySlice) String() string
> 返回切片字符串
***
### SyncSlice
是基于 sync.RWMutex 实现的线程安全的 slice
```go
type SyncSlice[V any] struct {
rw sync.RWMutex
data []V
}
```
#### func (*SyncSlice) Get(index int) V
***
#### func (*SyncSlice) GetWithRange(start int, end int) []V
***
#### func (*SyncSlice) Set(index int, value V)
***
#### func (*SyncSlice) Append(values ...V)
***
#### func (*SyncSlice) Release()
***
#### func (*SyncSlice) Clear()
***
#### func (*SyncSlice) GetData() []V
***

View File

@ -0,0 +1,43 @@
# Mappings
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/mappings)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewSyncMap](#NewSyncMap)|创建一个 SyncMap
> 结构体定义
|结构体|描述
|:--|:--
|[SyncMap](#syncmap)|是基于 sync.RWMutex 实现的线程安全的 map
</details>
#### func NewSyncMap(source ...map[K]V) *SyncMap[K, V]
<span id="NewSyncMap"></span>
> 创建一个 SyncMap
***
### SyncMap
是基于 sync.RWMutex 实现的线程安全的 map
- 适用于要考虑并发读写但是并发读写的频率不高的情况
```go
type SyncMap[K comparable, V any] struct {
lock sync.RWMutex
data map[K]V
atom bool
}
```

View File

@ -1,25 +1,291 @@
# Combination
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/combination)
combination 包提供了一些实用的组合函数。
`Combination` 包是一个实用的工具,提供了一系列用于生成和处理组合的函数,以帮助开发者处理复杂的组合问题。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/combination)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 特性
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
### 泛型类型
`Minotaur` 中,我们的组合函数是泛型类型,这意味着它们可以处理任意类型的元素,为开发者提供了灵活性,使得这个包可以在各种不同的场景和应用中使用。
> 包级函数定义
### 算法描述
|函数|描述
|:--|:--
|[NewCombination](#NewCombination)|创建一个新的组合器
|[WithEvaluation](#WithEvaluation)|设置组合评估函数
|[NewMatcher](#NewMatcher)|创建一个新的匹配器
|[WithMatcherEvaluation](#WithMatcherEvaluation)|设置匹配器评估函数
|[WithMatcherLeastLength](#WithMatcherLeastLength)|通过匹配最小长度的组合创建匹配器
|[WithMatcherLength](#WithMatcherLength)|通过匹配长度的组合创建匹配器
|[WithMatcherMostLength](#WithMatcherMostLength)|通过匹配最大长度的组合创建匹配器
|[WithMatcherIntervalLength](#WithMatcherIntervalLength)|通过匹配长度区间的组合创建匹配器
|[WithMatcherContinuity](#WithMatcherContinuity)|通过匹配连续的组合创建匹配器
|[WithMatcherSame](#WithMatcherSame)|通过匹配相同的组合创建匹配器
|[WithMatcherNCarryM](#WithMatcherNCarryM)|通过匹配 N 携带 M 的组合创建匹配器
|[WithMatcherNCarryIndependentM](#WithMatcherNCarryIndependentM)|通过匹配 N 携带独立 M 的组合创建匹配器
|[NewValidator](#NewValidator)|创建一个新的校验器
|[WithValidatorHandle](#WithValidatorHandle)|通过特定的验证函数对组合进行验证
|[WithValidatorHandleLength](#WithValidatorHandleLength)|校验组合的长度是否符合要求
|[WithValidatorHandleLengthRange](#WithValidatorHandleLengthRange)|校验组合的长度是否在指定的范围内
|[WithValidatorHandleLengthMin](#WithValidatorHandleLengthMin)|校验组合的长度是否大于等于指定的最小值
|[WithValidatorHandleLengthMax](#WithValidatorHandleLengthMax)|校验组合的长度是否小于等于指定的最大值
|[WithValidatorHandleLengthNot](#WithValidatorHandleLengthNot)|校验组合的长度是否不等于指定的值
|[WithValidatorHandleTypeLength](#WithValidatorHandleTypeLength)|校验组合成员类型数量是否为指定的值
|[WithValidatorHandleTypeLengthRange](#WithValidatorHandleTypeLengthRange)|校验组合成员类型数量是否在指定的范围内
|[WithValidatorHandleTypeLengthMin](#WithValidatorHandleTypeLengthMin)|校验组合成员类型数量是否大于等于指定的最小值
|[WithValidatorHandleTypeLengthMax](#WithValidatorHandleTypeLengthMax)|校验组合成员类型数量是否小于等于指定的最大值
|[WithValidatorHandleTypeLengthNot](#WithValidatorHandleTypeLengthNot)|校验组合成员类型数量是否不等于指定的值
|[WithValidatorHandleContinuous](#WithValidatorHandleContinuous)|校验组合成员是否连续
|[WithValidatorHandleContinuousNot](#WithValidatorHandleContinuousNot)|校验组合成员是否不连续
|[WithValidatorHandleGroupContinuous](#WithValidatorHandleGroupContinuous)|校验组合成员是否能够按类型分组并且连续
|[WithValidatorHandleGroupContinuousN](#WithValidatorHandleGroupContinuousN)|校验组合成员是否能够按分组为 n 组类型并且连续
|[WithValidatorHandleNCarryM](#WithValidatorHandleNCarryM)| 校验组合成员是否匹配 N 携带相同的 M 的组合
|[WithValidatorHandleNCarryIndependentM](#WithValidatorHandleNCarryIndependentM)|校验组合成员是否匹配 N 携带独立的 M 的组合
我们的组合函数使用了特定的算法,以便快速地生成和处理组合。这些算法被设计为能够处理各种复杂的组合问题,以确保结果的准确性。
### 易于使用
> 结构体定义
`Combination` 包的设计目标是使得开发者可以轻松地使用它。我们提供了清晰的文档和指南,帮助开发者理解和使用我们的组合函数。
|结构体|描述
|:--|:--
|[Combination](#combination)|用于从多个匹配器内提取组合的数据结构
|[Option](#option)|组合器选项
|[Item](#item)|暂无描述...
|[Matcher](#matcher)|用于从一组数据内提取组合的数据结构
|[MatcherOption](#matcheroption)|匹配器选项
|[Validator](#validator)|用于对组合进行验证的校验器
|[ValidatorOption](#validatoroption)|暂无描述...
## 用途
</details>
`Combination` 包可以在处理任何涉及到组合的问题时使用。无论是在数据分析、机器学习、算法设计,还是在其他需要处理组合的场景中,`Combination` 包都能够提供帮助。
我们鼓励开发者探索 `Combination` 包的可能用途,并分享他们的经验和发现。
#### func NewCombination(options ...Option[T]) *Combination[T]
<span id="NewCombination"></span>
> 创建一个新的组合器
***
#### func WithEvaluation(evaluate func (items []T) float64) Option[T]
<span id="WithEvaluation"></span>
> 设置组合评估函数
> - 用于对组合进行评估,返回一个分值的评价函数
> - 通过该选项将设置所有匹配器的默认评估函数为该函数
> - 通过匹配器选项 WithMatcherEvaluation 可以覆盖该默认评估函数
> - 默认的评估函数将返回一个随机数
***
#### func NewMatcher(options ...MatcherOption[T]) *Matcher[T]
<span id="NewMatcher"></span>
> 创建一个新的匹配器
***
#### func WithMatcherEvaluation(evaluate func (items []T) float64) MatcherOption[T]
<span id="WithMatcherEvaluation"></span>
> 设置匹配器评估函数
> - 用于对组合进行评估,返回一个分值的评价函数
> - 通过该选项将覆盖匹配器的默认(WithEvaluation)评估函数
***
#### func WithMatcherLeastLength(length int) MatcherOption[T]
<span id="WithMatcherLeastLength"></span>
> 通过匹配最小长度的组合创建匹配器
> - length: 组合的长度,表示需要匹配的组合最小数量
***
#### func WithMatcherLength(length int) MatcherOption[T]
<span id="WithMatcherLength"></span>
> 通过匹配长度的组合创建匹配器
> - length: 组合的长度,表示需要匹配的组合数量
***
#### func WithMatcherMostLength(length int) MatcherOption[T]
<span id="WithMatcherMostLength"></span>
> 通过匹配最大长度的组合创建匹配器
> - length: 组合的长度,表示需要匹配的组合最大数量
***
#### func WithMatcherIntervalLength(min int, max int) MatcherOption[T]
<span id="WithMatcherIntervalLength"></span>
> 通过匹配长度区间的组合创建匹配器
> - min: 组合的最小长度,表示需要匹配的组合最小数量
> - max: 组合的最大长度,表示需要匹配的组合最大数量
***
#### func WithMatcherContinuity(getIndex func (item T) Index) MatcherOption[T]
<span id="WithMatcherContinuity"></span>
> 通过匹配连续的组合创建匹配器
> - index: 用于获取组合中元素的索引值,用于判断是否连续
***
#### func WithMatcherSame(count int, getType func (item T) E) MatcherOption[T]
<span id="WithMatcherSame"></span>
> 通过匹配相同的组合创建匹配器
> - count: 组合中相同元素的数量,当 count <= 0 时,表示相同元素的数量不限
> - getType: 用于获取组合中元素的类型,用于判断是否相同
***
#### func WithMatcherNCarryM(n int, m int, getType func (item T) E) MatcherOption[T]
<span id="WithMatcherNCarryM"></span>
> 通过匹配 N 携带 M 的组合创建匹配器
> - n: 组合中元素的数量表示需要匹配的组合数量n 的类型需要全部相同
> - m: 组合中元素的数量表示需要匹配的组合数量m 的类型需要全部相同
> - getType: 用于获取组合中元素的类型,用于判断是否相同
***
#### func WithMatcherNCarryIndependentM(n int, m int, getType func (item T) E) MatcherOption[T]
<span id="WithMatcherNCarryIndependentM"></span>
> 通过匹配 N 携带独立 M 的组合创建匹配器
> - n: 组合中元素的数量表示需要匹配的组合数量n 的类型需要全部相同
> - m: 组合中元素的数量表示需要匹配的组合数量m 的类型无需全部相同
> - getType: 用于获取组合中元素的类型,用于判断是否相同
***
#### func NewValidator(options ...ValidatorOption[T]) *Validator[T]
<span id="NewValidator"></span>
> 创建一个新的校验器
***
#### func WithValidatorHandle(handle func (items []T) bool) ValidatorOption[T]
<span id="WithValidatorHandle"></span>
> 通过特定的验证函数对组合进行验证
***
#### func WithValidatorHandleLength(length int) ValidatorOption[T]
<span id="WithValidatorHandleLength"></span>
> 校验组合的长度是否符合要求
***
#### func WithValidatorHandleLengthRange(min int, max int) ValidatorOption[T]
<span id="WithValidatorHandleLengthRange"></span>
> 校验组合的长度是否在指定的范围内
***
#### func WithValidatorHandleLengthMin(min int) ValidatorOption[T]
<span id="WithValidatorHandleLengthMin"></span>
> 校验组合的长度是否大于等于指定的最小值
***
#### func WithValidatorHandleLengthMax(max int) ValidatorOption[T]
<span id="WithValidatorHandleLengthMax"></span>
> 校验组合的长度是否小于等于指定的最大值
***
#### func WithValidatorHandleLengthNot(length int) ValidatorOption[T]
<span id="WithValidatorHandleLengthNot"></span>
> 校验组合的长度是否不等于指定的值
***
#### func WithValidatorHandleTypeLength(length int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleTypeLength"></span>
> 校验组合成员类型数量是否为指定的值
***
#### func WithValidatorHandleTypeLengthRange(min int, max int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleTypeLengthRange"></span>
> 校验组合成员类型数量是否在指定的范围内
***
#### func WithValidatorHandleTypeLengthMin(min int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleTypeLengthMin"></span>
> 校验组合成员类型数量是否大于等于指定的最小值
***
#### func WithValidatorHandleTypeLengthMax(max int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleTypeLengthMax"></span>
> 校验组合成员类型数量是否小于等于指定的最大值
***
#### func WithValidatorHandleTypeLengthNot(length int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleTypeLengthNot"></span>
> 校验组合成员类型数量是否不等于指定的值
***
#### func WithValidatorHandleContinuous(getIndex func (item T) Index) ValidatorOption[T]
<span id="WithValidatorHandleContinuous"></span>
> 校验组合成员是否连续
***
#### func WithValidatorHandleContinuousNot(getIndex func (item T) Index) ValidatorOption[T]
<span id="WithValidatorHandleContinuousNot"></span>
> 校验组合成员是否不连续
***
#### func WithValidatorHandleGroupContinuous(getType func (item T) E, getIndex func (item T) Index) ValidatorOption[T]
<span id="WithValidatorHandleGroupContinuous"></span>
> 校验组合成员是否能够按类型分组并且连续
***
#### func WithValidatorHandleGroupContinuousN(n int, getType func (item T) E, getIndex func (item T) Index) ValidatorOption[T]
<span id="WithValidatorHandleGroupContinuousN"></span>
> 校验组合成员是否能够按分组为 n 组类型并且连续
***
#### func WithValidatorHandleNCarryM(n int, m int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleNCarryM"></span>
> 校验组合成员是否匹配 N 携带相同的 M 的组合
> - n: 组合中元素的数量表示需要匹配的组合数量n 的类型需要全部相同
> - m: 组合中元素的数量表示需要匹配的组合数量m 的类型需要全部相同
> - getType: 用于获取组合中元素的类型,用于判断是否相同
***
#### func WithValidatorHandleNCarryIndependentM(n int, m int, getType func (item T) E) ValidatorOption[T]
<span id="WithValidatorHandleNCarryIndependentM"></span>
> 校验组合成员是否匹配 N 携带独立的 M 的组合
> - n: 组合中元素的数量表示需要匹配的组合数量n 的类型需要全部相同
> - m: 组合中元素的数量表示需要匹配的组合数量m 的类型无需全部相同
> - getType: 用于获取组合中元素的类型,用于判断是否相同
***
### Combination
用于从多个匹配器内提取组合的数据结构
```go
type Combination[T Item] struct {
evaluate func([]T) float64
matchers map[string]*Matcher[T]
priority []string
}
```
#### func (*Combination) NewMatcher(name string, options ...MatcherOption[T]) *Combination[T]
> 添加一个新的匹配器
***
#### func (*Combination) AddMatcher(name string, matcher *Matcher[T]) *Combination[T]
> 添加一个匹配器
***
#### func (*Combination) RemoveMatcher(name string) *Combination[T]
> 移除一个匹配器
***
#### func (*Combination) Combinations(items []T) (result [][]T)
> 从一组数据中提取所有符合匹配器规则的组合
***
#### func (*Combination) CombinationsToName(items []T) (result map[string][][]T)
> 从一组数据中提取所有符合匹配器规则的组合,并返回匹配器名称
***
#### func (*Combination) Best(items []T) (name string, result []T)
> 从一组数据中提取符合匹配器规则的最佳组合
***
#### func (*Combination) Worst(items []T) (name string, result []T)
> 从一组数据中提取符合匹配器规则的最差组合
***
### Option
组合器选项
```go
type Option[T Item] struct{}
```
### Item
```go
type Item struct{}
```
### Matcher
用于从一组数据内提取组合的数据结构
```go
type Matcher[T Item] struct {
evaluate func(items []T) float64
filter []func(items []T) [][]T
}
```
#### func (*Matcher) AddFilter(filter func (items []T) [][]T)
> 添加一个筛选器
> - 筛选器用于对组合进行筛选,返回一个二维数组,每个数组内的元素都是一个组合
***
#### func (*Matcher) Combinations(items []T) [][]T
> 从一组数据中提取所有符合筛选器规则的组合
***
#### func (*Matcher) Best(items []T) []T
> 从一组数据中提取符筛选器规则的最佳组合
***
#### func (*Matcher) Worst(items []T) []T
> 从一组数据中提取符筛选器规则的最差组合
***
### MatcherOption
匹配器选项
```go
type MatcherOption[T Item] struct{}
```
### Validator
用于对组合进行验证的校验器
```go
type Validator[T Item] struct {
vh []func(items []T) bool
}
```
#### func (*Validator) Validate(items []T) bool
> 校验组合是否符合要求
***
### ValidatorOption
```go
type ValidatorOption[T Item] struct{}
```

View File

@ -1,5 +1,57 @@
# Compress
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/compress)
compress 提供了一些用于压缩和解压缩数据的函数。
该包提供了GZIP、ZIP和TAR的压缩和解压缩实现。开发者可以使用它来快速进行数据的压缩和解压缩。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/compress)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[GZipCompress](#GZipCompress)|对数据进行GZip压缩返回bytes.Buffer和错误信息
|[GZipUnCompress](#GZipUnCompress)|对已进行GZip压缩的数据进行解压缩返回字节数组及错误信息
|[TARCompress](#TARCompress)|对数据进行TAR压缩返回bytes.Buffer和错误信息
|[TARUnCompress](#TARUnCompress)|对已进行TAR压缩的数据进行解压缩返回字节数组及错误信息
|[ZIPCompress](#ZIPCompress)|对数据进行ZIP压缩返回bytes.Buffer和错误信息
|[ZIPUnCompress](#ZIPUnCompress)|对已进行ZIP压缩的数据进行解压缩返回字节数组及错误信息
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func GZipCompress(data []byte) bytes.Buffer, error
<span id="GZipCompress"></span>
> 对数据进行GZip压缩返回bytes.Buffer和错误信息
***
#### func GZipUnCompress(dataByte []byte) []byte, error
<span id="GZipUnCompress"></span>
> 对已进行GZip压缩的数据进行解压缩返回字节数组及错误信息
***
#### func TARCompress(data []byte) bytes.Buffer, error
<span id="TARCompress"></span>
> 对数据进行TAR压缩返回bytes.Buffer和错误信息
***
#### func TARUnCompress(dataByte []byte) []byte, error
<span id="TARUnCompress"></span>
> 对已进行TAR压缩的数据进行解压缩返回字节数组及错误信息
***
#### func ZIPCompress(data []byte) bytes.Buffer, error
<span id="ZIPCompress"></span>
> 对数据进行ZIP压缩返回bytes.Buffer和错误信息
***
#### func ZIPUnCompress(dataByte []byte) []byte, error
<span id="ZIPUnCompress"></span>
> 对已进行ZIP压缩的数据进行解压缩返回字节数组及错误信息
***

77
utils/crypto/README.md Normal file
View File

@ -0,0 +1,77 @@
# Crypto
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/crypto)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[EncryptBase64](#EncryptBase64)|对数据进行Base64编码
|[DecodedBase64](#DecodedBase64)|对数据进行Base64解码
|[EncryptCRC32](#EncryptCRC32)|对字符串进行CRC加密并返回其结果。
|[DecodedCRC32](#DecodedCRC32)|对字节数组进行CRC加密并返回其结果。
|[EncryptMD5](#EncryptMD5)|对字符串进行MD5加密并返回其结果。
|[DecodedMD5](#DecodedMD5)|对字节数组进行MD5加密并返回其结果。
|[EncryptSHA1](#EncryptSHA1)|对字符串进行SHA1加密并返回其结果。
|[DecodedSHA1](#DecodedSHA1)|对字节数组进行SHA1加密并返回其结果。
|[EncryptSHA256](#EncryptSHA256)|对字符串进行SHA256加密并返回其结果。
|[DecodedSHA256](#DecodedSHA256)|对字节数组进行SHA256加密并返回其结果。
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func EncryptBase64(data []byte) string
<span id="EncryptBase64"></span>
> 对数据进行Base64编码
***
#### func DecodedBase64(data string) []byte, error
<span id="DecodedBase64"></span>
> 对数据进行Base64解码
***
#### func EncryptCRC32(str string) uint32
<span id="EncryptCRC32"></span>
> 对字符串进行CRC加密并返回其结果。
***
#### func DecodedCRC32(data []byte) uint32
<span id="DecodedCRC32"></span>
> 对字节数组进行CRC加密并返回其结果。
***
#### func EncryptMD5(str string) string
<span id="EncryptMD5"></span>
> 对字符串进行MD5加密并返回其结果。
***
#### func DecodedMD5(data []byte) string
<span id="DecodedMD5"></span>
> 对字节数组进行MD5加密并返回其结果。
***
#### func EncryptSHA1(str string) string
<span id="EncryptSHA1"></span>
> 对字符串进行SHA1加密并返回其结果。
***
#### func DecodedSHA1(data []byte) string
<span id="DecodedSHA1"></span>
> 对字节数组进行SHA1加密并返回其结果。
***
#### func EncryptSHA256(str string) string
<span id="EncryptSHA256"></span>
> 对字符串进行SHA256加密并返回其结果。
***
#### func DecodedSHA256(data []byte) string
<span id="DecodedSHA256"></span>
> 对字节数组进行SHA256加密并返回其结果。
***

128
utils/deck/README.md Normal file
View File

@ -0,0 +1,128 @@
# Deck
deck 包中的内容用于针对一堆内容的管理,适用但不限于牌堆、麻将牌堆等情况。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/deck)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewDeck](#NewDeck)|创建一个新的甲板
|[NewGroup](#NewGroup)|创建一个新的组
> 结构体定义
|结构体|描述
|:--|:--
|[Deck](#deck)|甲板,用于针对一堆 Group 进行管理的数据结构
|[Group](#group)|甲板中的组,用于针对一堆内容进行管理的数据结构
|[Item](#item)|甲板成员
</details>
#### func NewDeck() *Deck[I]
<span id="NewDeck"></span>
> 创建一个新的甲板
***
#### func NewGroup(guid int64, fillHandle func (guid int64) []I) *Group[I]
<span id="NewGroup"></span>
> 创建一个新的组
***
### Deck
甲板,用于针对一堆 Group 进行管理的数据结构
```go
type Deck[I Item] struct {
groups map[int64]*Group[I]
sort []int64
}
```
#### func (*Deck) AddGroup(group *Group[I])
> 将一个组添加到甲板中
***
#### func (*Deck) RemoveGroup(guid int64)
> 移除甲板中的一个组
***
#### func (*Deck) GetCount() int
> 获取甲板中的组数量
***
#### func (*Deck) GetGroups() map[int64]*Group[I]
> 获取所有组
***
#### func (*Deck) GetGroupsSlice() []*Group[I]
> 获取所有组
***
#### func (*Deck) GetNext(guid int64) *Group[I]
> 获取特定组的下一个组
***
#### func (*Deck) GetPrev(guid int64) *Group[I]
> 获取特定组的上一个组
***
### Group
甲板中的组,用于针对一堆内容进行管理的数据结构
```go
type Group[I Item] struct {
guid int64
fillHandle func(guid int64) []I
items []I
}
```
#### func (*Group) GetGuid() int64
> 获取组的 guid
***
#### func (*Group) Fill()
> 将该组的数据填充为 WithGroupFillHandle 中设置的内容
***
#### func (*Group) Pop() (item I)
> 从顶部获取一个内容
***
#### func (*Group) PopN(n int) (items []I)
> 从顶部获取指定数量的内容
***
#### func (*Group) PressOut() (item I)
> 从底部压出一个内容
***
#### func (*Group) PressOutN(n int) (items []I)
> 从底部压出指定数量的内容
***
#### func (*Group) Push(item I)
> 向顶部压入一个内容
***
#### func (*Group) PushN(items []I)
> 向顶部压入指定数量的内容
***
#### func (*Group) Insert(item I)
> 向底部插入一个内容
***
#### func (*Group) InsertN(items []I)
> 向底部插入指定数量的内容
***
#### func (*Group) Pull(index int) (item I)
> 从特定位置拔出一个内容
***
#### func (*Group) Thrust(index int, item I)
> 向特定位置插入一个内容
***
#### func (*Group) IsFree() bool
> 检查组是否为空
***
#### func (*Group) GetCount() int
> 获取组中剩余的内容数量
***
#### func (*Group) GetItem(index int) I
> 获取组中的指定内容
***
### Item
甲板成员
```go
type Item struct{}
```

93
utils/file/README.md Normal file
View File

@ -0,0 +1,93 @@
# File
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/file)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[PathExist](#PathExist)|路径是否存在
|[IsDir](#IsDir)|路径是否是文件夹
|[WriterFile](#WriterFile)|向特定文件写入内容
|[ReadOnce](#ReadOnce)|单次读取文件
|[ReadBlockHook](#ReadBlockHook)|分块读取文件
|[ReadLine](#ReadLine)|分行读取文件
|[LineCount](#LineCount)|统计文件行数
|[Paths](#Paths)|获取指定目录下的所有文件路径
|[ReadLineWithParallel](#ReadLineWithParallel)|并行的分行读取文件并行处理,处理过程中会将每一行的内容传入 handlerFunc 中进行处理
|[FindLineChunks](#FindLineChunks)|查找文件按照每行划分的分块,每个分块的大小将在 chunkSize 和分割后的分块距离行首及行尾的距离中范围内
|[FindLineChunksByOffset](#FindLineChunksByOffset)|该函数与 FindLineChunks 类似,不同的是该函数可以指定 offset 从指定位置开始读取文件
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func PathExist(path string) bool, error
<span id="PathExist"></span>
> 路径是否存在
***
#### func IsDir(path string) bool, error
<span id="IsDir"></span>
> 路径是否是文件夹
***
#### func WriterFile(filePath string, content []byte) error
<span id="WriterFile"></span>
> 向特定文件写入内容
***
#### func ReadOnce(filePath string) []byte, error
<span id="ReadOnce"></span>
> 单次读取文件
> - 一次性对整个文件进行读取,小文件读取可以很方便的一次性将文件内容读取出来,而大文件读取会造成性能影响。
***
#### func ReadBlockHook(filePath string, bufferSize int, hook func (data []byte)) error
<span id="ReadBlockHook"></span>
> 分块读取文件
> - 将filePath路径对应的文件数据并将读到的每一部分传入hook函数中当过程中如果产生错误则会返回error。
> - 分块读取可以在读取速度和内存消耗之间有一个很好的平衡。
***
#### func ReadLine(filePath string, hook func (line string)) error
<span id="ReadLine"></span>
> 分行读取文件
> - 将filePath路径对应的文件数据并将读到的每一行传入hook函数中当过程中如果产生错误则会返回error。
***
#### func LineCount(filePath string) int
<span id="LineCount"></span>
> 统计文件行数
***
#### func Paths(dir string) []string
<span id="Paths"></span>
> 获取指定目录下的所有文件路径
> - 包括了子目录下的文件
> - 不包含目录
***
#### func ReadLineWithParallel(filename string, chunkSize int64, handlerFunc func ( string), start ...int64) (n int64, err error)
<span id="ReadLineWithParallel"></span>
> 并行的分行读取文件并行处理,处理过程中会将每一行的内容传入 handlerFunc 中进行处理
> - 由于是并行处理,所以处理过程中的顺序是不确定的。
> - 可通过 start 参数指定开始读取的位置,如果不指定则从文件开头开始读取。
***
#### func FindLineChunks(file *os.File, chunkSize int64) [][2]int64
<span id="FindLineChunks"></span>
> 查找文件按照每行划分的分块,每个分块的大小将在 chunkSize 和分割后的分块距离行首及行尾的距离中范围内
> - 使用该函数得到的分块是完整的行,不会出现行被分割的情况
> - 当过程中发生错误将会发生 panic
> - 返回值的成员是一个长度为 2 的数组,第一个元素是分块的起始位置,第二个元素是分块的结束位置
***
#### func FindLineChunksByOffset(file *os.File, offset int64, chunkSize int64) [][2]int64
<span id="FindLineChunksByOffset"></span>
> 该函数与 FindLineChunks 类似,不同的是该函数可以指定 offset 从指定位置开始读取文件
***

82
utils/fsm/README.md Normal file
View File

@ -0,0 +1,82 @@
# Fsm
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/fsm)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewFSM](#NewFSM)|创建一个新的状态机
|[WithEnterBeforeEvent](#WithEnterBeforeEvent)|设置状态进入前的回调
|[WithEnterAfterEvent](#WithEnterAfterEvent)|设置状态进入后的回调
|[WithUpdateEvent](#WithUpdateEvent)|设置状态内刷新的回调
|[WithExitBeforeEvent](#WithExitBeforeEvent)|设置状态退出前的回调
|[WithExitAfterEvent](#WithExitAfterEvent)|设置状态退出后的回调
> 结构体定义
|结构体|描述
|:--|:--
|[FSM](#fsm)|状态机
|[Option](#option)|暂无描述...
</details>
#### func NewFSM(data Data) *FSM[State, Data]
<span id="NewFSM"></span>
> 创建一个新的状态机
***
#### func WithEnterBeforeEvent(fn func (state *FSM[State, Data])) Option[State, Data]
<span id="WithEnterBeforeEvent"></span>
> 设置状态进入前的回调
> - 在首次设置状态时,状态机本身的当前状态为零值状态
***
#### func WithEnterAfterEvent(fn func (state *FSM[State, Data])) Option[State, Data]
<span id="WithEnterAfterEvent"></span>
> 设置状态进入后的回调
***
#### func WithUpdateEvent(fn func (state *FSM[State, Data])) Option[State, Data]
<span id="WithUpdateEvent"></span>
> 设置状态内刷新的回调
***
#### func WithExitBeforeEvent(fn func (state *FSM[State, Data])) Option[State, Data]
<span id="WithExitBeforeEvent"></span>
> 设置状态退出前的回调
> - 该阶段状态机的状态为退出前的状态,而非新的状态
***
#### func WithExitAfterEvent(fn func (state *FSM[State, Data])) Option[State, Data]
<span id="WithExitAfterEvent"></span>
> 设置状态退出后的回调
> - 该阶段状态机的状态为新的状态,而非退出前的状态
***
### FSM
状态机
```go
type FSM[State comparable, Data any] struct {
prev *State
current *State
data Data
states map[State]struct{}
enterBeforeEventHandles map[State][]func(state *FSM[State, Data])
enterAfterEventHandles map[State][]func(state *FSM[State, Data])
updateEventHandles map[State][]func(state *FSM[State, Data])
exitBeforeEventHandles map[State][]func(state *FSM[State, Data])
exitAfterEventHandles map[State][]func(state *FSM[State, Data])
}
```
### Option
```go
type Option[State comparable, Data any] struct{}
```

View File

@ -0,0 +1,127 @@
# Astgo
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/astgo)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewPackage](#NewPackage)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[Comment](#comment)|暂无描述...
|[Field](#field)|暂无描述...
|[File](#file)|暂无描述...
|[Function](#function)|暂无描述...
|[Package](#package)|暂无描述...
|[Struct](#struct)|暂无描述...
|[Type](#type)|暂无描述...
</details>
#### func NewPackage(dir string) *Package, error
<span id="NewPackage"></span>
***
### Comment
```go
type Comment struct {
Comments []string
Clear []string
}
```
### Field
```go
type Field struct {
Anonymous bool
Name string
Type *Type
Comments *Comment
}
```
### File
```go
type File struct {
af *ast.File
owner *Package
FilePath string
Structs []*Struct
Functions []*Function
Comment *Comment
}
```
#### func (*File) Package() string
***
### Function
```go
type Function struct {
Name string
Internal bool
Generic []*Field
Params []*Field
Results []*Field
Comments *Comment
Struct *Field
IsExample bool
IsTest bool
IsBenchmark bool
Test bool
}
```
### Package
```go
type Package struct {
Dir string
Name string
Dirs []string
Files []*File
}
```
#### func (*Package) StructFunc(name string) []*Function
***
#### func (*Package) PackageFunc() []*Function
***
#### func (*Package) Structs() []*Struct
***
#### func (*Package) FileComments() *Comment
***
### Struct
```go
type Struct struct {
Name string
Internal bool
Comments *Comment
Generic []*Field
Fields []*Field
Test bool
}
```
### Type
```go
type Type struct {
expr ast.Expr
Sign string
IsPointer bool
Name string
}
```

View File

@ -0,0 +1,30 @@
package astgo
import (
"go/ast"
"strings"
)
func newComment(cg *ast.CommentGroup) *Comment {
c := &Comment{}
if cg == nil {
return c
}
for i, comment := range cg.List {
c.Comments = append(c.Comments, comment.Text)
cc := strings.TrimPrefix(strings.Replace(comment.Text, "// ", "//", 1), "//")
if i == 0 {
s := strings.SplitN(cc, " ", 2)
if len(s) == 2 {
cc = s[1]
}
}
c.Clear = append(c.Clear, cc)
}
return c
}
type Comment struct {
Comments []string
Clear []string
}

View File

@ -0,0 +1,33 @@
package astgo
import (
"go/ast"
)
func newField(field *ast.Field) []*Field {
if len(field.Names) == 0 {
return []*Field{{
Anonymous: true,
Type: newType(field.Type),
Comments: newComment(field.Comment),
}}
} else {
var fs []*Field
for _, name := range field.Names {
fs = append(fs, &Field{
Anonymous: false,
Name: name.String(),
Type: newType(field.Type),
Comments: newComment(field.Comment),
})
}
return fs
}
}
type Field struct {
Anonymous bool // 匿名字段
Name string // 字段名称
Type *Type // 字段类型
Comments *Comment // 注释
}

View File

@ -0,0 +1,50 @@
package astgo
import (
"go/ast"
"go/parser"
"go/token"
"strings"
)
func newFile(owner *Package, filePath string) (*File, error) {
af, err := parser.ParseFile(token.NewFileSet(), filePath, nil, parser.ParseComments)
if err != nil {
return nil, err
}
f := &File{
af: af,
owner: owner,
FilePath: filePath,
Comment: newComment(af.Doc),
}
for _, decl := range af.Decls {
switch typ := decl.(type) {
case *ast.FuncDecl:
f.Functions = append(f.Functions, newFunction(typ))
case *ast.GenDecl:
_, ok := typ.Specs[0].(*ast.TypeSpec)
if ok {
s := newStruct(typ)
f.Structs = append(f.Structs, s)
if strings.HasSuffix(filePath, "_test.go") {
s.Test = true
}
}
}
}
return f, nil
}
type File struct {
af *ast.File // 抽象语法树文件
owner *Package // 所属包
FilePath string // 文件路径
Structs []*Struct // 包含的结构体
Functions []*Function // 包含的函数
Comment *Comment // 文件注释
}
func (f *File) Package() string {
return f.af.Name.String()
}

View File

@ -0,0 +1,51 @@
package astgo
import (
"go/ast"
"strings"
)
func newFunction(astFunc *ast.FuncDecl) *Function {
f := &Function{
Name: astFunc.Name.String(),
Comments: newComment(astFunc.Doc),
}
f.IsTest = strings.HasPrefix(f.Name, "Test")
f.IsBenchmark = strings.HasPrefix(f.Name, "Benchmark")
f.IsExample = strings.HasPrefix(f.Name, "Example")
f.Test = f.IsTest || f.IsBenchmark || f.IsExample
f.Internal = f.Name[0] >= 97 && f.Name[0] <= 122
if astFunc.Type.TypeParams != nil {
for _, field := range astFunc.Type.TypeParams.List {
f.Generic = append(f.Generic, newField(field)...)
}
}
if astFunc.Type.Params != nil {
for _, field := range astFunc.Type.Params.List {
f.Params = append(f.Params, newField(field)...)
}
}
if astFunc.Type.Results != nil {
for _, field := range astFunc.Type.Results.List {
f.Results = append(f.Results, newField(field)...)
}
}
if astFunc.Recv != nil {
f.Struct = newField(astFunc.Recv.List[0])[0]
}
return f
}
type Function struct {
Name string // 函数名
Internal bool // 内部函数
Generic []*Field // 泛型定义
Params []*Field // 参数字段
Results []*Field // 返回值字段
Comments *Comment // 注释
Struct *Field // 结构体函数对应的结构体字段
IsExample bool // 是否为测试用例
IsTest bool // 是否为单元测试
IsBenchmark bool // 是否为基准测试
Test bool // 是否为测试函数
}

View File

@ -0,0 +1,40 @@
package astgo
import (
"go/ast"
"strings"
)
func newName(expr ast.Expr) string {
var str strings.Builder
switch e := expr.(type) {
//case *ast.KeyValueExpr:
//case *ast.ArrayType:
//case *ast.StructType:
//case *ast.FuncType:
//case *ast.InterfaceType:
//case *ast.MapType:
//case *ast.ChanType:
case *ast.Ident:
str.WriteString(e.Name)
case *ast.Ellipsis:
str.WriteString(newName(e.Elt))
//case *ast.BasicLit:
//case *ast.FuncLit:
//case *ast.CompositeLit:
//case *ast.ParenExpr:
case *ast.SelectorExpr:
str.WriteString(newName(e.X))
case *ast.IndexExpr:
str.WriteString(newName(e.X))
case *ast.IndexListExpr:
case *ast.SliceExpr:
case *ast.TypeAssertExpr:
case *ast.CallExpr:
case *ast.StarExpr:
str.WriteString(newName(e.X))
case *ast.UnaryExpr:
case *ast.BinaryExpr:
}
return str.String()
}

View File

@ -0,0 +1,94 @@
package astgo
import (
"errors"
"os"
"path/filepath"
)
func NewPackage(dir string) (*Package, error) {
pkg := &Package{Dir: dir}
fs, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
for _, f := range fs {
path := filepath.Join(pkg.Dir, f.Name())
if f.IsDir() {
pkg.Dirs = append(pkg.Dirs, path)
continue
}
if filepath.Ext(path) != ".go" {
continue
}
f, err := newFile(pkg, path)
if err != nil {
continue
}
pkg.Files = append(pkg.Files, f)
}
if len(pkg.Files) == 0 {
return nil, errors.New("not found go ext file")
}
pkg.Name = pkg.Files[0].Package()
return pkg, nil
}
type Package struct {
Dir string
Name string
Dirs []string
Files []*File
}
func (p *Package) StructFunc(name string) []*Function {
var fs []*Function
for _, file := range p.Files {
for _, function := range file.Functions {
if function.Struct == nil {
continue
}
if function.Struct.Type.Name == name {
fs = append(fs, function)
}
}
}
return fs
}
func (p *Package) PackageFunc() []*Function {
var fs []*Function
for _, file := range p.Files {
for _, function := range file.Functions {
if function.Struct == nil {
fs = append(fs, function)
}
}
}
return fs
}
func (p *Package) Structs() []*Struct {
var structs []*Struct
for _, file := range p.Files {
for _, s := range file.Structs {
structs = append(structs, s)
}
}
return structs
}
func (p *Package) FileComments() *Comment {
var comment = newComment(nil)
for _, file := range p.Files {
for _, c := range file.Comment.Comments {
comment.Comments = append(comment.Comments, c)
}
for _, c := range file.Comment.Clear {
comment.Clear = append(comment.Clear, c)
}
}
return comment
}

View File

@ -0,0 +1,16 @@
package astgo_test
import (
"fmt"
"github.com/kercylan98/minotaur/utils/generator/astgo"
"github.com/kercylan98/minotaur/utils/super"
"testing"
)
func TestNewPackage(t *testing.T) {
p, err := astgo.NewPackage(`/Users/kercylan/Coding.localized/Go/minotaur/server`)
if err != nil {
panic(err)
}
fmt.Println(string(super.MarshalIndentJSON(p, "", " ")))
}

View File

@ -0,0 +1,36 @@
package astgo
import (
"go/ast"
)
func newStruct(astGen *ast.GenDecl) *Struct {
astTypeSpec := astGen.Specs[0].(*ast.TypeSpec)
s := &Struct{
Name: astTypeSpec.Name.String(),
Comments: newComment(astGen.Doc),
}
s.Internal = s.Name[0] >= 97 && s.Name[0] <= 122
if astTypeSpec.TypeParams != nil {
for _, field := range astTypeSpec.TypeParams.List {
s.Generic = append(s.Generic, newField(field)...)
}
}
t, ok := astTypeSpec.Type.(*ast.StructType)
if ok && t.Fields != nil {
for _, field := range t.Fields.List {
s.Fields = append(s.Fields, newField(field)...)
}
}
return s
}
type Struct struct {
Name string // 结构体名称
Internal bool // 内部结构体
Comments *Comment // 注释
Generic []*Field // 泛型类型
Fields []*Field // 结构体字段
Test bool // 是否是测试结构体
}

View File

@ -0,0 +1,129 @@
package astgo
import (
"fmt"
"go/ast"
"strings"
)
func newType(expr ast.Expr) *Type {
var typ = &Type{
expr: expr,
Name: newName(expr),
}
var str strings.Builder
switch e := typ.expr.(type) {
case *ast.KeyValueExpr:
k, v := newType(e.Key), newType(e.Value)
str.WriteString(fmt.Sprintf("%s : %s", k.Sign, v.Sign))
case *ast.ArrayType:
isSlice := e.Len == nil
str.WriteByte('[')
if !isSlice {
length := newType(e.Len)
str.WriteString(length.Sign)
}
str.WriteByte(']')
element := newType(e.Elt)
str.WriteString(element.Sign)
case *ast.StructType:
str.WriteString("struct {")
if e.Fields != nil && len(e.Fields.List) > 0 {
str.WriteString("\n")
for _, field := range e.Fields.List {
f := newField(field)[0]
str.WriteString(fmt.Sprintf("%s %s\n", f.Name, f.Type.Sign))
}
}
str.WriteString("}")
case *ast.FuncType:
var handler = func(fls *ast.FieldList) string {
var s string
if fls != nil {
var brackets bool
var params []string
for _, field := range fls.List {
f := newField(field)[0]
if !f.Anonymous {
brackets = true
}
params = append(params, fmt.Sprintf("%s %s", f.Name, f.Type.Sign))
}
s = strings.Join(params, ", ")
if brackets {
s = "(" + s + ")"
}
}
return s
}
str.WriteString(strings.TrimSpace(fmt.Sprintf("func %s %s", func() string {
f := handler(e.Params)
if len(strings.TrimSpace(f)) == 0 {
return "()"
}
if !strings.HasPrefix(f, "(") {
return "(" + f + ")"
}
return f
}(), handler(e.Results))))
case *ast.InterfaceType:
str.WriteString("interface {")
if e.Methods != nil && len(e.Methods.List) > 0 {
str.WriteString("\n")
for _, field := range e.Methods.List {
f := newField(field)[0]
str.WriteString(fmt.Sprintf("%s\n", f.Type.Sign))
}
}
str.WriteString("}")
case *ast.MapType:
k, v := newType(e.Key), newType(e.Value)
str.WriteString(fmt.Sprintf("map[%s]%s", k.Sign, v.Sign))
case *ast.ChanType:
t := newType(e.Value)
str.WriteString(fmt.Sprintf("chan %s", t.Sign))
case *ast.Ident:
str.WriteString(e.Name)
case *ast.Ellipsis:
element := newType(e.Elt)
str.WriteString(fmt.Sprintf("...%s", element.Sign))
case *ast.BasicLit:
str.WriteString(e.Value)
//case *ast.FuncLit:
//case *ast.CompositeLit:
//case *ast.ParenExpr:
case *ast.SelectorExpr:
t := newType(e.X)
str.WriteString(fmt.Sprintf("%s.%s", t.Sign, e.Sel.Name))
case *ast.IndexExpr:
t := newType(e.X)
generic := newType(e.Index)
str.WriteString(fmt.Sprintf("%s[%s]", t.Sign, generic.Sign))
case *ast.IndexListExpr:
self := newType(e.X)
var genericStr []string
for _, index := range e.Indices {
g := newType(index)
genericStr = append(genericStr, g.Sign)
}
str.WriteString(fmt.Sprintf("%s[%s]", self.Sign, strings.Join(genericStr, ", ")))
case *ast.SliceExpr:
case *ast.TypeAssertExpr:
case *ast.CallExpr:
case *ast.StarExpr:
typ.IsPointer = true
t := newType(e.X)
str.WriteString(fmt.Sprintf("*%s", t.Sign))
case *ast.UnaryExpr:
case *ast.BinaryExpr:
}
typ.Sign = str.String()
return typ
}
type Type struct {
expr ast.Expr
Sign string // 类型签名
IsPointer bool // 指针类型
Name string // 类型名称
}

View File

@ -0,0 +1,43 @@
# Genreadme
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/genreadme)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[New](#New)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[Builder](#builder)|暂无描述...
</details>
#### func New(pkgDirPath string, output string) *Builder, error
<span id="New"></span>
***
### Builder
```go
type Builder struct {
p *astgo.Package
b *strings.Builder
o string
}
```
#### func (*Builder) Generate() error
***

View File

@ -0,0 +1,251 @@
package genreadme
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
"github.com/kercylan98/minotaur/utils/file"
"github.com/kercylan98/minotaur/utils/generator/astgo"
"github.com/kercylan98/minotaur/utils/str"
"github.com/kercylan98/minotaur/utils/super"
"go/format"
"strings"
)
func New(pkgDirPath string, output string) (*Builder, error) {
p, err := astgo.NewPackage(pkgDirPath)
if err != nil {
return nil, err
}
b := &Builder{
p: p,
b: new(strings.Builder),
o: output,
}
return b, nil
}
type Builder struct {
p *astgo.Package
b *strings.Builder
o string
}
func (b *Builder) Generate() error {
//fmt.Println(string(super.MarshalIndentJSON(b.p, "", " ")))
b.genHeader()
b.genMenus()
b.genStructs()
return file.WriterFile(b.o, []byte(b.b.String()))
}
func (b *Builder) genHeader() {
b.title(1, str.FirstUpper(b.p.Name))
b.newLine()
b.newLine(b.p.FileComments().Clear...).newLine()
b.newLine(fmt.Sprintf(`[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/%s)`, b.p.Name))
b.newLine(fmt.Sprintf(`![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)`))
b.newLine()
}
func (b *Builder) genMenus() {
b.title(2, "目录")
b.newLine("列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️")
b.detailsStart("展开 / 折叠目录")
b.quote("包级函数定义").newLine()
b.tableCel("函数", "描述")
for _, function := range b.p.PackageFunc() {
if function.Test || function.Internal {
continue
}
b.tableRow(
fmt.Sprintf("[%s](#%s)", function.Name, function.Name),
collection.FindFirstOrDefaultInSlice(function.Comments.Clear, "暂无描述..."),
)
}
b.newLine().newLine()
b.quote("结构体定义").newLine()
b.tableCel("结构体", "描述")
for _, f := range b.p.Files {
if strings.HasSuffix(f.FilePath, "_test.go") {
continue
}
for _, structInfo := range f.Structs {
if structInfo.Test || structInfo.Internal {
continue
}
b.tableRow(
fmt.Sprintf("[%s](#%s)", structInfo.Name, strings.ToLower(structInfo.Name)),
collection.FindFirstOrDefaultInSlice(structInfo.Comments.Clear, "暂无描述..."),
)
}
}
b.detailsEnd()
}
func (b *Builder) genStructs() {
var funcHandler = func(params []*astgo.Field) string {
var s string
var brackets bool
var paramsStr []string
for _, field := range params {
if !field.Anonymous {
brackets = true
}
paramsStr = append(paramsStr, fmt.Sprintf("%s %s", field.Name, field.Type.Sign))
}
s = strings.Join(paramsStr, ", ")
if brackets {
s = "(" + s + ")"
}
return s
}
for _, function := range b.p.PackageFunc() {
if function.Internal || function.Test {
continue
}
b.title(4, strings.TrimSpace(fmt.Sprintf("func %s%s %s",
function.Name,
func() string {
f := funcHandler(function.Params)
if !strings.HasPrefix(f, "(") {
f = "(" + f + ")"
}
return f
}(),
funcHandler(function.Results),
)))
b.newLine(fmt.Sprintf(`<span id="%s"></span>`, function.Name))
b.quote()
for _, comment := range function.Comments.Clear {
b.quote(comment)
}
b.newLine("***")
}
for _, f := range b.p.Files {
for _, structInfo := range f.Structs {
if structInfo.Internal || structInfo.Test {
continue
}
b.title(3, structInfo.Name)
b.newLine(structInfo.Comments.Clear...)
b.newLine("```go")
structDefine := fmt.Sprintf("type %s struct {%s}",
func() string {
var sb strings.Builder
sb.WriteString(structInfo.Name)
if len(structInfo.Generic) > 0 {
sb.WriteString("[")
var gs []string
for _, field := range structInfo.Generic {
gs = append(gs, fmt.Sprintf("%s %s", field.Name, field.Type.Sign))
}
sb.WriteString(strings.Join(gs, ", "))
sb.WriteString("]")
}
return sb.String()
}(),
func() string {
var sb strings.Builder
if len(structInfo.Fields) > 0 {
sb.WriteString("\n")
}
for _, field := range structInfo.Fields {
sb.WriteString(fmt.Sprintf("\t%s %s\n", field.Name, field.Type.Sign))
}
return sb.String()
}())
sdb, err := format.Source([]byte(structDefine))
if err != nil {
fmt.Println(structDefine)
panic(err)
}
b.newLine(string(sdb))
b.newLine("```")
for _, function := range b.p.StructFunc(structInfo.Name) {
if function.Internal || function.Test {
continue
}
b.title(4, strings.TrimSpace(fmt.Sprintf("func (%s%s) %s%s %s",
super.If(function.Struct.Type.IsPointer, "*", ""),
structInfo.Name,
function.Name,
func() string {
f := funcHandler(function.Params)
if !strings.HasPrefix(f, "(") {
f = "(" + f + ")"
}
return f
}(),
funcHandler(function.Results),
)))
//b.newLine(fmt.Sprintf(`<span id="%s"></span>`, function.Name))
b.quote()
for _, comment := range function.Comments.Clear {
b.quote(comment)
}
b.newLine("***")
}
}
}
}
func (b *Builder) newLine(text ...string) *Builder {
if len(text) == 0 {
b.b.WriteString("\n")
return b
}
for _, s := range text {
b.b.WriteString(s + "\n")
}
return b
}
func (b *Builder) title(lv int, str string) *Builder {
var l string
for i := 0; i < lv; i++ {
l += "#"
}
b.b.WriteString(l + " " + str)
b.b.WriteString("\n")
return b
}
func (b *Builder) quote(str ...string) *Builder {
for _, s := range str {
b.b.WriteString("> " + s)
b.newLine()
}
return b
}
func (b *Builder) tableCel(str ...string) *Builder {
var a string
var c string
for _, s := range str {
a += "|" + s
c += "|:--"
}
b.newLine(a, c)
return b
}
func (b *Builder) tableRow(str ...string) *Builder {
var c string
for _, s := range str {
c += "|" + s
}
return b.newLine(c)
}
func (b *Builder) detailsStart(title string) *Builder {
return b.newLine("<details>", "<summary>"+title+"</summary").newLine().newLine()
}
func (b *Builder) detailsEnd() *Builder {
return b.newLine().newLine("</details>").newLine().newLine()
}

View File

@ -0,0 +1,39 @@
package genreadme
import (
"io/fs"
"path/filepath"
"strings"
"testing"
)
func TestBuilder_Generate(t *testing.T) {
//b, err := New(`/Users/kercylan/Coding.localized/Go/minotaur/utils/buffer`, `/Users/kercylan/Coding.localized/Go/minotaur/utils/buffer/README.md`)
//if err != nil {
// panic(err)
//}
//if err = b.Generate(); err != nil {
// panic(err)
//}
//return
filepath.Walk("/Users/kercylan/Coding.localized/Go/minotaur", func(path string, info fs.FileInfo, err error) error {
if !info.IsDir() {
return nil
}
if strings.Contains(strings.TrimPrefix(path, "/Users/kercylan/Coding.localized/Go/minotaur"), ".") {
return nil
}
b, err := New(
path,
filepath.Join(path, "README.md"),
)
if err != nil {
return nil
}
if err = b.Generate(); err != nil {
panic(err)
}
return nil
})
}

134
utils/generic/README.md Normal file
View File

@ -0,0 +1,134 @@
# Generic
generic 目的在于提供一组基于泛型的用于处理通用功能的函数和数据结构。该包旨在简化通用功能的实现,并提供一致的接口和易于使用的功能。
主要特性:
- 通用功能generic 包支持处理各种通用功能,如数据结构操作、算法实现和常用工具等。您可以使用这些功能来解决各种通用问题,并提高代码的复用性和可维护性。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/generic)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[IsNil](#IsNil)|检查指定的值是否为 nil
|[IsAllNil](#IsAllNil)|检查指定的值是否全部为 nil
|[IsHasNil](#IsHasNil)|检查指定的值是否存在 nil
> 结构体定义
|结构体|描述
|:--|:--
|[IdR](#idr)|暂无描述...
|[IDR](#idr)|暂无描述...
|[IdW](#idw)|暂无描述...
|[IDW](#idw)|暂无描述...
|[IdR2W](#idr2w)|暂无描述...
|[IDR2W](#idr2w)|暂无描述...
|[Ordered](#ordered)|可排序类型
|[Number](#number)|数字类型
|[SignedNumber](#signednumber)|有符号数字类型
|[Integer](#integer)|整数类型
|[Signed](#signed)|有符号整数类型
|[Unsigned](#unsigned)|无符号整数类型
|[UnsignedNumber](#unsignednumber)|无符号数字类型
|[Float](#float)|浮点类型
|[Basic](#basic)|基本类型
</details>
#### func IsNil(v V) bool
<span id="IsNil"></span>
> 检查指定的值是否为 nil
***
#### func IsAllNil(v ...V) bool
<span id="IsAllNil"></span>
> 检查指定的值是否全部为 nil
***
#### func IsHasNil(v ...V) bool
<span id="IsHasNil"></span>
> 检查指定的值是否存在 nil
***
### IdR
```go
type IdR[ID comparable] struct{}
```
### IDR
```go
type IDR[ID comparable] struct{}
```
### IdW
```go
type IdW[ID comparable] struct{}
```
### IDW
```go
type IDW[ID comparable] struct{}
```
### IdR2W
```go
type IdR2W[ID comparable] struct{}
```
### IDR2W
```go
type IDR2W[ID comparable] struct{}
```
### Ordered
可排序类型
```go
type Ordered struct{}
```
### Number
数字类型
```go
type Number struct{}
```
### SignedNumber
有符号数字类型
```go
type SignedNumber struct{}
```
### Integer
整数类型
```go
type Integer struct{}
```
### Signed
有符号整数类型
```go
type Signed struct{}
```
### Unsigned
无符号整数类型
```go
type Unsigned struct{}
```
### UnsignedNumber
无符号数字类型
```go
type UnsignedNumber struct{}
```
### Float
浮点类型
```go
type Float struct{}
```
### Basic
基本类型
```go
type Basic struct{}
```

691
utils/geometry/README.md Normal file
View File

@ -0,0 +1,691 @@
# Geometry
geometry 旨在提供一组用于处理几何形状和计算几何属性的函数和数据结构。该包旨在简化几何计算的过程,并提供一致的接口和易于使用的功能。
主要特性:
- 几何形状:"geometry"包支持处理各种几何形状,如点、线、多边形和圆等。您可以使用这些形状来表示和操作实际世界中的几何对象。
- 几何计算:该包提供了一系列函数,用于执行常见的几何计算,如计算两点之间的距离、计算线段的长度、计算多边形的面积等。这些函数旨在提供高效和准确的计算结果。
- 坐标转换:"geometry"包还提供了一些函数,用于在不同坐标系之间进行转换。您可以将点从笛卡尔坐标系转换为极坐标系,或者从二维坐标系转换为三维坐标系等。
- 简化接口:该包的设计目标之一是提供简化的接口,使几何计算变得更加直观和易于使用。您可以轻松地创建和操作几何对象,而无需处理繁琐的底层细节。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/geometry)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewCircle](#NewCircle)|通过传入圆的半径和需要的点数量,生成一个圆
|[CalcCircleCentroidDistance](#CalcCircleCentroidDistance)|计算两个圆质心距离
|[GetOppositionDirection](#GetOppositionDirection)|获取特定方向的对立方向
|[GetDirectionNextWithCoordinate](#GetDirectionNextWithCoordinate)|获取特定方向上的下一个坐标
|[GetDirectionNextWithPoint](#GetDirectionNextWithPoint)|获取特定方向上的下一个坐标
|[GetDirectionNextWithPos](#GetDirectionNextWithPos)|获取位置在特定宽度和特定方向上的下一个位置
|[CalcDirection](#CalcDirection)|计算点2位于点1的方向
|[CalcDistanceWithCoordinate](#CalcDistanceWithCoordinate)|计算两点之间的距离
|[CalcDistanceWithPoint](#CalcDistanceWithPoint)|计算两点之间的距离
|[CalcDistanceSquared](#CalcDistanceSquared)|计算两点之间的平方距离
|[CalcAngle](#CalcAngle)|计算点2位于点1之间的角度
|[CalcNewCoordinate](#CalcNewCoordinate)|根据给定的x、y坐标、角度和距离计算新的坐标
|[CalcRadianWithAngle](#CalcRadianWithAngle)|根据角度 angle 计算弧度
|[CalcAngleDifference](#CalcAngleDifference)|计算两个角度之间的最小角度差
|[CalcRayIsIntersect](#CalcRayIsIntersect)|根据给定的位置和角度生成射线,检测射线是否与多边形发生碰撞
|[NewLineSegment](#NewLineSegment)|创建一根线段
|[NewLineSegmentCap](#NewLineSegmentCap)|创建一根包含数据的线段
|[NewLineSegmentCapWithLine](#NewLineSegmentCapWithLine)|通过已有线段创建一根包含数据的线段
|[ConvertLineSegmentGeneric](#ConvertLineSegmentGeneric)|转换线段的泛型类型为特定类型
|[PointOnLineSegmentWithCoordinate](#PointOnLineSegmentWithCoordinate)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[PointOnLineSegmentWithPos](#PointOnLineSegmentWithPos)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[PointOnLineSegmentWithPoint](#PointOnLineSegmentWithPoint)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[PointOnLineSegmentWithCoordinateInBounds](#PointOnLineSegmentWithCoordinateInBounds)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[PointOnLineSegmentWithPosInBounds](#PointOnLineSegmentWithPosInBounds)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[PointOnLineSegmentWithPointInBounds](#PointOnLineSegmentWithPointInBounds)|通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|[CalcLineSegmentIsCollinear](#CalcLineSegmentIsCollinear)|检查两条线段在一个误差内是否共线
|[CalcLineSegmentIsOverlap](#CalcLineSegmentIsOverlap)|通过对点进行排序来检查两条共线线段是否重叠,返回重叠线段
|[CalcLineSegmentIsIntersect](#CalcLineSegmentIsIntersect)|计算两条线段是否相交
|[CalcLineSegmentSlope](#CalcLineSegmentSlope)|计算线段的斜率
|[CalcLineSegmentIntercept](#CalcLineSegmentIntercept)|计算线段的截距
|[NewPoint](#NewPoint)|创建一个由 x、y 坐标组成的点
|[NewPointCap](#NewPointCap)|创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
|[NewPointCapWithData](#NewPointCapWithData)|通过设置数据的方式创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
|[NewPointCapWithPoint](#NewPointCapWithPoint)|通过设置数据的方式创建一个由已有坐标组成的点,这个点具有一个数据容量
|[CoordinateToPoint](#CoordinateToPoint)|将坐标转换为x、y的坐标数组
|[CoordinateToPos](#CoordinateToPos)|将坐标转换为二维数组的顺序位置坐标
|[PointToCoordinate](#PointToCoordinate)|将坐标数组转换为x和y坐标
|[PointToPos](#PointToPos)|将坐标转换为二维数组的顺序位置
|[PosToCoordinate](#PosToCoordinate)|通过宽度将一个二维数组的顺序位置转换为xy坐标
|[PosToPoint](#PosToPoint)|通过宽度将一个二维数组的顺序位置转换为x、y的坐标数组
|[PosToCoordinateX](#PosToCoordinateX)|通过宽度将一个二维数组的顺序位置转换为X坐标
|[PosToCoordinateY](#PosToCoordinateY)|通过宽度将一个二维数组的顺序位置转换为Y坐标
|[PointCopy](#PointCopy)|复制一个坐标数组
|[PointToPosWithMulti](#PointToPosWithMulti)|将一组坐标转换为二维数组的顺序位置
|[PosToPointWithMulti](#PosToPointWithMulti)|将一组二维数组的顺序位置转换为一组数组坐标
|[PosSameRow](#PosSameRow)|返回两个顺序位置在同一宽度是否位于同一行
|[DoublePointToCoordinate](#DoublePointToCoordinate)|将两个位置转换为 x1, y1, x2, y2 的坐标进行返回
|[CalcProjectionPoint](#CalcProjectionPoint)|计算一个点到一条线段的最近点(即投影点)的。这个函数接收一个点和一条线段作为输入,线段由两个端点组成。
|[GetAdjacentTranslatePos](#GetAdjacentTranslatePos)|获取一个连续位置的矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
|[GetAdjacentTranslateCoordinateXY](#GetAdjacentTranslateCoordinateXY)|获取一个基于 x、y 的二维矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
|[GetAdjacentTranslateCoordinateYX](#GetAdjacentTranslateCoordinateYX)|获取一个基于 y、x 的二维矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
|[GetAdjacentDiagonalsPos](#GetAdjacentDiagonalsPos)|获取一个连续位置的矩阵中,特定位置相邻的对角线最多四个方向的位置
|[GetAdjacentDiagonalsCoordinateXY](#GetAdjacentDiagonalsCoordinateXY)|获取一个基于 x、y 的二维矩阵中,特定位置相邻的对角线最多四个方向的位置
|[GetAdjacentDiagonalsCoordinateYX](#GetAdjacentDiagonalsCoordinateYX)|获取一个基于 tx 的二维矩阵中,特定位置相邻的对角线最多四个方向的位置
|[GetAdjacentPos](#GetAdjacentPos)|获取一个连续位置的矩阵中,特定位置相邻的最多八个方向的位置
|[GetAdjacentCoordinateXY](#GetAdjacentCoordinateXY)|获取一个基于 x、y 的二维矩阵中,特定位置相邻的最多八个方向的位置
|[GetAdjacentCoordinateYX](#GetAdjacentCoordinateYX)|获取一个基于 yx 的二维矩阵中,特定位置相邻的最多八个方向的位置
|[CoordinateMatrixToPosMatrix](#CoordinateMatrixToPosMatrix)|将二维矩阵转换为顺序的二维矩阵
|[GetShapeCoverageAreaWithPoint](#GetShapeCoverageAreaWithPoint)|通过传入的一组坐标 points 计算一个图形覆盖的矩形范围
|[GetShapeCoverageAreaWithPos](#GetShapeCoverageAreaWithPos)|通过传入的一组坐标 positions 计算一个图形覆盖的矩形范围
|[CoverageAreaBoundless](#CoverageAreaBoundless)|将一个图形覆盖矩形范围设置为无边的
|[GenerateShapeOnRectangle](#GenerateShapeOnRectangle)|生成一组二维坐标的形状
|[GenerateShapeOnRectangleWithCoordinate](#GenerateShapeOnRectangleWithCoordinate)|生成一组二维坐标的形状
|[GetExpressibleRectangleBySize](#GetExpressibleRectangleBySize)|获取一个宽高可表达的所有特定尺寸以上的矩形形状
|[GetExpressibleRectangle](#GetExpressibleRectangle)|获取一个宽高可表达的所有矩形形状
|[GetRectangleFullPointsByXY](#GetRectangleFullPointsByXY)|通过开始结束坐标获取一个矩形包含的所有点
|[GetRectangleFullPoints](#GetRectangleFullPoints)|获取一个矩形填充满后包含的所有点
|[GetRectangleFullPos](#GetRectangleFullPos)|获取一个矩形填充满后包含的所有位置
|[CalcRectangleCentroid](#CalcRectangleCentroid)|计算矩形质心
|[SetShapeStringHasBorder](#SetShapeStringHasBorder)|设置 Shape.String 是拥有边界的
|[SetShapeStringNotHasBorder](#SetShapeStringNotHasBorder)|设置 Shape.String 是没有边界的
|[NewShape](#NewShape)|通过多个点生成一个形状进行返回
|[NewShapeWithString](#NewShapeWithString)|通过字符串将指定 rune 转换为点位置生成形状进行返回
|[CalcBoundingRadius](#CalcBoundingRadius)|计算多边形转换为圆的半径
|[CalcBoundingRadiusWithCentroid](#CalcBoundingRadiusWithCentroid)|计算多边形在特定质心下圆的半径
|[CalcTriangleTwiceArea](#CalcTriangleTwiceArea)|计算由 a、b、c 三个点组成的三角形的面积的两倍
|[IsPointOnEdge](#IsPointOnEdge)|检查点是否在 edges 的任意一条边上
|[ProjectionPointToShape](#ProjectionPointToShape)|将一个点投影到一个多边形上,找到离该点最近的投影点,并返回投影点和距离
|[WithShapeSearchRectangleLowerLimit](#WithShapeSearchRectangleLowerLimit)|通过矩形宽高下限的方式搜索
|[WithShapeSearchRectangleUpperLimit](#WithShapeSearchRectangleUpperLimit)|通过矩形宽高上限的方式搜索
|[WithShapeSearchRightAngle](#WithShapeSearchRightAngle)|通过直角的方式进行搜索
|[WithShapeSearchOppositionDirection](#WithShapeSearchOppositionDirection)|通过限制对立方向的方式搜索
|[WithShapeSearchDirectionCount](#WithShapeSearchDirectionCount)|通过限制方向数量的方式搜索
|[WithShapeSearchDirectionCountLowerLimit](#WithShapeSearchDirectionCountLowerLimit)|通过限制特定方向数量下限的方式搜索
|[WithShapeSearchDirectionCountUpperLimit](#WithShapeSearchDirectionCountUpperLimit)|通过限制特定方向数量上限的方式搜索
|[WithShapeSearchDeduplication](#WithShapeSearchDeduplication)|通过去重的方式进行搜索
|[WithShapeSearchPointCountLowerLimit](#WithShapeSearchPointCountLowerLimit)|通过限制图形构成的最小点数进行搜索
|[WithShapeSearchPointCountUpperLimit](#WithShapeSearchPointCountUpperLimit)|通过限制图形构成的最大点数进行搜索
|[WithShapeSearchAsc](#WithShapeSearchAsc)|通过升序的方式进行搜索
|[WithShapeSearchDesc](#WithShapeSearchDesc)|通过降序的方式进行搜索
> 结构体定义
|结构体|描述
|:--|:--
|[Circle](#circle)|圆形
|[FloorPlan](#floorplan)|平面图
|[Direction](#direction)|方向
|[LineSegment](#linesegment)|通过两个点表示一根线段
|[LineSegmentCap](#linesegmentcap)|可以包含一份额外数据的线段
|[Point](#point)|表示了一个由 x、y 坐标组成的点
|[PointCap](#pointcap)|表示了一个由 x、y 坐标组成的点,这个点具有一个数据容量
|[Shape](#shape)|通过多个点表示了一个形状
|[ShapeSearchOption](#shapesearchoption)|图形搜索可选项,用于 Shape.ShapeSearch 搜索支持
</details>
#### func NewCircle(radius V, points int) Circle[V]
<span id="NewCircle"></span>
> 通过传入圆的半径和需要的点数量,生成一个圆
***
#### func CalcCircleCentroidDistance(circle1 Circle[V], circle2 Circle[V]) V
<span id="CalcCircleCentroidDistance"></span>
> 计算两个圆质心距离
***
#### func GetOppositionDirection(direction Direction) Direction
<span id="GetOppositionDirection"></span>
> 获取特定方向的对立方向
***
#### func GetDirectionNextWithCoordinate(direction Direction, x V, y V) (nx V, ny V)
<span id="GetDirectionNextWithCoordinate"></span>
> 获取特定方向上的下一个坐标
***
#### func GetDirectionNextWithPoint(direction Direction, point Point[V]) Point[V]
<span id="GetDirectionNextWithPoint"></span>
> 获取特定方向上的下一个坐标
***
#### func GetDirectionNextWithPos(direction Direction, width V, pos V) V
<span id="GetDirectionNextWithPos"></span>
> 获取位置在特定宽度和特定方向上的下一个位置
> - 需要注意的是,在左右方向时,当下一个位置不在矩形区域内时,将会返回上一行的末位置或下一行的首位置
***
#### func CalcDirection(x1 V, y1 V, x2 V, y2 V) Direction
<span id="CalcDirection"></span>
> 计算点2位于点1的方向
***
#### func CalcDistanceWithCoordinate(x1 V, y1 V, x2 V, y2 V) V
<span id="CalcDistanceWithCoordinate"></span>
> 计算两点之间的距离
***
#### func CalcDistanceWithPoint(point1 Point[V], point2 Point[V]) V
<span id="CalcDistanceWithPoint"></span>
> 计算两点之间的距离
***
#### func CalcDistanceSquared(x1 V, y1 V, x2 V, y2 V) V
<span id="CalcDistanceSquared"></span>
> 计算两点之间的平方距离
> - 这个函数的主要用途是在需要计算两点之间距离的情况下,但不需要得到实际的距离值,而只需要比较距离大小。因为平方根运算相对较为耗时,所以在只需要比较大小的情况下,通常会使用平方距离。
***
#### func CalcAngle(x1 V, y1 V, x2 V, y2 V) V
<span id="CalcAngle"></span>
> 计算点2位于点1之间的角度
***
#### func CalcNewCoordinate(x V, y V, angle V, distance V) (newX V, newY V)
<span id="CalcNewCoordinate"></span>
> 根据给定的x、y坐标、角度和距离计算新的坐标
***
#### func CalcRadianWithAngle(angle V) V
<span id="CalcRadianWithAngle"></span>
> 根据角度 angle 计算弧度
***
#### func CalcAngleDifference(angleA V, angleB V) V
<span id="CalcAngleDifference"></span>
> 计算两个角度之间的最小角度差
***
#### func CalcRayIsIntersect(x V, y V, angle V, shape Shape[V]) bool
<span id="CalcRayIsIntersect"></span>
> 根据给定的位置和角度生成射线,检测射线是否与多边形发生碰撞
***
#### func NewLineSegment(start Point[V], end Point[V]) LineSegment[V]
<span id="NewLineSegment"></span>
> 创建一根线段
***
#### func NewLineSegmentCap(start Point[V], end Point[V], data Data) LineSegmentCap[V, Data]
<span id="NewLineSegmentCap"></span>
> 创建一根包含数据的线段
***
#### func NewLineSegmentCapWithLine(line LineSegment[V], data Data) LineSegmentCap[V, Data]
<span id="NewLineSegmentCapWithLine"></span>
> 通过已有线段创建一根包含数据的线段
***
#### func ConvertLineSegmentGeneric(line LineSegment[V]) LineSegment[TO]
<span id="ConvertLineSegmentGeneric"></span>
> 转换线段的泛型类型为特定类型
***
#### func PointOnLineSegmentWithCoordinate(x1 V, y1 V, x2 V, y2 V, x V, y V) bool
<span id="PointOnLineSegmentWithCoordinate"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
***
#### func PointOnLineSegmentWithPos(width V, pos1 V, pos2 V, pos V) bool
<span id="PointOnLineSegmentWithPos"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
***
#### func PointOnLineSegmentWithPoint(point1 Point[V], point2 Point[V], point Point[V]) bool
<span id="PointOnLineSegmentWithPoint"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
***
#### func PointOnLineSegmentWithCoordinateInBounds(x1 V, y1 V, x2 V, y2 V, x V, y V) bool
<span id="PointOnLineSegmentWithCoordinateInBounds"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
> - 与 PointOnLineSegmentWithCoordinate 不同的是, PointOnLineSegmentWithCoordinateInBounds 中会判断线段及点的位置是否正确
***
#### func PointOnLineSegmentWithPosInBounds(width V, pos1 V, pos2 V, pos V) bool
<span id="PointOnLineSegmentWithPosInBounds"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
> - 与 PointOnLineSegmentWithPos 不同的是, PointOnLineSegmentWithPosInBounds 中会判断线段及点的位置是否正确
***
#### func PointOnLineSegmentWithPointInBounds(point1 Point[V], point2 Point[V], point Point[V]) bool
<span id="PointOnLineSegmentWithPointInBounds"></span>
> 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
> - 与 PointOnLineSegmentWithPoint 不同的是, PointOnLineSegmentWithPointInBounds 中会判断线段及点的位置是否正确
***
#### func CalcLineSegmentIsCollinear(line1 LineSegment[V], line2 LineSegment[V], tolerance V) bool
<span id="CalcLineSegmentIsCollinear"></span>
> 检查两条线段在一个误差内是否共线
> - 共线是指两条线段在同一直线上,即它们的延长线可以重合
***
#### func CalcLineSegmentIsOverlap(line1 LineSegment[V], line2 LineSegment[V]) (line LineSegment[V], overlap bool)
<span id="CalcLineSegmentIsOverlap"></span>
> 通过对点进行排序来检查两条共线线段是否重叠,返回重叠线段
***
#### func CalcLineSegmentIsIntersect(line1 LineSegment[V], line2 LineSegment[V]) bool
<span id="CalcLineSegmentIsIntersect"></span>
> 计算两条线段是否相交
***
#### func CalcLineSegmentSlope(line LineSegment[V]) V
<span id="CalcLineSegmentSlope"></span>
> 计算线段的斜率
***
#### func CalcLineSegmentIntercept(line LineSegment[V]) V
<span id="CalcLineSegmentIntercept"></span>
> 计算线段的截距
***
#### func NewPoint(x V, y V) Point[V]
<span id="NewPoint"></span>
> 创建一个由 x、y 坐标组成的点
***
#### func NewPointCap(x V, y V) PointCap[V, D]
<span id="NewPointCap"></span>
> 创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
***
#### func NewPointCapWithData(x V, y V, data D) PointCap[V, D]
<span id="NewPointCapWithData"></span>
> 通过设置数据的方式创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
***
#### func NewPointCapWithPoint(point Point[V], data D) PointCap[V, D]
<span id="NewPointCapWithPoint"></span>
> 通过设置数据的方式创建一个由已有坐标组成的点,这个点具有一个数据容量
***
#### func CoordinateToPoint(x V, y V) Point[V]
<span id="CoordinateToPoint"></span>
> 将坐标转换为x、y的坐标数组
***
#### func CoordinateToPos(width V, x V, y V) V
<span id="CoordinateToPos"></span>
> 将坐标转换为二维数组的顺序位置坐标
> - 需要确保x的取值范围必须小于width或者将会得到不正确的值
***
#### func PointToCoordinate(position Point[V]) (x V, y V)
<span id="PointToCoordinate"></span>
> 将坐标数组转换为x和y坐标
***
#### func PointToPos(width V, xy Point[V]) V
<span id="PointToPos"></span>
> 将坐标转换为二维数组的顺序位置
> - 需要确保x的取值范围必须小于width或者将会得到不正确的值
***
#### func PosToCoordinate(width V, pos V) (x V, y V)
<span id="PosToCoordinate"></span>
> 通过宽度将一个二维数组的顺序位置转换为xy坐标
***
#### func PosToPoint(width V, pos V) Point[V]
<span id="PosToPoint"></span>
> 通过宽度将一个二维数组的顺序位置转换为x、y的坐标数组
***
#### func PosToCoordinateX(width V, pos V) V
<span id="PosToCoordinateX"></span>
> 通过宽度将一个二维数组的顺序位置转换为X坐标
***
#### func PosToCoordinateY(width V, pos V) V
<span id="PosToCoordinateY"></span>
> 通过宽度将一个二维数组的顺序位置转换为Y坐标
***
#### func PointCopy(point Point[V]) Point[V]
<span id="PointCopy"></span>
> 复制一个坐标数组
***
#### func PointToPosWithMulti(width V, points ...Point[V]) []V
<span id="PointToPosWithMulti"></span>
> 将一组坐标转换为二维数组的顺序位置
> - 需要确保x的取值范围必须小于width或者将会得到不正确的值
***
#### func PosToPointWithMulti(width V, positions ...V) []Point[V]
<span id="PosToPointWithMulti"></span>
> 将一组二维数组的顺序位置转换为一组数组坐标
***
#### func PosSameRow(width V, pos1 V, pos2 V) bool
<span id="PosSameRow"></span>
> 返回两个顺序位置在同一宽度是否位于同一行
***
#### func DoublePointToCoordinate(point1 Point[V], point2 Point[V]) (x1 V, y1 V, x2 V, y2 V)
<span id="DoublePointToCoordinate"></span>
> 将两个位置转换为 x1, y1, x2, y2 的坐标进行返回
***
#### func CalcProjectionPoint(line LineSegment[V], point Point[V]) Point[V]
<span id="CalcProjectionPoint"></span>
> 计算一个点到一条线段的最近点(即投影点)的。这个函数接收一个点和一条线段作为输入,线段由两个端点组成。
> - 该函数的主要用于需要计算一个点到一条线段的最近点的情况下
***
#### func GetAdjacentTranslatePos(matrix []T, width P, pos P) (result []P)
<span id="GetAdjacentTranslatePos"></span>
> 获取一个连续位置的矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
***
#### func GetAdjacentTranslateCoordinateXY(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentTranslateCoordinateXY"></span>
> 获取一个基于 x、y 的二维矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
***
#### func GetAdjacentTranslateCoordinateYX(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentTranslateCoordinateYX"></span>
> 获取一个基于 y、x 的二维矩阵中,特定位置相邻的最多四个平移方向(上下左右)的位置
***
#### func GetAdjacentDiagonalsPos(matrix []T, width P, pos P) (result []P)
<span id="GetAdjacentDiagonalsPos"></span>
> 获取一个连续位置的矩阵中,特定位置相邻的对角线最多四个方向的位置
***
#### func GetAdjacentDiagonalsCoordinateXY(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentDiagonalsCoordinateXY"></span>
> 获取一个基于 x、y 的二维矩阵中,特定位置相邻的对角线最多四个方向的位置
***
#### func GetAdjacentDiagonalsCoordinateYX(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentDiagonalsCoordinateYX"></span>
> 获取一个基于 tx 的二维矩阵中,特定位置相邻的对角线最多四个方向的位置
***
#### func GetAdjacentPos(matrix []T, width P, pos P) (result []P)
<span id="GetAdjacentPos"></span>
> 获取一个连续位置的矩阵中,特定位置相邻的最多八个方向的位置
***
#### func GetAdjacentCoordinateXY(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentCoordinateXY"></span>
> 获取一个基于 x、y 的二维矩阵中,特定位置相邻的最多八个方向的位置
***
#### func GetAdjacentCoordinateYX(matrix [][]T, x P, y P) (result []Point[P])
<span id="GetAdjacentCoordinateYX"></span>
> 获取一个基于 yx 的二维矩阵中,特定位置相邻的最多八个方向的位置
***
#### func CoordinateMatrixToPosMatrix(matrix [][]V) (width int, posMatrix []V)
<span id="CoordinateMatrixToPosMatrix"></span>
> 将二维矩阵转换为顺序的二维矩阵
***
#### func GetShapeCoverageAreaWithPoint(points ...Point[V]) (left V, right V, top V, bottom V)
<span id="GetShapeCoverageAreaWithPoint"></span>
> 通过传入的一组坐标 points 计算一个图形覆盖的矩形范围
***
#### func GetShapeCoverageAreaWithPos(width V, positions ...V) (left V, right V, top V, bottom V)
<span id="GetShapeCoverageAreaWithPos"></span>
> 通过传入的一组坐标 positions 计算一个图形覆盖的矩形范围
***
#### func CoverageAreaBoundless(l V, r V, t V, b V) (left V, right V, top V, bottom V)
<span id="CoverageAreaBoundless"></span>
> 将一个图形覆盖矩形范围设置为无边的
> - 无边化表示会将多余的部分进行裁剪,例如图形左边从 2 开始的时候,那么左边将会被裁剪到从 0 开始
***
#### func GenerateShapeOnRectangle(points ...Point[V]) (result []PointCap[V, bool])
<span id="GenerateShapeOnRectangle"></span>
> 生成一组二维坐标的形状
> - 这个形状将被在一个刚好能容纳形状的矩形中表示
> - 为 true 的位置表示了形状的每一个点
***
#### func GenerateShapeOnRectangleWithCoordinate(points ...Point[V]) (result [][]bool)
<span id="GenerateShapeOnRectangleWithCoordinate"></span>
> 生成一组二维坐标的形状
> - 这个形状将被在一个刚好能容纳形状的矩形中表示
> - 为 true 的位置表示了形状的每一个点
***
#### func GetExpressibleRectangleBySize(width V, height V, minWidth V, minHeight V) (result []Point[V])
<span id="GetExpressibleRectangleBySize"></span>
> 获取一个宽高可表达的所有特定尺寸以上的矩形形状
> - 返回值表示了每一个矩形右下角的x,y位置左上角始终为0, 0
> - 矩形尺寸由大到小
***
#### func GetExpressibleRectangle(width V, height V) (result []Point[V])
<span id="GetExpressibleRectangle"></span>
> 获取一个宽高可表达的所有矩形形状
> - 返回值表示了每一个矩形右下角的x,y位置左上角始终为0, 0
> - 矩形尺寸由大到小
***
#### func GetRectangleFullPointsByXY(startX V, startY V, endX V, endY V) (result []Point[V])
<span id="GetRectangleFullPointsByXY"></span>
> 通过开始结束坐标获取一个矩形包含的所有点
> - 例如 1,1 到 2,2 的矩形结果为 1,1 2,1 1,2 2,2
***
#### func GetRectangleFullPoints(width V, height V) (result []Point[V])
<span id="GetRectangleFullPoints"></span>
> 获取一个矩形填充满后包含的所有点
***
#### func GetRectangleFullPos(width V, height V) (result []V)
<span id="GetRectangleFullPos"></span>
> 获取一个矩形填充满后包含的所有位置
***
#### func CalcRectangleCentroid(shape Shape[V]) Point[V]
<span id="CalcRectangleCentroid"></span>
> 计算矩形质心
> - 非多边形质心计算,仅为顶点的平均值 - 该区域中多边形因子的适当质心
***
#### func SetShapeStringHasBorder()
<span id="SetShapeStringHasBorder"></span>
> 设置 Shape.String 是拥有边界的
***
#### func SetShapeStringNotHasBorder()
<span id="SetShapeStringNotHasBorder"></span>
> 设置 Shape.String 是没有边界的
***
#### func NewShape(points ...Point[V]) Shape[V]
<span id="NewShape"></span>
> 通过多个点生成一个形状进行返回
***
#### func NewShapeWithString(rows []string, point rune) (shape Shape[V])
<span id="NewShapeWithString"></span>
> 通过字符串将指定 rune 转换为点位置生成形状进行返回
> - 每个点的顺序从上到下,从左到右
***
#### func CalcBoundingRadius(shape Shape[V]) V
<span id="CalcBoundingRadius"></span>
> 计算多边形转换为圆的半径
***
#### func CalcBoundingRadiusWithCentroid(shape Shape[V], centroid Point[V]) V
<span id="CalcBoundingRadiusWithCentroid"></span>
> 计算多边形在特定质心下圆的半径
***
#### func CalcTriangleTwiceArea(a Point[V], b Point[V], c Point[V]) V
<span id="CalcTriangleTwiceArea"></span>
> 计算由 a、b、c 三个点组成的三角形的面积的两倍
***
#### func IsPointOnEdge(edges []LineSegment[V], point Point[V]) bool
<span id="IsPointOnEdge"></span>
> 检查点是否在 edges 的任意一条边上
***
#### func ProjectionPointToShape(point Point[V], shape Shape[V]) Point[V], V
<span id="ProjectionPointToShape"></span>
> 将一个点投影到一个多边形上,找到离该点最近的投影点,并返回投影点和距离
***
#### func WithShapeSearchRectangleLowerLimit(minWidth int, minHeight int) ShapeSearchOption
<span id="WithShapeSearchRectangleLowerLimit"></span>
> 通过矩形宽高下限的方式搜索
***
#### func WithShapeSearchRectangleUpperLimit(maxWidth int, maxHeight int) ShapeSearchOption
<span id="WithShapeSearchRectangleUpperLimit"></span>
> 通过矩形宽高上限的方式搜索
***
#### func WithShapeSearchRightAngle() ShapeSearchOption
<span id="WithShapeSearchRightAngle"></span>
> 通过直角的方式进行搜索
***
#### func WithShapeSearchOppositionDirection(direction Direction) ShapeSearchOption
<span id="WithShapeSearchOppositionDirection"></span>
> 通过限制对立方向的方式搜索
> - 对立方向例如上不能与下共存
***
#### func WithShapeSearchDirectionCount(count int) ShapeSearchOption
<span id="WithShapeSearchDirectionCount"></span>
> 通过限制方向数量的方式搜索
***
#### func WithShapeSearchDirectionCountLowerLimit(direction Direction, count int) ShapeSearchOption
<span id="WithShapeSearchDirectionCountLowerLimit"></span>
> 通过限制特定方向数量下限的方式搜索
***
#### func WithShapeSearchDirectionCountUpperLimit(direction Direction, count int) ShapeSearchOption
<span id="WithShapeSearchDirectionCountUpperLimit"></span>
> 通过限制特定方向数量上限的方式搜索
***
#### func WithShapeSearchDeduplication() ShapeSearchOption
<span id="WithShapeSearchDeduplication"></span>
> 通过去重的方式进行搜索
> - 去重方式中每个点仅会被使用一次
***
#### func WithShapeSearchPointCountLowerLimit(lowerLimit int) ShapeSearchOption
<span id="WithShapeSearchPointCountLowerLimit"></span>
> 通过限制图形构成的最小点数进行搜索
> - 当搜索到的图形的点数量低于 lowerLimit 时,将被忽略
***
#### func WithShapeSearchPointCountUpperLimit(upperLimit int) ShapeSearchOption
<span id="WithShapeSearchPointCountUpperLimit"></span>
> 通过限制图形构成的最大点数进行搜索
> - 当搜索到的图形的点数量大于 upperLimit 时,将被忽略
***
#### func WithShapeSearchAsc() ShapeSearchOption
<span id="WithShapeSearchAsc"></span>
> 通过升序的方式进行搜索
***
#### func WithShapeSearchDesc() ShapeSearchOption
<span id="WithShapeSearchDesc"></span>
> 通过降序的方式进行搜索
***
### Circle
圆形
```go
type Circle[V generic.SignedNumber] struct {
Shape[V]
}
```
#### func (Circle) Radius() V
> 获取圆形半径
***
#### func (Circle) Centroid() Point[V]
> 获取圆形质心位置
***
#### func (Circle) Overlap(circle Circle[V]) bool
> 与另一个圆是否发生重叠
***
#### func (Circle) Area() V
> 获取圆形面积
***
#### func (Circle) Length() V
> 获取圆的周长
***
#### func (Circle) CentroidDistance(circle Circle[V]) V
> 计算与另一个圆的质心距离
***
### FloorPlan
平面图
```go
type FloorPlan struct{}
```
#### func (FloorPlan) IsFree(point Point[int]) bool
> 检查位置是否为空格
***
#### func (FloorPlan) IsInBounds(point Point[int]) bool
> 检查位置是否在边界内
***
#### func (FloorPlan) Put(point Point[int], c rune)
> 设置平面图特定位置的字符
***
#### func (FloorPlan) String() string
> 获取平面图结果
***
### Direction
方向
```go
type Direction struct{}
```
### LineSegment
通过两个点表示一根线段
```go
type LineSegment[V generic.SignedNumber] struct{}
```
#### func (LineSegment) GetPoints() [2]Point[V]
> 获取该线段的两个点
***
#### func (LineSegment) GetStart() Point[V]
> 获取该线段的开始位置
***
#### func (LineSegment) GetEnd() Point[V]
> 获取该线段的结束位置
***
#### func (LineSegment) GetLength() V
> 获取该线段的长度
***
### LineSegmentCap
可以包含一份额外数据的线段
```go
type LineSegmentCap[V generic.SignedNumber, Data any] struct {
LineSegment[V]
Data Data
}
```
### Point
表示了一个由 x、y 坐标组成的点
```go
type Point[V generic.SignedNumber] struct{}
```
#### func (Point) GetX() V
> 返回该点的 x 坐标
***
#### func (Point) GetY() V
> 返回该点的 y 坐标
***
#### func (Point) GetXY() (x V, y V)
> 返回该点的 x、y 坐标
***
#### func (Point) GetPos(width V) V
> 返回该点位于特定宽度的二维数组的顺序位置
***
#### func (Point) GetOffset(x V, y V) Point[V]
> 获取偏移后的新坐标
***
#### func (Point) Negative() bool
> 返回该点是否是一个负数坐标
***
#### func (Point) OutOf(minWidth V, minHeight V, maxWidth V, maxHeight V) bool
> 返回该点在特定宽高下是否越界f
***
#### func (Point) Equal(point Point[V]) bool
> 返回两个点是否相等
***
#### func (Point) Copy() Point[V]
> 复制一个点位置
***
#### func (Point) Add(point Point[V]) Point[V]
> 得到加上 point 后的点
***
#### func (Point) Sub(point Point[V]) Point[V]
> 得到减去 point 后的点
***
#### func (Point) Mul(point Point[V]) Point[V]
> 得到乘以 point 后的点
***
#### func (Point) Div(point Point[V]) Point[V]
> 得到除以 point 后的点
***
#### func (Point) Abs() Point[V]
> 返回位置的绝对值
***
#### func (Point) Max(point Point[V]) Point[V]
> 返回两个位置中每个维度的最大值组成的新的位置
***
#### func (Point) Min(point Point[V]) Point[V]
> 返回两个位置中每个维度的最小值组成的新的位置
***
### PointCap
表示了一个由 x、y 坐标组成的点,这个点具有一个数据容量
```go
type PointCap[V generic.SignedNumber, D any] struct {
Point[V]
Data D
}
```
### Shape
通过多个点表示了一个形状
```go
type Shape[V generic.SignedNumber] struct{}
```
#### func (Shape) Points() []Point[V]
> 获取这个形状的所有点
***
#### func (Shape) PointCount() int
> 获取这个形状的点数量
***
#### func (Shape) Contains(point Point[V]) bool
> 返回该形状中是否包含点
***
#### func (Shape) ToCircle() Circle[V]
> 将形状转换为圆形进行处理
> - 当形状非圆形时将会产生意外情况
***
#### func (Shape) String() string
> 将该形状转换为可视化的字符串进行返回
***
#### func (Shape) ShapeSearch(options ...ShapeSearchOption) (result []Shape[V])
> 获取该形状中包含的所有图形组合及其位置
> - 需要注意的是,即便图形最终表示为相同的,但是只要位置组合顺序不同,那么也将被认定为一种图形组合
> - [[1 0] [1 1] [1 2]] 和 [[1 1] [1 0] [1 2]] 可以被视为两个图形组合
> - 返回的坐标为原始形状的坐标
>
> 可通过可选项对搜索结果进行过滤
***
#### func (Shape) Edges() (edges []LineSegment[V])
> 获取该形状每一条边
> - 该形状需要最少由3个点组成否则将不会返回任意一边
***
#### func (Shape) IsPointOnEdge(point Point[V]) bool
> 检查点是否在该形状的一条边上
***
### ShapeSearchOption
图形搜索可选项,用于 Shape.ShapeSearch 搜索支持
```go
type ShapeSearchOption struct{}
```

View File

@ -0,0 +1,64 @@
# Astar
astar 提供用于实现 A* 算法的函数和数据结构。A* 算法是一种常用的路径搜索算法,用于在图形或网络中找到最短路径。该包旨在简化 A* 算法的实现过程,并提供一致的接口和易于使用的功能。
主要特性:
- 图形表示astar 包支持使用图形或网络来表示路径搜索的环境。您可以定义节点和边,以构建图形,并在其中执行路径搜索。
- A* 算法:该包提供了 A* 算法的实现用于在图形中找到最短路径。A* 算法使用启发式函数来评估节点的优先级,并选择最有希望的节点进行扩展,以达到最短路径的目标。
- 自定义启发式函数:您可以根据具体问题定义自己的启发式函数,以指导 A* 算法的搜索过程。启发式函数用于估计从当前节点到目标节点的代价,以帮助算法选择最佳路径。
- 可定制性astar 包提供了一些可定制的选项,以满足不同场景下的需求。您可以设置节点的代价、边的权重等参数,以调整算法的行为。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/astar)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Find](#Find)|使用 A* 算法在导航网格上查找从起点到终点的最短路径,并返回路径上的节点序列。
> 结构体定义
|结构体|描述
|:--|:--
|[Graph](#graph)|适用于 A* 算法的图数据结构接口定义,表示导航网格,其中包含了节点和连接节点的边。
</details>
#### func Find(graph Graph[Node], start Node, end Node, cost func (a Node) V, heuristic func (a Node) V) []Node
<span id="Find"></span>
> 使用 A* 算法在导航网格上查找从起点到终点的最短路径,并返回路径上的节点序列。
>
> 参数:
> - graph: 图对象,类型为 Graph[Node],表示导航网格。
> - start: 起点节点,类型为 Node表示路径的起点。
> - end: 终点节点,类型为 Node表示路径的终点。
> - cost: 路径代价函数,类型为 func(a, b Node) V用于计算两个节点之间的代价。
> - heuristic: 启发函数,类型为 func(a, b Node) V用于估计从当前节点到目标节点的启发式代价。
>
> 返回值:
> - []Node: 节点序列,表示从起点到终点的最短路径。如果找不到路径,则返回空序列。
>
> 注意事项:
> - graph 对象表示导航网格,其中包含了节点和连接节点的边。
> - start 和 end 分别表示路径的起点和终点。
> - cost 函数用于计算两个节点之间的代价,可以根据实际情况自定义实现。
> - heuristic 函数用于估计从当前节点到目标节点的启发式代价,可以根据实际情况自定义实现。
> - 函数使用了 A* 算法来搜索最短路径。
> - 函数内部使用了堆数据结构来管理待处理的节点。
> - 函数返回一个节点序列,表示从起点到终点的最短路径。如果找不到路径,则返回空序列。
***
### Graph
适用于 A* 算法的图数据结构接口定义,表示导航网格,其中包含了节点和连接节点的边。
```go
type Graph[Node comparable] struct{}
```
#### func (Graph) Neighbours(point geometry.Point[int]) []geometry.Point[int]
***

View File

@ -0,0 +1,81 @@
# Dp
dp (DistributionPattern) 提供用于在二维数组中根据不同的特征标记为数组成员建立分布链接的函数和数据结构。该包的目标是实现快速查找与给定位置成员具有相同特征且位置紧邻的其他成员。
主要特性:
- 分布链接机制dp 包提供了一种分布链接的机制,可以根据成员的特征将它们链接在一起。这样,可以快速查找与给定成员具有相同特征且位置紧邻的其他成员。
- 二维数组支持:该包支持在二维数组中建立分布链接。可以将二维数组中的成员视为节点,并根据其特征进行链接。
- 快速查找功能:使用 dp 包提供的函数,可以快速查找与给定位置成员具有相同特征且位置紧邻的其他成员。这有助于在二维数组中进行相关性分析或查找相邻成员。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/dp)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewDistributionPattern](#NewDistributionPattern)|构建一个分布图实例
> 结构体定义
|结构体|描述
|:--|:--
|[DistributionPattern](#distributionpattern)|分布图
|[Link](#link)|暂无描述...
</details>
#### func NewDistributionPattern(sameKindVerifyHandle func (itemA Item) bool) *DistributionPattern[Item]
<span id="NewDistributionPattern"></span>
> 构建一个分布图实例
***
### DistributionPattern
分布图
```go
type DistributionPattern[Item any] struct {
matrix []Item
links map[int]map[int]Item
sameKindVerifyHandle func(itemA Item) bool
width int
usePos bool
}
```
#### func (*DistributionPattern) GetLinks(pos int) (result []Link[Item])
> 获取关联的成员
> - 其中包含传入的 pos 成员
***
#### func (*DistributionPattern) HasLink(pos int) bool
> 检查一个位置是否包含除它本身外的其他关联成员
***
#### func (*DistributionPattern) LoadMatrix(matrix [][]Item)
> 通过二维矩阵加载分布图
> - 通过该函数加载的分布图使用的矩阵是复制后的矩阵,因此无法直接通过刷新(Refresh)来更新分布关系
> - 需要通过直接刷新的方式请使用 LoadMatrixWithPos
***
#### func (*DistributionPattern) LoadMatrixWithPos(width int, matrix []Item)
> 通过二维矩阵加载分布图
***
#### func (*DistributionPattern) Refresh(pos int)
> 刷新特定位置的分布关系
> - 由于 LoadMatrix 的矩阵是复制后的矩阵,所以任何外部的改动都不会影响到分布图的变化,在这种情况下,刷新将没有任何意义
> - 需要通过直接刷新的方式请使用 LoadMatrixWithPos 加载矩阵,或者通过 RefreshWithItem 函数进行刷新
***
#### func (*DistributionPattern) RefreshWithItem(pos int, item Item)
> 通过特定的成员刷新特定位置的分布关系
> - 如果矩阵通过 LoadMatrixWithPos 加载,将会重定向至 Refresh
***
### Link
```go
type Link[V any] struct {
Pos int
Item V
}
```

View File

@ -0,0 +1,93 @@
# Matrix
matrix 提供了一个简单的二维数组的实现
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/matrix)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewMatrix](#NewMatrix)|生成特定宽高的二维矩阵
> 结构体定义
|结构体|描述
|:--|:--
|[Matrix](#matrix)|二维矩阵
</details>
#### func NewMatrix(width int, height int) *Matrix[T]
<span id="NewMatrix"></span>
> 生成特定宽高的二维矩阵
> - 虽然提供了通过x、y坐标的操作函数但是建议无论如何使用pos进行处理
> - 该矩阵为XY而非YX
***
### Matrix
二维矩阵
```go
type Matrix[T any] struct {
w int
h int
m []T
}
```
#### func (*Matrix) GetWidth() int
> 获取二维矩阵宽度
***
#### func (*Matrix) GetHeight() int
> 获取二维矩阵高度
***
#### func (*Matrix) GetWidth2Height() (width int, height int)
> 获取二维矩阵的宽度和高度
***
#### func (*Matrix) GetMatrix() [][]T
> 获取二维矩阵
> - 通常建议使用 GetMatrixWithPos 进行处理这样将拥有更高的效率
***
#### func (*Matrix) GetMatrixWithPos() []T
> 获取顺序的矩阵
***
#### func (*Matrix) Get(x int, y int) (value T)
> 获取特定坐标的内容
***
#### func (*Matrix) GetExist(x int, y int) (value T, exist bool)
> 获取特定坐标的内容,如果不存在则返回 false
***
#### func (*Matrix) GetWithPos(pos int) (value T)
> 获取特定坐标的内容
***
#### func (*Matrix) Set(x int, y int, data T)
> 设置特定坐标的内容
***
#### func (*Matrix) SetWithPos(pos int, data T)
> 设置特定坐标的内容
***
#### func (*Matrix) Swap(x1 int, y1 int, x2 int, y2 int)
> 交换两个位置的内容
***
#### func (*Matrix) SwapWithPos(pos1 int, pos2 int)
> 交换两个位置的内容
***
#### func (*Matrix) TrySwap(x1 int, y1 int, x2 int, y2 int, expressionHandle func (matrix *Matrix[T]) bool)
> 尝试交换两个位置的内容,交换后不满足表达式时进行撤销
***
#### func (*Matrix) TrySwapWithPos(pos1 int, pos2 int, expressionHandle func (matrix *Matrix[T]) bool)
> 尝试交换两个位置的内容,交换后不满足表达式时进行撤销
***
#### func (*Matrix) FillFull(generateHandle func (x int) T)
> 根据提供的生成器填充整个矩阵
***
#### func (*Matrix) FillFullWithPos(generateHandle func (pos int) T)
> 根据提供的生成器填充整个矩阵
***

View File

@ -0,0 +1,97 @@
# Navmesh
navmesh 提供了用于导航网格处理的函数和数据结构。导航网格是一种常用的数据结构,用于在游戏开发和虚拟环境中进行路径规划和导航。该包旨在简化导航网格的创建、查询和操作过程,并提供高效的导航功能。
主要特性:
- 导航网格表示navmesh 包支持使用导航网格来表示虚拟环境中的可行走区域和障碍物。您可以定义多边形区域和连接关系,以构建导航网格,并在其中执行路径规划和导航。
- 导航算法:采用了 A* 算法作为导航算法,用于在导航网格中找到最短路径或最优路径。这些算法使用启发式函数和代价评估来指导路径搜索,并提供高效的路径规划能力。
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/navmesh)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewNavMesh](#NewNavMesh)|创建一个新的导航网格,并返回一个指向该导航网格的指针。
> 结构体定义
|结构体|描述
|:--|:--
|[NavMesh](#navmesh)|暂无描述...
</details>
#### func NewNavMesh(shapes []geometry.Shape[V], meshShrinkAmount V) *NavMesh[V]
<span id="NewNavMesh"></span>
> 创建一个新的导航网格,并返回一个指向该导航网格的指针。
>
> 参数:
> - shapes: 形状切片,类型为 []geometry.Shape[V],表示导航网格中的形状。
> - meshShrinkAmount: 网格缩小量,类型为 V表示导航网格的缩小量。
>
> 返回值:
> - *NavMesh[V]: 指向创建的导航网格的指针。
>
> 注意事项:
> - 导航网格的形状可以是任何几何形状。
> - meshShrinkAmount 表示导航网格的缩小量,用于在形状之间创建链接时考虑形状的缩小效果。
> - 函数内部使用了泛型类型参数 V可以根据需要指定形状的坐标类型。
> - 函数返回一个指向创建的导航网格的指针。
>
> 使用建议:
> - 确保 NavMesh 计算精度的情况下V 建议使用 float64 类型
***
### NavMesh
```go
type NavMesh[V generic.SignedNumber] struct {
meshShapes []*shape[V]
meshShrinkAmount V
}
```
#### func (*NavMesh) Neighbours(node *shape[V]) []*shape[V]
> 实现 astar.Graph 的接口,用于向 A* 算法提供相邻图形
***
#### func (*NavMesh) Find(point geometry.Point[V], maxDistance V) (distance V, findPoint geometry.Point[V], findShape geometry.Shape[V])
> 用于在 NavMesh 中查找离给定点最近的形状,并返回距离、找到的点和找到的形状。
>
> 参数:
> - point: 给定的点,类型为 geometry.Point[V],表示一个 V 维度的点坐标。
> - maxDistance: 最大距离,类型为 V表示查找的最大距离限制。
>
> 返回值:
> - distance: 距离,类型为 V表示离给定点最近的形状的距离。
> - findPoint: 找到的点,类型为 geometry.Point[V],表示离给定点最近的点坐标。
> - findShape: 找到的形状,类型为 geometry.Shape[V],表示离给定点最近的形状。
>
> 注意事项:
> - 如果给定点在 NavMesh 中的某个形状内部或者在形状的边上,距离为 0找到的形状为该形状找到的点为给定点。
> - 如果给定点不在任何形状内部或者形状的边上,将计算给定点到每个形状的距离,并找到最近的形状和对应的点。
> - 距离的计算采用几何学中的投影点到形状的距离。
> - 函数返回离给定点最近的形状的距离、找到的点和找到的形状。
***
#### func (*NavMesh) FindPath(start geometry.Point[V], end geometry.Point[V]) (result []geometry.Point[V])
> 函数用于在 NavMesh 中查找从起点到终点的路径,并返回路径上的点序列。
>
> 参数:
> - start: 起点,类型为 geometry.Point[V],表示路径的起始点。
> - end: 终点,类型为 geometry.Point[V],表示路径的终点。
>
> 返回值:
> - result: 路径上的点序列,类型为 []geometry.Point[V]。
>
> 注意事项:
> - 函数首先根据起点和终点的位置,找到离它们最近的形状作为起点形状和终点形状。
> - 如果起点或终点不在任何形状内部,且 NavMesh 的 meshShrinkAmount 大于0则会考虑缩小的形状。
> - 使用 A* 算法在 NavMesh 上搜索从起点形状到终点形状的最短路径。
> - 使用漏斗算法对路径进行优化,以得到最终的路径点序列。
***

48
utils/hub/README.md Normal file
View File

@ -0,0 +1,48 @@
# Hub
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/hub)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewObjectPool](#NewObjectPool)|创建一个 ObjectPool
> 结构体定义
|结构体|描述
|:--|:--
|[ObjectPool](#objectpool)|基于 sync.Pool 实现的线程安全的对象池
</details>
#### func NewObjectPool(generator func () *T, releaser func (data *T)) *ObjectPool[*T]
<span id="NewObjectPool"></span>
> 创建一个 ObjectPool
***
### ObjectPool
基于 sync.Pool 实现的线程安全的对象池
- 一些高频临时生成使用的对象可以通过 ObjectPool 进行管理,例如属性计算等
```go
type ObjectPool[T any] struct {
p sync.Pool
releaser func(data T)
}
```
#### func (*ObjectPool) Get() T
> 获取一个对象
***
#### func (*ObjectPool) Release(data T)
> 将使用完成的对象放回缓冲区
***

372
utils/huge/README.md Normal file
View File

@ -0,0 +1,372 @@
# Huge
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/huge)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewFloat](#NewFloat)|创建一个 Float
|[NewFloatByString](#NewFloatByString)|通过字符串创建一个 Float
|[NewInt](#NewInt)|创建一个 Int
|[NewIntByString](#NewIntByString)|通过字符串创建一个 Int
> 结构体定义
|结构体|描述
|:--|:--
|[Float](#float)|暂无描述...
|[Int](#int)|暂无描述...
</details>
#### func NewFloat(x T) *Float
<span id="NewFloat"></span>
> 创建一个 Float
***
#### func NewFloatByString(i string) *Float
<span id="NewFloatByString"></span>
> 通过字符串创建一个 Float
> - 如果字符串不是一个合法的数字,则返回 0
***
#### func NewInt(x T) *Int
<span id="NewInt"></span>
> 创建一个 Int
***
#### func NewIntByString(i string) *Int
<span id="NewIntByString"></span>
> 通过字符串创建一个 Int
> - 如果字符串不是一个合法的数字,则返回 0
***
### Float
```go
type Float struct{}
```
#### func (*Float) Copy() *Float
***
#### func (*Float) Set(i *Float) *Float
***
#### func (*Float) IsZero() bool
***
#### func (*Float) ToBigFloat() *big.Float
***
#### func (*Float) Cmp(i *Float) int
> 比较,当 slf > i 时返回 1当 slf < i 时返回 -1 slf == i 时返回 0
***
#### func (*Float) GreaterThan(i *Float) bool
> 大于
***
#### func (*Float) GreaterThanOrEqualTo(i *Float) bool
> 大于或等于
***
#### func (*Float) LessThan(i *Float) bool
> 小于
***
#### func (*Float) LessThanOrEqualTo(i *Float) bool
> 小于或等于
***
#### func (*Float) EqualTo(i *Float) bool
> 等于
***
#### func (*Float) Float64() float64
***
#### func (*Float) String() string
***
#### func (*Float) Add(i *Float) *Float
***
#### func (*Float) Sub(i *Float) *Float
***
#### func (*Float) Mul(i *Float) *Float
***
#### func (*Float) Div(i *Float) *Float
***
#### func (*Float) Sqrt() *Float
> 平方根
***
#### func (*Float) Abs() *Float
> 返回数字的绝对值
***
#### func (*Float) Sign() int
> 返回数字的符号
> - 1正数
> - 0
> - -1负数
***
#### func (*Float) IsPositive() bool
> 是否为正数
***
#### func (*Float) IsNegative() bool
> 是否为负数
***
### Int
```go
type Int struct{}
```
#### func (*Int) Copy() *Int
***
#### func (*Int) Set(i *Int) *Int
***
#### func (*Int) SetInt(i int) *Int
***
#### func (*Int) SetInt8(i int8) *Int
***
#### func (*Int) SetInt16(i int16) *Int
***
#### func (*Int) SetInt32(i int32) *Int
***
#### func (*Int) SetInt64(i int64) *Int
***
#### func (*Int) SetUint(i uint) *Int
***
#### func (*Int) SetUint8(i uint8) *Int
***
#### func (*Int) SetUint16(i uint16) *Int
***
#### func (*Int) SetUint32(i uint32) *Int
***
#### func (*Int) SetUint64(i uint64) *Int
***
#### func (*Int) IsZero() bool
***
#### func (*Int) ToBigint() *big.Int
***
#### func (*Int) Cmp(i *Int) int
> 比较,当 slf > i 时返回 1当 slf < i 时返回 -1 slf == i 时返回 0
***
#### func (*Int) GreaterThan(i *Int) bool
> 大于
***
#### func (*Int) GreaterThanOrEqualTo(i *Int) bool
> 大于或等于
***
#### func (*Int) LessThan(i *Int) bool
> 小于
***
#### func (*Int) LessThanOrEqualTo(i *Int) bool
> 小于或等于
***
#### func (*Int) EqualTo(i *Int) bool
> 等于
***
#### func (*Int) Int64() int64
***
#### func (*Int) String() string
***
#### func (*Int) Add(i *Int) *Int
***
#### func (*Int) AddInt(i int) *Int
***
#### func (*Int) AddInt8(i int8) *Int
***
#### func (*Int) AddInt16(i int16) *Int
***
#### func (*Int) AddInt32(i int32) *Int
***
#### func (*Int) AddInt64(i int64) *Int
***
#### func (*Int) AddUint(i uint) *Int
***
#### func (*Int) AddUint8(i uint8) *Int
***
#### func (*Int) AddUint16(i uint16) *Int
***
#### func (*Int) AddUint32(i uint32) *Int
***
#### func (*Int) AddUint64(i uint64) *Int
***
#### func (*Int) Mul(i *Int) *Int
***
#### func (*Int) MulInt(i int) *Int
***
#### func (*Int) MulInt8(i int8) *Int
***
#### func (*Int) MulInt16(i int16) *Int
***
#### func (*Int) MulInt32(i int32) *Int
***
#### func (*Int) MulInt64(i int64) *Int
***
#### func (*Int) MulUint(i uint) *Int
***
#### func (*Int) MulUint8(i uint8) *Int
***
#### func (*Int) MulUint16(i uint16) *Int
***
#### func (*Int) MulUint32(i uint32) *Int
***
#### func (*Int) MulUint64(i uint64) *Int
***
#### func (*Int) Sub(i *Int) *Int
***
#### func (*Int) SubInt(i int) *Int
***
#### func (*Int) SubInt8(i int8) *Int
***
#### func (*Int) SubInt16(i int16) *Int
***
#### func (*Int) SubInt32(i int32) *Int
***
#### func (*Int) SubInt64(i int64) *Int
***
#### func (*Int) SubUint(i uint) *Int
***
#### func (*Int) SubUint8(i uint8) *Int
***
#### func (*Int) SubUint16(i uint16) *Int
***
#### func (*Int) SubUint32(i uint32) *Int
***
#### func (*Int) SubUint64(i uint64) *Int
***
#### func (*Int) Div(i *Int) *Int
***
#### func (*Int) DivInt(i int) *Int
***
#### func (*Int) DivInt8(i int8) *Int
***
#### func (*Int) DivInt16(i int16) *Int
***
#### func (*Int) DivInt32(i int32) *Int
***
#### func (*Int) DivInt64(i int64) *Int
***
#### func (*Int) DivUint(i uint) *Int
***
#### func (*Int) DivUint8(i uint8) *Int
***
#### func (*Int) DivUint16(i uint16) *Int
***
#### func (*Int) DivUint32(i uint32) *Int
***
#### func (*Int) DivUint64(i uint64) *Int
***
#### func (*Int) Mod(i *Int) *Int
***
#### func (*Int) ModInt(i int) *Int
***
#### func (*Int) ModInt8(i int8) *Int
***
#### func (*Int) ModInt16(i int16) *Int
***
#### func (*Int) ModInt32(i int32) *Int
***
#### func (*Int) ModInt64(i int64) *Int
***
#### func (*Int) ModUint(i uint) *Int
***
#### func (*Int) ModUint8(i uint8) *Int
***
#### func (*Int) ModUint16(i uint16) *Int
***
#### func (*Int) ModUint32(i uint32) *Int
***
#### func (*Int) ModUint64(i uint64) *Int
***
#### func (*Int) Pow(i *Int) *Int
***
#### func (*Int) PowInt(i int) *Int
***
#### func (*Int) PowInt8(i int8) *Int
***
#### func (*Int) PowInt16(i int16) *Int
***
#### func (*Int) PowInt32(i int32) *Int
***
#### func (*Int) PowInt64(i int64) *Int
***
#### func (*Int) PowUint(i uint) *Int
***
#### func (*Int) PowUint8(i uint8) *Int
***
#### func (*Int) PowUint16(i uint16) *Int
***
#### func (*Int) PowUint32(i uint32) *Int
***
#### func (*Int) PowUint64(i uint64) *Int
***
#### func (*Int) Lsh(i int) *Int
> 左移
***
#### func (*Int) Rsh(i int) *Int
> 右移
***
#### func (*Int) And(i *Int) *Int
> 与
***
#### func (*Int) AndNot(i *Int) *Int
> 与非
***
#### func (*Int) Or(i *Int) *Int
> 或
***
#### func (*Int) Xor(i *Int) *Int
> 异或
***
#### func (*Int) Not() *Int
> 非
***
#### func (*Int) Sqrt() *Int
> 平方根
***
#### func (*Int) GCD(i *Int) *Int
> 最大公约数
***
#### func (*Int) LCM(i *Int) *Int
> 最小公倍数
***
#### func (*Int) ModInverse(i *Int) *Int
> 模反元素
***
#### func (*Int) ModSqrt(i *Int) *Int
> 模平方根
***
#### func (*Int) BitLen() int
> 二进制长度
***
#### func (*Int) Bit(i int) uint
> 二进制位
***
#### func (*Int) SetBit(i int, v uint) *Int
> 设置二进制位
***
#### func (*Int) Neg() *Int
> 返回数字的相反数
***
#### func (*Int) Abs() *Int
> 返回数字的绝对值
***
#### func (*Int) Sign() int
> 返回数字的符号
> - 1正数
> - 0
> - -1负数
***
#### func (*Int) IsPositive() bool
> 是否为正数
***
#### func (*Int) IsNegative() bool
> 是否为负数
***
#### func (*Int) IsEven() bool
> 是否为偶数
***
#### func (*Int) IsOdd() bool
> 是否为奇数
***
#### func (*Int) ProportionalCalc(proportional *Int, formula func (v *Int) *Int) *Int
> 比例计算,该函数会再 formula 返回值的基础上除以 proportional
> - formula 为计算公式,该公式的参数为调用该函数的 Int 的拷贝
***

View File

@ -0,0 +1,70 @@
# Leaderboard
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/leaderboard)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewBinarySearch](#NewBinarySearch)|创建一个基于内存的二分查找排行榜
|[WithBinarySearchCount](#WithBinarySearchCount)|通过限制排行榜竞争者数量来创建排行榜
|[WithBinarySearchASC](#WithBinarySearchASC)|通过升序的方式创建排行榜
> 结构体定义
|结构体|描述
|:--|:--
|[BinarySearch](#binarysearch)|暂无描述...
|[BinarySearchRankChangeEventHandle](#binarysearchrankchangeeventhandle)|暂无描述...
|[BinarySearchOption](#binarysearchoption)|暂无描述...
</details>
#### func NewBinarySearch(options ...BinarySearchOption[CompetitorID, Score]) *BinarySearch[CompetitorID, Score]
<span id="NewBinarySearch"></span>
> 创建一个基于内存的二分查找排行榜
***
#### func WithBinarySearchCount(rankCount int) BinarySearchOption[CompetitorID, Score]
<span id="WithBinarySearchCount"></span>
> 通过限制排行榜竞争者数量来创建排行榜
> - 默认情况下允许100位竞争者
***
#### func WithBinarySearchASC() BinarySearchOption[CompetitorID, Score]
<span id="WithBinarySearchASC"></span>
> 通过升序的方式创建排行榜
> - 默认情况下为降序
***
### BinarySearch
```go
type BinarySearch[CompetitorID comparable, Score generic.Ordered] struct {
*binarySearchEvent[CompetitorID, Score]
asc bool
rankCount int
competitors *mappings.SyncMap[CompetitorID, Score]
scores []*scoreItem[CompetitorID, Score]
rankChangeEventHandles []BinarySearchRankChangeEventHandle[CompetitorID, Score]
rankClearBeforeEventHandles []BinarySearchRankClearBeforeEventHandle[CompetitorID, Score]
}
```
### BinarySearchRankChangeEventHandle
```go
type BinarySearchRankChangeEventHandle[CompetitorID comparable, Score generic.Ordered] struct{}
```
### BinarySearchOption
```go
type BinarySearchOption[CompetitorID comparable, Score generic.Ordered] struct{}
```

342
utils/log/README.md Normal file
View File

@ -0,0 +1,342 @@
# Log
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/log)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[CallerBasicFormat](#CallerBasicFormat)|返回调用者的基本格式
|[Println](#Println)|暂无描述...
|[Default](#Default)|获取默认的日志记录器
|[SetDefault](#SetDefault)|设置默认的日志记录器
|[SetDefaultBySlog](#SetDefaultBySlog)|设置默认的日志记录器
|[Debug](#Debug)|在 DebugLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Info](#Info)|在 InfoLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Warn](#Warn)|在 WarnLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Error](#Error)|在 ErrorLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[DPanic](#DPanic)|在 DPanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Panic](#Panic)|在 PanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Fatal](#Fatal)|在 FatalLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|[Skip](#Skip)|构造一个无操作字段,这在处理其他 Field 构造函数中的无效输入时通常很有用
|[Duration](#Duration)|使用给定的键和值构造一个字段。编码器控制持续时间的序列化方式
|[DurationP](#DurationP)|构造一个带有 time.Duration 的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Bool](#Bool)|构造一个带有布尔值的字段
|[BoolP](#BoolP)|构造一个带有布尔值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[String](#String)|构造一个带有字符串值的字段
|[StringP](#StringP)|构造一个带有字符串值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Int](#Int)|构造一个带有整数值的字段
|[IntP](#IntP)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Int8](#Int8)|构造一个带有整数值的字段
|[Int8P](#Int8P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Int16](#Int16)|构造一个带有整数值的字段
|[Int16P](#Int16P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Int32](#Int32)|构造一个带有整数值的字段
|[Int32P](#Int32P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Int64](#Int64)|构造一个带有整数值的字段
|[Int64P](#Int64P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Uint](#Uint)|构造一个带有整数值的字段
|[UintP](#UintP)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Uint8](#Uint8)|构造一个带有整数值的字段
|[Uint8P](#Uint8P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Uint16](#Uint16)|构造一个带有整数值的字段
|[Uint16P](#Uint16P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Uint32](#Uint32)|构造一个带有整数值的字段
|[Uint32P](#Uint32P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Uint64](#Uint64)|构造一个带有整数值的字段
|[Uint64P](#Uint64P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Float](#Float)|构造一个带有浮点值的字段
|[FloatP](#FloatP)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Float32](#Float32)|构造一个带有浮点值的字段
|[Float32P](#Float32P)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Float64](#Float64)|构造一个带有浮点值的字段
|[Float64P](#Float64P)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Time](#Time)|构造一个带有时间值的字段
|[TimeP](#TimeP)|构造一个带有时间值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|[Any](#Any)|构造一个带有任意值的字段
|[Group](#Group)|返回分组字段
|[Stack](#Stack)|返回堆栈字段
|[Err](#Err)|构造一个带有错误值的字段
|[NewHandler](#NewHandler)|创建一个更偏向于人类可读的处理程序,该处理程序也是默认的处理程序
|[NewLogger](#NewLogger)|创建一个新的日志记录器
|[NewMultiHandler](#NewMultiHandler)|创建一个新的多处理程序
|[NewOptions](#NewOptions)|创建一个新的日志选项
> 结构体定义
|结构体|描述
|:--|:--
|[Field](#field)|暂无描述...
|[Logger](#logger)|暂无描述...
|[MultiHandler](#multihandler)|暂无描述...
|[Option](#option)|暂无描述...
</details>
#### func CallerBasicFormat(file string, line int) (repFile string, refLine string)
<span id="CallerBasicFormat"></span>
> 返回调用者的基本格式
***
#### func Println(str string, color string, desc string)
<span id="Println"></span>
***
#### func Default() *Logger
<span id="Default"></span>
> 获取默认的日志记录器
***
#### func SetDefault(l *Logger)
<span id="SetDefault"></span>
> 设置默认的日志记录器
***
#### func SetDefaultBySlog(l *slog.Logger)
<span id="SetDefaultBySlog"></span>
> 设置默认的日志记录器
***
#### func Debug(msg string, args ...any)
<span id="Debug"></span>
> 在 DebugLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
***
#### func Info(msg string, args ...any)
<span id="Info"></span>
> 在 InfoLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
***
#### func Warn(msg string, args ...any)
<span id="Warn"></span>
> 在 WarnLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
***
#### func Error(msg string, args ...any)
<span id="Error"></span>
> 在 ErrorLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
***
#### func DPanic(msg string, args ...any)
<span id="DPanic"></span>
> 在 DPanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
> - 如果记录器处于开发模式,它就会出现 panicDPanic 的意思是“development panic”。这对于捕获可恢复但不应该发生的错误很有用
> - 该 panic 仅在 NewHandler 中创建的处理器会生效
***
#### func Panic(msg string, args ...any)
<span id="Panic"></span>
> 在 PanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
> - 即使禁用了 PanicLevel 的日志记录,记录器也会出现 panic
***
#### func Fatal(msg string, args ...any)
<span id="Fatal"></span>
> 在 FatalLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
> - 然后记录器调用 os.Exit(1),即使 FatalLevel 的日志记录被禁用
***
#### func Skip(vs ...any) slog.Attr
<span id="Skip"></span>
> 构造一个无操作字段,这在处理其他 Field 构造函数中的无效输入时通常很有用
> - 该函数还支持将其他字段快捷的转换为 Skip 字段
***
#### func Duration(key string, val time.Duration) slog.Attr
<span id="Duration"></span>
> 使用给定的键和值构造一个字段。编码器控制持续时间的序列化方式
***
#### func DurationP(key string, val *time.Duration) slog.Attr
<span id="DurationP"></span>
> 构造一个带有 time.Duration 的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Bool(key string, val bool) slog.Attr
<span id="Bool"></span>
> 构造一个带有布尔值的字段
***
#### func BoolP(key string, val *bool) slog.Attr
<span id="BoolP"></span>
> 构造一个带有布尔值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func String(key string, val string) slog.Attr
<span id="String"></span>
> 构造一个带有字符串值的字段
***
#### func StringP(key string, val *string) slog.Attr
<span id="StringP"></span>
> 构造一个带有字符串值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Int(key string, val I) slog.Attr
<span id="Int"></span>
> 构造一个带有整数值的字段
***
#### func IntP(key string, val *I) slog.Attr
<span id="IntP"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Int8(key string, val I) slog.Attr
<span id="Int8"></span>
> 构造一个带有整数值的字段
***
#### func Int8P(key string, val *I) slog.Attr
<span id="Int8P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Int16(key string, val I) slog.Attr
<span id="Int16"></span>
> 构造一个带有整数值的字段
***
#### func Int16P(key string, val *I) slog.Attr
<span id="Int16P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Int32(key string, val I) slog.Attr
<span id="Int32"></span>
> 构造一个带有整数值的字段
***
#### func Int32P(key string, val *I) slog.Attr
<span id="Int32P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Int64(key string, val I) slog.Attr
<span id="Int64"></span>
> 构造一个带有整数值的字段
***
#### func Int64P(key string, val *I) slog.Attr
<span id="Int64P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Uint(key string, val I) slog.Attr
<span id="Uint"></span>
> 构造一个带有整数值的字段
***
#### func UintP(key string, val *I) slog.Attr
<span id="UintP"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Uint8(key string, val I) slog.Attr
<span id="Uint8"></span>
> 构造一个带有整数值的字段
***
#### func Uint8P(key string, val *I) slog.Attr
<span id="Uint8P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Uint16(key string, val I) slog.Attr
<span id="Uint16"></span>
> 构造一个带有整数值的字段
***
#### func Uint16P(key string, val *I) slog.Attr
<span id="Uint16P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Uint32(key string, val I) slog.Attr
<span id="Uint32"></span>
> 构造一个带有整数值的字段
***
#### func Uint32P(key string, val *I) slog.Attr
<span id="Uint32P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Uint64(key string, val I) slog.Attr
<span id="Uint64"></span>
> 构造一个带有整数值的字段
***
#### func Uint64P(key string, val *I) slog.Attr
<span id="Uint64P"></span>
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Float(key string, val F) slog.Attr
<span id="Float"></span>
> 构造一个带有浮点值的字段
***
#### func FloatP(key string, val *F) slog.Attr
<span id="FloatP"></span>
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Float32(key string, val F) slog.Attr
<span id="Float32"></span>
> 构造一个带有浮点值的字段
***
#### func Float32P(key string, val *F) slog.Attr
<span id="Float32P"></span>
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Float64(key string, val F) slog.Attr
<span id="Float64"></span>
> 构造一个带有浮点值的字段
***
#### func Float64P(key string, val *F) slog.Attr
<span id="Float64P"></span>
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Time(key string, val time.Time) slog.Attr
<span id="Time"></span>
> 构造一个带有时间值的字段
***
#### func TimeP(key string, val *time.Time) slog.Attr
<span id="TimeP"></span>
> 构造一个带有时间值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
***
#### func Any(key string, val any) slog.Attr
<span id="Any"></span>
> 构造一个带有任意值的字段
***
#### func Group(key string, args ...any) slog.Attr
<span id="Group"></span>
> 返回分组字段
***
#### func Stack(key string) slog.Attr
<span id="Stack"></span>
> 返回堆栈字段
***
#### func Err(err error) slog.Attr
<span id="Err"></span>
> 构造一个带有错误值的字段
***
#### func NewHandler(w io.Writer, opts *Options) slog.Handler
<span id="NewHandler"></span>
> 创建一个更偏向于人类可读的处理程序,该处理程序也是默认的处理程序
***
#### func NewLogger(handlers ...slog.Handler) *Logger
<span id="NewLogger"></span>
> 创建一个新的日志记录器
***
#### func NewMultiHandler(handlers ...slog.Handler) slog.Handler
<span id="NewMultiHandler"></span>
> 创建一个新的多处理程序
***
#### func NewOptions() *Options
<span id="NewOptions"></span>
> 创建一个新的日志选项
***
### Field
```go
type Field struct{}
```
### Logger
```go
type Logger struct {
*slog.Logger
}
```
### MultiHandler
```go
type MultiHandler struct {
handlers []slog.Handler
}
```
#### func (MultiHandler) Enabled(ctx context.Context, level slog.Level) bool
***
#### func (MultiHandler) Handle(ctx context.Context, record slog.Record) (err error)
***
#### func (MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler
***
#### func (MultiHandler) WithGroup(name string) slog.Handler
***
### Option
```go
type Option struct{}
```

247
utils/log/survey/README.md Normal file
View File

@ -0,0 +1,247 @@
# Survey
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/survey)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewFileFlusher](#NewFileFlusher)|创建一个文件刷新器
|[WithFlushInterval](#WithFlushInterval)|设置日志文件刷新间隔
|[Reg](#Reg)|注册一个运营日志记录器
|[Record](#Record)|记录一条运营日志
|[RecordBytes](#RecordBytes)|记录一条运营日志
|[Flush](#Flush)|将运营日志记录器的缓冲区数据写入到文件
|[Close](#Close)|关闭运营日志记录器
|[Analyze](#Analyze)|分析特定文件的记录,当发生错误时,会发生 panic
|[AnalyzeMulti](#AnalyzeMulti)|与 Analyze 类似,但是可以分析多个文件
|[IncrementAnalyze](#IncrementAnalyze)|增量分析,返回一个函数,每次调用该函数都会分析文件中新增的内容
> 结构体定义
|结构体|描述
|:--|:--
|[Analyzer](#analyzer)|分析器
|[Flusher](#flusher)|用于刷新缓冲区的接口
|[FileFlusher](#fileflusher)|暂无描述...
|[Option](#option)|选项
|[Result](#result)|暂无描述...
|[R](#r)|记录器所记录的一条数据
|[Report](#report)|分析报告
</details>
#### func NewFileFlusher(filePath string, layout ...string) *FileFlusher
<span id="NewFileFlusher"></span>
> 创建一个文件刷新器
> - layout 为日志文件名的时间戳格式 (默认为 time.DateOnly)
***
#### func WithFlushInterval(interval time.Duration) Option
<span id="WithFlushInterval"></span>
> 设置日志文件刷新间隔
> - 默认为 3s当日志文件刷新间隔 <= 0 时,将会在每次写入日志时刷新日志文件
***
#### func Reg(name string, flusher Flusher, options ...Option)
<span id="Reg"></span>
> 注册一个运营日志记录器
***
#### func Record(name string, data map[string]any)
<span id="Record"></span>
> 记录一条运营日志
***
#### func RecordBytes(name string, data []byte)
<span id="RecordBytes"></span>
> 记录一条运营日志
***
#### func Flush(names ...string)
<span id="Flush"></span>
> 将运营日志记录器的缓冲区数据写入到文件
> - name 为空时,将所有记录器的缓冲区数据写入到文件
***
#### func Close(names ...string)
<span id="Close"></span>
> 关闭运营日志记录器
***
#### func Analyze(filePath string, handle func (analyzer *Analyzer, record R)) *Report
<span id="Analyze"></span>
> 分析特定文件的记录,当发生错误时,会发生 panic
> - handle 为并行执行的,需要自行处理并发安全
> - 适用于外部进程对于日志文件的读取,但是需要注意的是,此时日志文件可能正在被写入,所以可能会读取到错误的数据
***
#### func AnalyzeMulti(filePaths []string, handle func (analyzer *Analyzer, record R)) *Report
<span id="AnalyzeMulti"></span>
> 与 Analyze 类似,但是可以分析多个文件
***
#### func IncrementAnalyze(filePath string, handle func (analyzer *Analyzer, record R)) func () *Report, error
<span id="IncrementAnalyze"></span>
> 增量分析,返回一个函数,每次调用该函数都会分析文件中新增的内容
***
### Analyzer
分析器
```go
type Analyzer struct {
v map[string]any
vc map[string]int64
repeat map[string]struct{}
subs map[string]*Analyzer
format map[string]func(v any) any
m sync.Mutex
}
```
#### func (*Analyzer) Sub(key string) *Analyzer
> 获取子分析器
***
#### func (*Analyzer) SetFormat(key string, format func (v any) any)
> 设置格式化函数
***
#### func (*Analyzer) SetValueIfGreaterThan(key string, value float64)
> 设置指定 key 的值,当新值大于旧值时
> - 当已有值不为 float64 时,将会被忽略
***
#### func (*Analyzer) SetValueIfLessThan(key string, value float64)
> 设置指定 key 的值,当新值小于旧值时
> - 当已有值不为 float64 时,将会被忽略
***
#### func (*Analyzer) SetValueIf(key string, expression bool, value float64)
> 当表达式满足的时候将设置指定 key 的值为 value
***
#### func (*Analyzer) SetValueStringIf(key string, expression bool, value string)
> 当表达式满足的时候将设置指定 key 的值为 value
***
#### func (*Analyzer) SetValue(key string, value float64)
> 设置指定 key 的值
***
#### func (*Analyzer) SetValueString(key string, value string)
> 设置指定 key 的值
***
#### func (*Analyzer) Increase(key string, record R, recordKey string)
> 在指定 key 现有值的基础上增加 recordKey 的值
> - 当分析器已经记录过相同 key 的值时,会根据已有的值类型进行不同处理
>
> 处理方式:
> - 当已有值类型为 string 时,将会使用新的值的 string 类型进行覆盖
> - 当已有值类型为 float64 时,当新的值类型不为 float64 时,将会被忽略
***
#### func (*Analyzer) IncreaseValue(key string, value float64)
> 在指定 key 现有值的基础上增加 value
***
#### func (*Analyzer) IncreaseNonRepeat(key string, record R, recordKey string, dimension ...string)
> 在指定 key 现有值的基础上增加 recordKey 的值,但是当去重维度 dimension 相同时,不会增加
***
#### func (*Analyzer) IncreaseValueNonRepeat(key string, record R, value float64, dimension ...string)
> 在指定 key 现有值的基础上增加 value但是当去重维度 dimension 相同时,不会增加
***
#### func (*Analyzer) GetValue(key string) float64
> 获取当前记录的值
***
#### func (*Analyzer) GetValueString(key string) string
> 获取当前记录的值
***
### Flusher
用于刷新缓冲区的接口
```go
type Flusher struct{}
```
### FileFlusher
```go
type FileFlusher struct {
dir string
fn string
fe string
layout string
layoutLen int
}
```
#### func (*FileFlusher) Flush(records []string)
***
#### func (*FileFlusher) Info() string
***
### Option
选项
```go
type Option struct{}
```
### Result
```go
type Result struct{}
```
### R
记录器所记录的一条数据
```go
type R struct{}
```
#### func (R) GetTime(layout string) time.Time
> 获取该记录的时间
***
#### func (R) Get(key string) Result
> 获取指定 key 的值
> - 当 key 为嵌套 key 时,使用 . 进行分割例如a.b.c
> - 更多用法参考https://github.com/tidwall/gjson
***
#### func (R) Exist(key string) bool
> 判断指定 key 是否存在
***
#### func (R) GetString(key string) string
> 该函数为 Get(key).String() 的简写
***
#### func (R) GetInt64(key string) int64
> 该函数为 Get(key).Int() 的简写
***
#### func (R) GetInt(key string) int
> 该函数为 Get(key).Int() 的简写,但是返回值为 int 类型
***
#### func (R) GetFloat64(key string) float64
> 该函数为 Get(key).Float() 的简写
***
#### func (R) GetBool(key string) bool
> 该函数为 Get(key).Bool() 的简写
***
#### func (R) String() string
***
### Report
分析报告
```go
type Report struct {
analyzer *Analyzer
Name string
Values map[string]any
Counter map[string]int64
Subs []*Report
}
```
#### func (*Report) Avg(key string) float64
> 计算平均值
***
#### func (*Report) Count(key string) int64
> 获取特定 key 的计数次数
***
#### func (*Report) Sum(keys ...string) float64
> 获取特定 key 的总和
***
#### func (*Report) Sub(name string) *Report
> 获取特定名称的子报告
***
#### func (*Report) ReserveSubByPrefix(prefix string) *Report
> 仅保留特定前缀的子报告
***
#### func (*Report) ReserveSub(names ...string) *Report
> 仅保留特定名称子报告
***
#### func (*Report) FilterSub(names ...string) *Report
> 将特定名称的子报告过滤掉
***
#### func (*Report) String() string
***

153
utils/maths/README.md Normal file
View File

@ -0,0 +1,153 @@
# Maths
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/maths)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Compare](#Compare)|根据特定表达式比较两个值
|[IsContinuity](#IsContinuity)|检查一组值是否连续
|[IsContinuityWithSort](#IsContinuityWithSort)|检查一组值排序后是否连续
|[GetDefaultTolerance](#GetDefaultTolerance)|获取默认误差范围
|[Pow](#Pow)|整数幂运算
|[PowInt64](#PowInt64)|整数幂运算
|[Min](#Min)|返回两个数之中较小的值
|[Max](#Max)|返回两个数之中较大的值
|[MinMax](#MinMax)|将两个数按照较小的和较大的顺序进行返回
|[MaxMin](#MaxMin)|将两个数按照较大的和较小的顺序进行返回
|[Clamp](#Clamp)|将给定值限制在最小值和最大值之间
|[Tolerance](#Tolerance)|检查两个值是否在一个误差范围内
|[Merge](#Merge)|通过一个参考值合并两个数字
|[UnMerge](#UnMerge)|通过一个参考值取消合并的两个数字
|[MergeToInt64](#MergeToInt64)|将两个数字合并为一个 int64 数字
|[UnMergeInt64](#UnMergeInt64)|将一个 int64 数字拆分为两个数字
|[ToContinuous](#ToContinuous)|将一组非连续的数字转换为从1开始的连续数字
|[CountDigits](#CountDigits)|接收一个整数 num 作为输入,并返回该数字的位数
|[GetDigitValue](#GetDigitValue)|接收一个整数 num 和一个表示目标位数的整数 digit 作为输入,并返
|[JoinNumbers](#JoinNumbers)|将一组数字连接起来
|[IsOdd](#IsOdd)|返回 n 是否为奇数
|[IsEven](#IsEven)|返回 n 是否为偶数
|[MakeLastDigitsZero](#MakeLastDigitsZero)|返回一个新的数,其中 num 的最后 digits 位数被设为零。
> 结构体定义
|结构体|描述
|:--|:--
|[CompareExpression](#compareexpression)|比较表达式
</details>
#### func Compare(a V, expression CompareExpression, b V) bool
<span id="Compare"></span>
> 根据特定表达式比较两个值
***
#### func IsContinuity(values S) bool
<span id="IsContinuity"></span>
> 检查一组值是否连续
***
#### func IsContinuityWithSort(values S) bool
<span id="IsContinuityWithSort"></span>
> 检查一组值排序后是否连续
***
#### func GetDefaultTolerance() float64
<span id="GetDefaultTolerance"></span>
> 获取默认误差范围
***
#### func Pow(a int, n int) int
<span id="Pow"></span>
> 整数幂运算
***
#### func PowInt64(a int64, n int64) int64
<span id="PowInt64"></span>
> 整数幂运算
***
#### func Min(a V, b V) V
<span id="Min"></span>
> 返回两个数之中较小的值
***
#### func Max(a V, b V) V
<span id="Max"></span>
> 返回两个数之中较大的值
***
#### func MinMax(a V, b V) (min V, max V)
<span id="MinMax"></span>
> 将两个数按照较小的和较大的顺序进行返回
***
#### func MaxMin(a V, b V) (max V, min V)
<span id="MaxMin"></span>
> 将两个数按照较大的和较小的顺序进行返回
***
#### func Clamp(value V, min V, max V) V
<span id="Clamp"></span>
> 将给定值限制在最小值和最大值之间
***
#### func Tolerance(value1 V, value2 V, tolerance V) bool
<span id="Tolerance"></span>
> 检查两个值是否在一个误差范围内
***
#### func Merge(refer V, a V, b V) V
<span id="Merge"></span>
> 通过一个参考值合并两个数字
***
#### func UnMerge(refer V, num V) (a V, b V)
<span id="UnMerge"></span>
> 通过一个参考值取消合并的两个数字
***
#### func MergeToInt64(v1 V, v2 V) int64
<span id="MergeToInt64"></span>
> 将两个数字合并为一个 int64 数字
***
#### func UnMergeInt64(n int64) V, V
<span id="UnMergeInt64"></span>
> 将一个 int64 数字拆分为两个数字
***
#### func ToContinuous(nums S) map[V]V
<span id="ToContinuous"></span>
> 将一组非连续的数字转换为从1开始的连续数字
> - 返回值是一个 mapkey 是从 1 开始的连续数字value 是原始数字
***
#### func CountDigits(num V) int
<span id="CountDigits"></span>
> 接收一个整数 num 作为输入,并返回该数字的位数
***
#### func GetDigitValue(num int64, digit int) int64
<span id="GetDigitValue"></span>
> 接收一个整数 num 和一个表示目标位数的整数 digit 作为输入,并返
> 回数字 num 在指定位数上的数值。我们使用 math.Abs() 函数获取 num 的绝对值,并通
> 过除以10的操作将 num 移动到目标位数上。然后,通过取余运算得到位数上的数值
***
#### func JoinNumbers(num1 V, n ...V) V
<span id="JoinNumbers"></span>
> 将一组数字连接起来
***
#### func IsOdd(n V) bool
<span id="IsOdd"></span>
> 返回 n 是否为奇数
***
#### func IsEven(n V) bool
<span id="IsEven"></span>
> 返回 n 是否为偶数
***
#### func MakeLastDigitsZero(num T, digits int) T
<span id="MakeLastDigitsZero"></span>
> 返回一个新的数,其中 num 的最后 digits 位数被设为零。
> - 函数首先创建一个 10 的 digits 次方的遮罩,然后通过整除和乘以这个遮罩来使 num 的最后 digits 位归零。
> - 当 T 类型为浮点型时,将被向下取整后再进行转换
***
### CompareExpression
比较表达式
```go
type CompareExpression struct{}
```

83
utils/memory/README.md Normal file
View File

@ -0,0 +1,83 @@
# Memory
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/memory)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Run](#Run)|运行持久化缓存程序
|[BindPersistCacheProgram](#BindPersistCacheProgram)|绑定持久化缓存程序
|[BindAction](#BindAction)|绑定需要缓存的操作函数
|[NewOption](#NewOption)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[Option](#option)|暂无描述...
</details>
#### func Run()
<span id="Run"></span>
> 运行持久化缓存程序
***
#### func BindPersistCacheProgram(name string, handler OutputParamHandlerFunc, option ...*Option) func ()
<span id="BindPersistCacheProgram"></span>
> 绑定持久化缓存程序
> - name 持久化缓存程序名称
> - handler 持久化缓存程序处理函数
> - option 持久化缓存程序选项
>
> 注意事项:
> - 持久化程序建议声明为全局变量进行使用
> - 持久化程序处理函数参数类型必须与绑定的缓存程序输出参数类型一致,并且相同 name 的持久化程序必须在 BindAction 之后进行绑定
> - 默认情况下只有执行该函数返回的函数才会进行持久化,如果需要持久化策略,可以设置 option 参数或者自行实现策略调用返回的函数
> - 所有持久化程序绑定完成后,应该主动调用 Run 函数运行
***
#### func BindAction(name string, handler Func) Func
<span id="BindAction"></span>
> 绑定需要缓存的操作函数
> - name 缓存操作名称
> - handler 缓存操作处理函数
>
> 注意事项:
> - 关于持久化缓存程序的绑定请参考 BindPersistCacheProgram
> - handler 函数的返回值将被作为缓存目标,如果返回值为非指针类型,将可能会发生意外的情况
> - 当传入的 handler 没有任何返回值时,将不会被缓存,并且不会占用缓存操作名称
>
> 使用场景:
> - 例如在游戏中,需要根据玩家 ID 查询玩家信息,可以使用该函数进行绑定,当查询玩家信息时,如果缓存中存在该玩家信息,将直接返回缓存中的数据,否则将执行 handler 函数进行查询并缓存
***
#### func NewOption() *Option
<span id="NewOption"></span>
***
### Option
```go
type Option struct {
ticker *timer.Ticker
firstDelay time.Duration
interval time.Duration
delay time.Duration
}
```
#### func (*Option) WithPeriodicity(ticker *timer.Ticker, firstDelay time.Duration, interval time.Duration, delay time.Duration) *Option
> 设置持久化周期
> - ticker 定时器,通常建议使用服务器的定时器,这样可以降低多线程的程序复杂性
> - firstDelay 首次持久化延迟,当首次持久化为 0 时,将会在下一个持久化周期开始时持久化
> - interval 持久化间隔
> - delay 每条数据持久化间隔适当的设置该值可以使持久化期间尽量降低对用户体验的影响如果为0将会一次性持久化所有数据
***

90
utils/moving/README.md Normal file
View File

@ -0,0 +1,90 @@
# Moving
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/moving)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewTwoDimensional](#NewTwoDimensional)|创建一个用于2D对象移动的实例(TwoDimensional)
|[WithTwoDimensionalTimeUnit](#WithTwoDimensionalTimeUnit)|通过特定时间单位创建
|[WithTwoDimensionalIdleWaitTime](#WithTwoDimensionalIdleWaitTime)|通过特定的空闲等待时间创建
|[WithTwoDimensionalInterval](#WithTwoDimensionalInterval)|通过特定的移动间隔时间创建
|[NewEntity](#NewEntity)|暂无描述...
> 结构体定义
|结构体|描述
|:--|:--
|[TwoDimensional](#twodimensional)|用于2D对象移动的数据结构
|[TwoDimensionalEntity](#twodimensionalentity)|2D移动对象接口定义
|[Position2DChangeEventHandle](#position2dchangeeventhandle)|暂无描述...
|[TwoDimensionalOption](#twodimensionaloption)|暂无描述...
</details>
#### func NewTwoDimensional(options ...TwoDimensionalOption[EID, PosType]) *TwoDimensional[EID, PosType]
<span id="NewTwoDimensional"></span>
> 创建一个用于2D对象移动的实例(TwoDimensional)
***
#### func WithTwoDimensionalTimeUnit(duration time.Duration) TwoDimensionalOption[EID, PosType]
<span id="WithTwoDimensionalTimeUnit"></span>
> 通过特定时间单位创建
> - 默认单位为1毫秒最小单位也为1毫秒
***
#### func WithTwoDimensionalIdleWaitTime(duration time.Duration) TwoDimensionalOption[EID, PosType]
<span id="WithTwoDimensionalIdleWaitTime"></span>
> 通过特定的空闲等待时间创建
> - 默认情况下在没有新的移动计划时将限制 100毫秒 + 移动间隔事件(默认100毫秒)
***
#### func WithTwoDimensionalInterval(duration time.Duration) TwoDimensionalOption[EID, PosType]
<span id="WithTwoDimensionalInterval"></span>
> 通过特定的移动间隔时间创建
***
#### func NewEntity(guid int64, speed float64) *MoveEntity
<span id="NewEntity"></span>
***
### TwoDimensional
用于2D对象移动的数据结构
- 通过对象调用 MoveTo 方法后将开始执行该对象的移动
- 移动将在根据设置的每次移动间隔时间(WithTwoDimensionalInterval)进行移动,当无对象移动需要移动时将会进入短暂的休眠
- 当对象移动速度永久为0时将会导致永久无法完成的移动
```go
type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber] struct {
rw sync.RWMutex
entities map[EID]*moving2DTarget[EID, PosType]
timeUnit float64
idle time.Duration
interval time.Duration
close bool
position2DChangeEventHandles []Position2DChangeEventHandle[EID, PosType]
position2DDestinationEventHandles []Position2DDestinationEventHandle[EID, PosType]
position2DStopMoveEventHandles []Position2DStopMoveEventHandle[EID, PosType]
}
```
### TwoDimensionalEntity
2D移动对象接口定义
```go
type TwoDimensionalEntity[EID generic.Basic, PosType generic.SignedNumber] struct{}
```
### Position2DChangeEventHandle
```go
type Position2DChangeEventHandle[EID generic.Basic, PosType generic.SignedNumber] struct{}
```
### TwoDimensionalOption
```go
type TwoDimensionalOption[EID generic.Basic, PosType generic.SignedNumber] struct{}
```

32
utils/network/README.md Normal file
View File

@ -0,0 +1,32 @@
# Network
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/network)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[IP](#IP)|返回本机出站地址
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func IP() (ip net.IP, err error)
<span id="IP"></span>
> 返回本机出站地址
***

69
utils/offset/README.md Normal file
View File

@ -0,0 +1,69 @@
# Offset
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/offset)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewTime](#NewTime)|新建一个包含偏移的时间
|[SetGlobal](#SetGlobal)|设置全局偏移时间
|[GetGlobal](#GetGlobal)|获取全局偏移时间
|[Now](#Now)|获取当前时间偏移后的时间
|[Since](#Since)|获取当前时间偏移后的时间自从 t 以来经过的时间
> 结构体定义
|结构体|描述
|:--|:--
|[Time](#time)|带有偏移量的时间
</details>
#### func NewTime(offset time.Duration) *Time
<span id="NewTime"></span>
> 新建一个包含偏移的时间
***
#### func SetGlobal(offset time.Duration)
<span id="SetGlobal"></span>
> 设置全局偏移时间
***
#### func GetGlobal() *Time
<span id="GetGlobal"></span>
> 获取全局偏移时间
***
#### func Now() time.Time
<span id="Now"></span>
> 获取当前时间偏移后的时间
***
#### func Since(t time.Time) time.Duration
<span id="Since"></span>
> 获取当前时间偏移后的时间自从 t 以来经过的时间
***
### Time
带有偏移量的时间
```go
type Time struct {
offset time.Duration
}
```
#### func (*Time) SetOffset(offset time.Duration)
> 设置时间偏移
***
#### func (*Time) Now() time.Time
> 获取当前时间偏移后的时间
***
#### func (*Time) Since(t time.Time) time.Duration
> 获取当前时间偏移后的时间自从 t 以来经过的时间
***

173
utils/random/README.md Normal file
View File

@ -0,0 +1,173 @@
# Random
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/random)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Dice](#Dice)|掷骰子
|[DiceN](#DiceN)|掷骰子
|[NetIP](#NetIP)|返回一个随机的IP地址
|[Port](#Port)|返回一个随机的端口号
|[IPv4](#IPv4)|返回一个随机产生的IPv4地址。
|[IPv4Port](#IPv4Port)|返回一个随机产生的IPv4地址和端口。
|[Int64](#Int64)|返回一个介于min和max之间的int64类型的随机数。
|[Int](#Int)|返回一个介于min和max之间的的int类型的随机数。
|[Duration](#Duration)|返回一个介于min和max之间的的Duration类型的随机数。
|[Float64](#Float64)|返回一个0~1的浮点数
|[Float32](#Float32)|返回一个0~1的浮点数
|[IntN](#IntN)|返回一个0~n的整数
|[Bool](#Bool)|返回一个随机的布尔值
|[ProbabilitySlice](#ProbabilitySlice)|按概率随机从切片中产生一个数据并返回命中的对象及是否未命中
|[ProbabilitySliceIndex](#ProbabilitySliceIndex)|按概率随机从切片中产生一个数据并返回命中的对象及对象索引以及是否未命中
|[Probability](#Probability)|输入一个概率,返回是否命中
|[ProbabilityChooseOne](#ProbabilityChooseOne)|输入一组概率,返回命中的索引
|[RefreshSeed](#RefreshSeed)|暂无描述...
|[ChineseName](#ChineseName)|返回一个随机组成的中文姓名。
|[EnglishName](#EnglishName)|返回一个随机组成的英文姓名。
|[Name](#Name)|返回一个随机组成的中文或英文姓名
|[NumberString](#NumberString)|返回一个介于min和max之间的string类型的随机数。
|[NumberStringRepair](#NumberStringRepair)|返回一个介于min和max之间的string类型的随机数
|[HostName](#HostName)|返回一个随机产生的hostname。
|[WeightSlice](#WeightSlice)|按权重随机从切片中产生一个数据并返回
|[WeightSliceIndex](#WeightSliceIndex)|按权重随机从切片中产生一个数据并返回数据和对应索引
|[WeightMap](#WeightMap)|按权重随机从map中产生一个数据并返回
|[WeightMapKey](#WeightMapKey)|按权重随机从map中产生一个数据并返回数据和对应 key
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func Dice() int
<span id="Dice"></span>
> 掷骰子
> - 常规掷骰子将返回 1-6 的随机数
***
#### func DiceN(n int) int
<span id="DiceN"></span>
> 掷骰子
> - 与 Dice 不同的是,将返回 1-N 的随机数
***
#### func NetIP() net.IP
<span id="NetIP"></span>
> 返回一个随机的IP地址
***
#### func Port() int
<span id="Port"></span>
> 返回一个随机的端口号
***
#### func IPv4() string
<span id="IPv4"></span>
> 返回一个随机产生的IPv4地址。
***
#### func IPv4Port() string
<span id="IPv4Port"></span>
> 返回一个随机产生的IPv4地址和端口。
***
#### func Int64(min int64, max int64) int64
<span id="Int64"></span>
> 返回一个介于min和max之间的int64类型的随机数。
***
#### func Int(min int, max int) int
<span id="Int"></span>
> 返回一个介于min和max之间的的int类型的随机数。
***
#### func Duration(min int64, max int64) time.Duration
<span id="Duration"></span>
> 返回一个介于min和max之间的的Duration类型的随机数。
***
#### func Float64() float64
<span id="Float64"></span>
> 返回一个0~1的浮点数
***
#### func Float32() float32
<span id="Float32"></span>
> 返回一个0~1的浮点数
***
#### func IntN(n int) int
<span id="IntN"></span>
> 返回一个0~n的整数
***
#### func Bool() bool
<span id="Bool"></span>
> 返回一个随机的布尔值
***
#### func ProbabilitySlice(getProbabilityHandle func (data T) float64, data ...T) (hit T, miss bool)
<span id="ProbabilitySlice"></span>
> 按概率随机从切片中产生一个数据并返回命中的对象及是否未命中
> - 当总概率小于 1 将会发生未命中的情况
***
#### func ProbabilitySliceIndex(getProbabilityHandle func (data T) float64, data ...T) (hit T, index int, miss bool)
<span id="ProbabilitySliceIndex"></span>
> 按概率随机从切片中产生一个数据并返回命中的对象及对象索引以及是否未命中
> - 当总概率小于 1 将会发生未命中的情况
***
#### func Probability(p int, full ...int) bool
<span id="Probability"></span>
> 输入一个概率,返回是否命中
> - 当 full 不为空时,将以 full 为基数p 为分子,计算命中概率
***
#### func ProbabilityChooseOne(ps ...int) int
<span id="ProbabilityChooseOne"></span>
> 输入一组概率,返回命中的索引
***
#### func RefreshSeed(seed ...int64)
<span id="RefreshSeed"></span>
***
#### func ChineseName() string
<span id="ChineseName"></span>
> 返回一个随机组成的中文姓名。
***
#### func EnglishName() string
<span id="EnglishName"></span>
> 返回一个随机组成的英文姓名。
***
#### func Name() string
<span id="Name"></span>
> 返回一个随机组成的中文或英文姓名
> - 以1/2的概率决定生产的是中文还是英文姓名。
***
#### func NumberString(min int, max int) string
<span id="NumberString"></span>
> 返回一个介于min和max之间的string类型的随机数。
***
#### func NumberStringRepair(min int, max int) string
<span id="NumberStringRepair"></span>
> 返回一个介于min和max之间的string类型的随机数
> - 通过Int64生成一个随机数当结果的字符串长度小于max的字符串长度的情况下使用0在开头补齐。
***
#### func HostName() string
<span id="HostName"></span>
> 返回一个随机产生的hostname。
***
#### func WeightSlice(getWeightHandle func (data T) int64, data ...T) T
<span id="WeightSlice"></span>
> 按权重随机从切片中产生一个数据并返回
***
#### func WeightSliceIndex(getWeightHandle func (data T) int64, data ...T) (item T, index int)
<span id="WeightSliceIndex"></span>
> 按权重随机从切片中产生一个数据并返回数据和对应索引
***
#### func WeightMap(getWeightHandle func (data T) int64, data map[K]T) T
<span id="WeightMap"></span>
> 按权重随机从map中产生一个数据并返回
***
#### func WeightMapKey(getWeightHandle func (data T) int64, data map[K]T) (item T, key K)
<span id="WeightMapKey"></span>
> 按权重随机从map中产生一个数据并返回数据和对应 key
***

67
utils/reflects/README.md Normal file
View File

@ -0,0 +1,67 @@
# Reflects
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/reflects)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[WrapperFunc](#WrapperFunc)|包装函数
|[WrapperFuncBefore2After](#WrapperFuncBefore2After)|包装函数,前置函数执行前,后置函数执行后
|[WrapperFuncBefore](#WrapperFuncBefore)|包装函数,前置函数执行前
|[WrapperFuncAfter](#WrapperFuncAfter)|包装函数,后置函数执行后
|[GetPtrUnExportFiled](#GetPtrUnExportFiled)|获取指针类型的未导出字段
|[SetPtrUnExportFiled](#SetPtrUnExportFiled)|设置指针类型的未导出字段
|[Copy](#Copy)|拷贝
|[GetPointer](#GetPointer)|获取指针
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func WrapperFunc(f any, wrapper func (call func ( []reflect.Value) []reflect.Value) func (args []reflect.Value) []reflect.Value) (wf Func, err error)
<span id="WrapperFunc"></span>
> 包装函数
***
#### func WrapperFuncBefore2After(f Func, before func (), after func ()) (wf Func, err error)
<span id="WrapperFuncBefore2After"></span>
> 包装函数,前置函数执行前,后置函数执行后
***
#### func WrapperFuncBefore(f Func, before func ()) (wf Func, err error)
<span id="WrapperFuncBefore"></span>
> 包装函数,前置函数执行前
***
#### func WrapperFuncAfter(f Func, after func ()) (wf Func, err error)
<span id="WrapperFuncAfter"></span>
> 包装函数,后置函数执行后
***
#### func GetPtrUnExportFiled(s reflect.Value, filedIndex int) reflect.Value
<span id="GetPtrUnExportFiled"></span>
> 获取指针类型的未导出字段
***
#### func SetPtrUnExportFiled(s reflect.Value, filedIndex int, val reflect.Value)
<span id="SetPtrUnExportFiled"></span>
> 设置指针类型的未导出字段
***
#### func Copy(s reflect.Value) reflect.Value
<span id="Copy"></span>
> 拷贝
***
#### func GetPointer(src T) reflect.Value
<span id="GetPointer"></span>
> 获取指针
***

52
utils/runtimes/README.md Normal file
View File

@ -0,0 +1,52 @@
# Runtimes
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/runtimes)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[GetWorkingDir](#GetWorkingDir)|获取工作目录绝对路径
|[GetTempDir](#GetTempDir)|获取系统临时目录
|[GetExecutablePathByBuild](#GetExecutablePathByBuild)|获取当前执行文件绝对路径go build
|[GetExecutablePathByCaller](#GetExecutablePathByCaller)|获取当前执行文件绝对路径go run
|[CurrentRunningFuncName](#CurrentRunningFuncName)|获取正在运行的函数名
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func GetWorkingDir() string
<span id="GetWorkingDir"></span>
> 获取工作目录绝对路径
***
#### func GetTempDir() string
<span id="GetTempDir"></span>
> 获取系统临时目录
***
#### func GetExecutablePathByBuild() string
<span id="GetExecutablePathByBuild"></span>
> 获取当前执行文件绝对路径go build
***
#### func GetExecutablePathByCaller() string
<span id="GetExecutablePathByCaller"></span>
> 获取当前执行文件绝对路径go run
***
#### func CurrentRunningFuncName(skip ...int) string
<span id="CurrentRunningFuncName"></span>
> 获取正在运行的函数名
***

121
utils/sole/README.md Normal file
View File

@ -0,0 +1,121 @@
# Sole
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/sole)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[RegNameSpace](#RegNameSpace)|注册特定命名空间的唯一标识符
|[UnRegNameSpace](#UnRegNameSpace)|解除注销特定命名空间的唯一标识符
|[Get](#Get)|获取全局唯一标识符
|[Reset](#Reset)|重置全局唯一标识符
|[GetWith](#GetWith)|获取特定命名空间的唯一标识符
|[ResetWith](#ResetWith)|重置特定命名空间的唯一标识符
|[NewOnce](#NewOnce)|创建一个用于数据取值去重的结构实例
|[SonyflakeIDE](#SonyflakeIDE)|获取一个雪花id
|[SonyflakeID](#SonyflakeID)|获取一个雪花id
|[SonyflakeSetting](#SonyflakeSetting)|配置雪花id生成策略
|[AutoIncrementUint32](#AutoIncrementUint32)|获取一个自增的 uint32 值
|[AutoIncrementUint64](#AutoIncrementUint64)|获取一个自增的 uint64 值
|[AutoIncrementInt32](#AutoIncrementInt32)|获取一个自增的 int32 值
|[AutoIncrementInt64](#AutoIncrementInt64)|获取一个自增的 int64 值
|[AutoIncrementInt](#AutoIncrementInt)|获取一个自增的 int 值
|[AutoIncrementString](#AutoIncrementString)|获取一个自增的字符串
> 结构体定义
|结构体|描述
|:--|:--
|[Once](#once)|用于数据取值去重的结构体
</details>
#### func RegNameSpace(name any)
<span id="RegNameSpace"></span>
> 注册特定命名空间的唯一标识符
***
#### func UnRegNameSpace(name any)
<span id="UnRegNameSpace"></span>
> 解除注销特定命名空间的唯一标识符
***
#### func Get() int64
<span id="Get"></span>
> 获取全局唯一标识符
***
#### func Reset()
<span id="Reset"></span>
> 重置全局唯一标识符
***
#### func GetWith(name any) int64
<span id="GetWith"></span>
> 获取特定命名空间的唯一标识符
***
#### func ResetWith(name any)
<span id="ResetWith"></span>
> 重置特定命名空间的唯一标识符
***
#### func NewOnce() *Once[V]
<span id="NewOnce"></span>
> 创建一个用于数据取值去重的结构实例
***
#### func SonyflakeIDE() int64, error
<span id="SonyflakeIDE"></span>
> 获取一个雪花id
***
#### func SonyflakeID() int64
<span id="SonyflakeID"></span>
> 获取一个雪花id
***
#### func SonyflakeSetting(settings sonyflake.Settings)
<span id="SonyflakeSetting"></span>
> 配置雪花id生成策略
***
#### func AutoIncrementUint32() uint32
<span id="AutoIncrementUint32"></span>
> 获取一个自增的 uint32 值
***
#### func AutoIncrementUint64() uint64
<span id="AutoIncrementUint64"></span>
> 获取一个自增的 uint64 值
***
#### func AutoIncrementInt32() int32
<span id="AutoIncrementInt32"></span>
> 获取一个自增的 int32 值
***
#### func AutoIncrementInt64() int64
<span id="AutoIncrementInt64"></span>
> 获取一个自增的 int64 值
***
#### func AutoIncrementInt() int
<span id="AutoIncrementInt"></span>
> 获取一个自增的 int 值
***
#### func AutoIncrementString() string
<span id="AutoIncrementString"></span>
> 获取一个自增的字符串
***
### Once
用于数据取值去重的结构体
```go
type Once[V any] struct {
r map[any]struct{}
}
```
#### func (*Once) Get(key any, value V, defaultValue V) V
> 获取一个值,当该值已经被获取过的时候,返回 defaultValue否则返回 value
***
#### func (*Once) Reset(key ...any)
> 当 key 数量大于 0 时,将会重置对应 key 的记录,否则重置所有记录
***

37
utils/sorts/README.md Normal file
View File

@ -0,0 +1,37 @@
# Sorts
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/sorts)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[Topological](#Topological)|拓扑排序是一种对有向图进行排序的算法,它可以用来解决一些依赖关系的问题,比如计算字段的依赖关系。拓扑排序会将存在依赖关系的元素进行排序,使得依赖关系的元素总是排在被依赖的元素之前。
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func Topological(slice S, queryIndexHandler func (item V) Index, queryDependsHandler func (item V) []Index) S, error
<span id="Topological"></span>
> 拓扑排序是一种对有向图进行排序的算法,它可以用来解决一些依赖关系的问题,比如计算字段的依赖关系。拓扑排序会将存在依赖关系的元素进行排序,使得依赖关系的元素总是排在被依赖的元素之前。
> - slice: 需要排序的切片
> - queryIndexHandler: 用于查询切片中每个元素的索引
> - queryDependsHandler: 用于查询切片中每个元素的依赖关系,返回的是一个索引切片,如果没有依赖关系,那么返回空切片
>
> 该函数在存在循环依赖的情况下将会返回 ErrCircularDependencyDetected 错误
***

155
utils/str/README.md Normal file
View File

@ -0,0 +1,155 @@
# Str
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/str)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[RangeLine](#RangeLine)|对传入的eachString进行按行切片后再进行遍历
|[SplitTrimSpace](#SplitTrimSpace)|按照空格分割字符串并去除空格
|[FirstUpper](#FirstUpper)|首字母大写
|[FirstLower](#FirstLower)|首字母小写
|[FirstUpperBytes](#FirstUpperBytes)|首字母大写
|[FirstLowerBytes](#FirstLowerBytes)|首字母小写
|[IsEmpty](#IsEmpty)|判断字符串是否为空
|[IsEmptyBytes](#IsEmptyBytes)|判断字符串是否为空
|[IsNotEmpty](#IsNotEmpty)|判断字符串是否不为空
|[IsNotEmptyBytes](#IsNotEmptyBytes)|判断字符串是否不为空
|[SnakeString](#SnakeString)|蛇形字符串
|[SnakeStringBytes](#SnakeStringBytes)|蛇形字符串
|[CamelString](#CamelString)|驼峰字符串
|[CamelStringBytes](#CamelStringBytes)|驼峰字符串
|[SortJoin](#SortJoin)|将多个字符串排序后拼接
|[HideSensitivity](#HideSensitivity)|返回防敏感化后的字符串
|[ThousandsSeparator](#ThousandsSeparator)|返回将str进行千位分隔符处理后的字符串。
|[KV](#KV)|返回str经过转换后形成的key、value
|[FormatSpeedyInt](#FormatSpeedyInt)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|[FormatSpeedyInt64](#FormatSpeedyInt64)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|[FormatSpeedyFloat32](#FormatSpeedyFloat32)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|[FormatSpeedyFloat64](#FormatSpeedyFloat64)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func RangeLine(eachString string, eachFunc func (index int, line string) error) error
<span id="RangeLine"></span>
> 对传入的eachString进行按行切片后再进行遍历
> - 该函数会预先对“\r\n”进行处理替换为“\n”。
> - 在遍历到每一行的时候会将结果index和line作为入参传入eachFunc中进行调用。
> - index表示了当前行的行号由0开始line表示了当前行的内容。
***
#### func SplitTrimSpace(str string, sep string) []string
<span id="SplitTrimSpace"></span>
> 按照空格分割字符串并去除空格
***
#### func FirstUpper(str string) string
<span id="FirstUpper"></span>
> 首字母大写
***
#### func FirstLower(str string) string
<span id="FirstLower"></span>
> 首字母小写
***
#### func FirstUpperBytes(str []byte) []byte
<span id="FirstUpperBytes"></span>
> 首字母大写
***
#### func FirstLowerBytes(str []byte) []byte
<span id="FirstLowerBytes"></span>
> 首字母小写
***
#### func IsEmpty(str string) bool
<span id="IsEmpty"></span>
> 判断字符串是否为空
***
#### func IsEmptyBytes(str []byte) bool
<span id="IsEmptyBytes"></span>
> 判断字符串是否为空
***
#### func IsNotEmpty(str string) bool
<span id="IsNotEmpty"></span>
> 判断字符串是否不为空
***
#### func IsNotEmptyBytes(str []byte) bool
<span id="IsNotEmptyBytes"></span>
> 判断字符串是否不为空
***
#### func SnakeString(str string) string
<span id="SnakeString"></span>
> 蛇形字符串
***
#### func SnakeStringBytes(str []byte) []byte
<span id="SnakeStringBytes"></span>
> 蛇形字符串
***
#### func CamelString(str string) string
<span id="CamelString"></span>
> 驼峰字符串
***
#### func CamelStringBytes(str []byte) []byte
<span id="CamelStringBytes"></span>
> 驼峰字符串
***
#### func SortJoin(delimiter string, s ...string) string
<span id="SortJoin"></span>
> 将多个字符串排序后拼接
***
#### func HideSensitivity(str string) (result string)
<span id="HideSensitivity"></span>
> 返回防敏感化后的字符串
> - 隐藏身份证、邮箱、手机号等敏感信息用*号替代
***
#### func ThousandsSeparator(str string) string
<span id="ThousandsSeparator"></span>
> 返回将str进行千位分隔符处理后的字符串。
***
#### func KV(str string, tag ...string) string, string
<span id="KV"></span>
> 返回str经过转换后形成的key、value
> - 这里tag表示使用什么字符串来区分key和value的分隔符。
> - 默认情况即不传入tag的情况下分隔符为“=”。
***
#### func FormatSpeedyInt(numberStr string) int, error
<span id="FormatSpeedyInt"></span>
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
> - 当字符串为“123,456,789”的时候返回结果为“123456789”。
> - 当字符串为“123 456 789”的时候返回结果为“123456789”。
> - 当字符串为“1 23, 45 6, 789”的时候返回结果为“123456789”。
***
#### func FormatSpeedyInt64(numberStr string) int64, error
<span id="FormatSpeedyInt64"></span>
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
> - 当字符串为“123,456,789”的时候返回结果为“123456789”。
> - 当字符串为“123 456 789”的时候返回结果为“123456789”。
> - 当字符串为“1 23, 45 6, 789”的时候返回结果为“123456789”。
***
#### func FormatSpeedyFloat32(numberStr string) float64, error
<span id="FormatSpeedyFloat32"></span>
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
> - 当字符串为“123,456,789.123”的时候返回结果为“123456789.123”。
> - 当字符串为“123 456 789.123”的时候返回结果为“123456789.123”。
> - 当字符串为“1 23, 45 6, 789.123”的时候返回结果为“123456789.123”。
***
#### func FormatSpeedyFloat64(numberStr string) float64, error
<span id="FormatSpeedyFloat64"></span>
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
> - 当字符串为“123,456,789.123”的时候返回结果为“123456789.123”。
> - 当字符串为“123 456 789.123”的时候返回结果为“123456789.123”。
> - 当字符串为“1 23, 45 6, 789.123”的时候返回结果为“123456789.123”。
***

588
utils/super/README.md Normal file
View File

@ -0,0 +1,588 @@
# Super
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/super)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[NewBitSet](#NewBitSet)|通过指定的 Bit 位创建一个 BitSet
|[TryWriteChannel](#TryWriteChannel)|尝试写入 channel如果 channel 无法写入则忽略,返回是否写入成功
|[TryWriteChannelByHandler](#TryWriteChannelByHandler)|尝试写入 channel如果 channel 无法写入则执行 handler
|[RegError](#RegError)|通过错误码注册错误,返回错误的引用
|[RegErrorRef](#RegErrorRef)|通过错误码注册错误,返回错误的引用
|[GetError](#GetError)|通过错误引用获取错误码和真实错误信息,如果错误不存在则返回 0如果错误引用不存在则返回原本的错误
|[RecoverTransform](#RecoverTransform)|recover 错误转换
|[Handle](#Handle)|执行 f 函数,如果 f 为 nil则不执行
|[HandleErr](#HandleErr)|执行 f 函数,如果 f 为 nil则不执行
|[HandleV](#HandleV)|执行 f 函数,如果 f 为 nil则不执行
|[GoFormat](#GoFormat)|go 代码格式化
|[If](#If)|暂无描述...
|[MarshalJSON](#MarshalJSON)|将对象转换为 json
|[MarshalJSONE](#MarshalJSONE)|将对象转换为 json
|[UnmarshalJSON](#UnmarshalJSON)|将 json 转换为对象
|[MarshalIndentJSON](#MarshalIndentJSON)|将对象转换为 json
|[MarshalToTargetWithJSON](#MarshalToTargetWithJSON)|将对象转换为目标对象
|[StartLossCounter](#StartLossCounter)|开始损耗计数
|[Match](#Match)|匹配
|[IsNumber](#IsNumber)|判断是否为数字
|[NumberToRome](#NumberToRome)|将数字转换为罗马数字
|[StringToInt](#StringToInt)|字符串转换为整数
|[StringToFloat64](#StringToFloat64)|字符串转换为 float64
|[StringToBool](#StringToBool)|字符串转换为 bool
|[StringToUint64](#StringToUint64)|字符串转换为 uint64
|[StringToUint](#StringToUint)|字符串转换为 uint
|[StringToFloat32](#StringToFloat32)|字符串转换为 float32
|[StringToInt64](#StringToInt64)|字符串转换为 int64
|[StringToUint32](#StringToUint32)|字符串转换为 uint32
|[StringToInt32](#StringToInt32)|字符串转换为 int32
|[StringToUint16](#StringToUint16)|字符串转换为 uint16
|[StringToInt16](#StringToInt16)|字符串转换为 int16
|[StringToUint8](#StringToUint8)|字符串转换为 uint8
|[StringToInt8](#StringToInt8)|字符串转换为 int8
|[StringToByte](#StringToByte)|字符串转换为 byte
|[StringToRune](#StringToRune)|字符串转换为 rune
|[IntToString](#IntToString)|整数转换为字符串
|[Float64ToString](#Float64ToString)|float64 转换为字符串
|[BoolToString](#BoolToString)|bool 转换为字符串
|[Uint64ToString](#Uint64ToString)|uint64 转换为字符串
|[UintToString](#UintToString)|uint 转换为字符串
|[Float32ToString](#Float32ToString)|float32 转换为字符串
|[Int64ToString](#Int64ToString)|int64 转换为字符串
|[Uint32ToString](#Uint32ToString)|uint32 转换为字符串
|[Int32ToString](#Int32ToString)|int32 转换为字符串
|[Uint16ToString](#Uint16ToString)|uint16 转换为字符串
|[Int16ToString](#Int16ToString)|int16 转换为字符串
|[Uint8ToString](#Uint8ToString)|uint8 转换为字符串
|[Int8ToString](#Int8ToString)|int8 转换为字符串
|[ByteToString](#ByteToString)|byte 转换为字符串
|[RuneToString](#RuneToString)|rune 转换为字符串
|[StringToSlice](#StringToSlice)|字符串转换为切片
|[SliceToString](#SliceToString)|切片转换为字符串
|[NewPermission](#NewPermission)|创建权限
|[Retry](#Retry)|根据提供的 count 次数尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功或者达到 count 次数
|[RetryByRule](#RetryByRule)|根据提供的规则尝试执行 f 函数,如果 f 函数返回错误,则根据 rule 的返回值进行重试
|[RetryByExponentialBackoff](#RetryByExponentialBackoff)|根据指数退避算法尝试执行 f 函数
|[ConditionalRetryByExponentialBackoff](#ConditionalRetryByExponentialBackoff)|该函数与 RetryByExponentialBackoff 类似,但是可以被中断
|[RetryAsync](#RetryAsync)|与 Retry 类似,但是是异步执行
|[RetryForever](#RetryForever)|根据提供的 interval 时间间隔尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功
|[NewStackGo](#NewStackGo)|返回一个用于获取上一个协程调用的堆栈信息的收集器
|[LaunchTime](#LaunchTime)|获取程序启动时间
|[Hostname](#Hostname)|获取主机名
|[PID](#PID)|获取进程 PID
|[StringToBytes](#StringToBytes)|以零拷贝的方式将字符串转换为字节切片
|[BytesToString](#BytesToString)|以零拷贝的方式将字节切片转换为字符串
|[Convert](#Convert)|以零拷贝的方式将一个对象转换为另一个对象
|[Verify](#Verify)|对特定表达式进行校验,当表达式不成立时,将执行 handle
|[OldVersion](#OldVersion)|检查 version2 对于 version1 来说是不是旧版本
|[CompareVersion](#CompareVersion)|返回一个整数,用于表示两个版本号的比较结果:
> 结构体定义
|结构体|描述
|:--|:--
|[BitSet](#bitset)|是一个可以动态增长的比特位集合
|[LossCounter](#losscounter)|暂无描述...
|[Matcher](#matcher)|匹配器
|[Permission](#permission)|暂无描述...
|[StackGo](#stackgo)|用于获取上一个协程调用的堆栈信息
|[VerifyHandle](#verifyhandle)|校验句柄
</details>
#### func NewBitSet(bits ...Bit) *BitSet[Bit]
<span id="NewBitSet"></span>
> 通过指定的 Bit 位创建一个 BitSet
***
#### func TryWriteChannel(ch chan T, data T) bool
<span id="TryWriteChannel"></span>
> 尝试写入 channel如果 channel 无法写入则忽略,返回是否写入成功
> - 无法写入的情况包括channel 已满、channel 已关闭
***
#### func TryWriteChannelByHandler(ch chan T, data T, handler func ())
<span id="TryWriteChannelByHandler"></span>
> 尝试写入 channel如果 channel 无法写入则执行 handler
> - 无法写入的情况包括channel 已满、channel 已关闭
***
#### func RegError(code int, message string) error
<span id="RegError"></span>
> 通过错误码注册错误,返回错误的引用
***
#### func RegErrorRef(code int, message string, ref error) error
<span id="RegErrorRef"></span>
> 通过错误码注册错误,返回错误的引用
> - 引用将会被重定向到注册的错误信息
***
#### func GetError(err error) int, error
<span id="GetError"></span>
> 通过错误引用获取错误码和真实错误信息,如果错误不存在则返回 0如果错误引用不存在则返回原本的错误
***
#### func RecoverTransform(a any) error
<span id="RecoverTransform"></span>
> recover 错误转换
***
#### func Handle(f func ())
<span id="Handle"></span>
> 执行 f 函数,如果 f 为 nil则不执行
***
#### func HandleErr(f func () error) error
<span id="HandleErr"></span>
> 执行 f 函数,如果 f 为 nil则不执行
***
#### func HandleV(v V, f func (v V))
<span id="HandleV"></span>
> 执行 f 函数,如果 f 为 nil则不执行
***
#### func GoFormat(filePath string)
<span id="GoFormat"></span>
> go 代码格式化
***
#### func If(expression bool, t T, f T) T
<span id="If"></span>
***
#### func MarshalJSON(v interface {}) []byte
<span id="MarshalJSON"></span>
> 将对象转换为 json
> - 当转换失败时,将返回 json 格式的空对象
***
#### func MarshalJSONE(v interface {}) []byte, error
<span id="MarshalJSONE"></span>
> 将对象转换为 json
> - 当转换失败时,将返回错误信息
***
#### func UnmarshalJSON(data []byte, v interface {}) error
<span id="UnmarshalJSON"></span>
> 将 json 转换为对象
***
#### func MarshalIndentJSON(v interface {}, prefix string, indent string) []byte
<span id="MarshalIndentJSON"></span>
> 将对象转换为 json
***
#### func MarshalToTargetWithJSON(src interface {}, dest interface {}) error
<span id="MarshalToTargetWithJSON"></span>
> 将对象转换为目标对象
***
#### func StartLossCounter() *LossCounter
<span id="StartLossCounter"></span>
> 开始损耗计数
***
#### func Match(value Value) *Matcher[Value, Result]
<span id="Match"></span>
> 匹配
***
#### func IsNumber(v any) bool
<span id="IsNumber"></span>
> 判断是否为数字
***
#### func NumberToRome(num int) string
<span id="NumberToRome"></span>
> 将数字转换为罗马数字
***
#### func StringToInt(value string) int
<span id="StringToInt"></span>
> 字符串转换为整数
***
#### func StringToFloat64(value string) float64
<span id="StringToFloat64"></span>
> 字符串转换为 float64
***
#### func StringToBool(value string) bool
<span id="StringToBool"></span>
> 字符串转换为 bool
***
#### func StringToUint64(value string) uint64
<span id="StringToUint64"></span>
> 字符串转换为 uint64
***
#### func StringToUint(value string) uint
<span id="StringToUint"></span>
> 字符串转换为 uint
***
#### func StringToFloat32(value string) float32
<span id="StringToFloat32"></span>
> 字符串转换为 float32
***
#### func StringToInt64(value string) int64
<span id="StringToInt64"></span>
> 字符串转换为 int64
***
#### func StringToUint32(value string) uint32
<span id="StringToUint32"></span>
> 字符串转换为 uint32
***
#### func StringToInt32(value string) int32
<span id="StringToInt32"></span>
> 字符串转换为 int32
***
#### func StringToUint16(value string) uint16
<span id="StringToUint16"></span>
> 字符串转换为 uint16
***
#### func StringToInt16(value string) int16
<span id="StringToInt16"></span>
> 字符串转换为 int16
***
#### func StringToUint8(value string) uint8
<span id="StringToUint8"></span>
> 字符串转换为 uint8
***
#### func StringToInt8(value string) int8
<span id="StringToInt8"></span>
> 字符串转换为 int8
***
#### func StringToByte(value string) byte
<span id="StringToByte"></span>
> 字符串转换为 byte
***
#### func StringToRune(value string) rune
<span id="StringToRune"></span>
> 字符串转换为 rune
***
#### func IntToString(value int) string
<span id="IntToString"></span>
> 整数转换为字符串
***
#### func Float64ToString(value float64) string
<span id="Float64ToString"></span>
> float64 转换为字符串
***
#### func BoolToString(value bool) string
<span id="BoolToString"></span>
> bool 转换为字符串
***
#### func Uint64ToString(value uint64) string
<span id="Uint64ToString"></span>
> uint64 转换为字符串
***
#### func UintToString(value uint) string
<span id="UintToString"></span>
> uint 转换为字符串
***
#### func Float32ToString(value float32) string
<span id="Float32ToString"></span>
> float32 转换为字符串
***
#### func Int64ToString(value int64) string
<span id="Int64ToString"></span>
> int64 转换为字符串
***
#### func Uint32ToString(value uint32) string
<span id="Uint32ToString"></span>
> uint32 转换为字符串
***
#### func Int32ToString(value int32) string
<span id="Int32ToString"></span>
> int32 转换为字符串
***
#### func Uint16ToString(value uint16) string
<span id="Uint16ToString"></span>
> uint16 转换为字符串
***
#### func Int16ToString(value int16) string
<span id="Int16ToString"></span>
> int16 转换为字符串
***
#### func Uint8ToString(value uint8) string
<span id="Uint8ToString"></span>
> uint8 转换为字符串
***
#### func Int8ToString(value int8) string
<span id="Int8ToString"></span>
> int8 转换为字符串
***
#### func ByteToString(value byte) string
<span id="ByteToString"></span>
> byte 转换为字符串
***
#### func RuneToString(value rune) string
<span id="RuneToString"></span>
> rune 转换为字符串
***
#### func StringToSlice(value string) []string
<span id="StringToSlice"></span>
> 字符串转换为切片
***
#### func SliceToString(value []string) string
<span id="SliceToString"></span>
> 切片转换为字符串
***
#### func NewPermission() *Permission[Code, EntityID]
<span id="NewPermission"></span>
> 创建权限
***
#### func Retry(count int, interval time.Duration, f func () error) error
<span id="Retry"></span>
> 根据提供的 count 次数尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功或者达到 count 次数
***
#### func RetryByRule(f func () error, rule func (count int) time.Duration) error
<span id="RetryByRule"></span>
> 根据提供的规则尝试执行 f 函数,如果 f 函数返回错误,则根据 rule 的返回值进行重试
> - rule 将包含一个入参,表示第几次重试,返回值表示下一次重试的时间间隔,当返回值为 0 时,表示不再重试
> - rule 的 count 将在 f 首次失败后变为 1因此 rule 的入参将从 1 开始
***
#### func RetryByExponentialBackoff(f func () error, maxRetries int, baseDelay time.Duration, maxDelay time.Duration, multiplier float64, randomization float64, ignoreErrors ...error) error
<span id="RetryByExponentialBackoff"></span>
> 根据指数退避算法尝试执行 f 函数
> - maxRetries最大重试次数
> - baseDelay基础延迟
> - maxDelay最大延迟
> - multiplier延迟时间的乘数通常为 2
> - randomization延迟时间的随机化因子通常为 0.5
> - ignoreErrors忽略的错误当 f 返回的错误在 ignoreErrors 中时,将不会进行重试
***
#### func ConditionalRetryByExponentialBackoff(f func () error, cond func () bool, maxRetries int, baseDelay time.Duration, maxDelay time.Duration, multiplier float64, randomization float64, ignoreErrors ...error) error
<span id="ConditionalRetryByExponentialBackoff"></span>
> 该函数与 RetryByExponentialBackoff 类似,但是可以被中断
> - cond 为中断条件,当 cond 返回 false 时,将会中断重试
>
> 该函数通常用于在重试过程中,需要中断重试的场景,例如:
> - 用户请求开始游戏,由于网络等情况,进入重试状态。此时用户再次发送开始游戏请求,此时需要中断之前的重试,避免重复进入游戏
***
#### func RetryAsync(count int, interval time.Duration, f func () error, callback func (err error))
<span id="RetryAsync"></span>
> 与 Retry 类似,但是是异步执行
> - 传入的 callback 函数会在执行完毕后被调用,如果执行成功,则 err 为 nil否则为错误信息
> - 如果 callback 为 nil则不会在执行完毕后被调用
***
#### func RetryForever(interval time.Duration, f func () error)
<span id="RetryForever"></span>
> 根据提供的 interval 时间间隔尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功
***
#### func NewStackGo() *StackGo
<span id="NewStackGo"></span>
> 返回一个用于获取上一个协程调用的堆栈信息的收集器
***
#### func LaunchTime() time.Time
<span id="LaunchTime"></span>
> 获取程序启动时间
***
#### func Hostname() string
<span id="Hostname"></span>
> 获取主机名
***
#### func PID() int
<span id="PID"></span>
> 获取进程 PID
***
#### func StringToBytes(s string) []byte
<span id="StringToBytes"></span>
> 以零拷贝的方式将字符串转换为字节切片
***
#### func BytesToString(b []byte) string
<span id="BytesToString"></span>
> 以零拷贝的方式将字节切片转换为字符串
***
#### func Convert(src A) B
<span id="Convert"></span>
> 以零拷贝的方式将一个对象转换为另一个对象
> - 两个对象字段必须完全一致
> - 该函数可以绕过私有字段的访问限制
***
#### func Verify(handle func ( V)) *VerifyHandle[V]
<span id="Verify"></span>
> 对特定表达式进行校验,当表达式不成立时,将执行 handle
***
#### func OldVersion(version1 string, version2 string) bool
<span id="OldVersion"></span>
> 检查 version2 对于 version1 来说是不是旧版本
***
#### func CompareVersion(version1 string, version2 string) int
<span id="CompareVersion"></span>
> 返回一个整数,用于表示两个版本号的比较结果:
> - 如果 version1 大于 version2它将返回 1
> - 如果 version1 小于 version2它将返回 -1
> - 如果 version1 和 version2 相等,它将返回 0
***
### BitSet
是一个可以动态增长的比特位集合
- 默认情况下将使用 64 位无符号整数来表示比特位,当需要表示的比特位超过 64 位时,将自动增长
```go
type BitSet[Bit generic.Integer] struct {
set []uint64
}
```
#### func (*BitSet) Set(bit Bit) *BitSet[Bit]
> 将指定的位 bit 设置为 1
***
#### func (*BitSet) Del(bit Bit) *BitSet[Bit]
> 将指定的位 bit 设置为 0
***
#### func (*BitSet) Shrink() *BitSet[Bit]
> 将 BitSet 中的比特位集合缩小到最小
> - 正常情况下当 BitSet 中的比特位超出 64 位时,将自动增长,当 BitSet 中的比特位数量减少时,可以使用该方法将 BitSet 中的比特位集合缩小到最小
***
#### func (*BitSet) Cap() int
> 返回当前 BitSet 中可以表示的最大比特位数量
***
#### func (*BitSet) Has(bit Bit) bool
> 检查指定的位 bit 是否被设置为 1
***
#### func (*BitSet) Clear() *BitSet[Bit]
> 清空所有的比特位
***
#### func (*BitSet) Len() int
> 返回当前 BitSet 中被设置的比特位数量
***
#### func (*BitSet) Bits() []Bit
> 返回当前 BitSet 中被设置的比特位
***
#### func (*BitSet) Reverse() *BitSet[Bit]
> 反转当前 BitSet 中的所有比特位
***
#### func (*BitSet) Not() *BitSet[Bit]
> 返回当前 BitSet 中所有比特位的反转
***
#### func (*BitSet) And(other *BitSet[Bit]) *BitSet[Bit]
> 将当前 BitSet 与另一个 BitSet 进行按位与运算
***
#### func (*BitSet) Or(other *BitSet[Bit]) *BitSet[Bit]
> 将当前 BitSet 与另一个 BitSet 进行按位或运算
***
#### func (*BitSet) Xor(other *BitSet[Bit]) *BitSet[Bit]
> 将当前 BitSet 与另一个 BitSet 进行按位异或运算
***
#### func (*BitSet) Sub(other *BitSet[Bit]) *BitSet[Bit]
> 将当前 BitSet 与另一个 BitSet 进行按位减运算
***
#### func (*BitSet) IsZero() bool
> 检查当前 BitSet 是否为空
***
#### func (*BitSet) Clone() *BitSet[Bit]
> 返回当前 BitSet 的副本
***
#### func (*BitSet) Equal(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否与另一个 BitSet 相等
***
#### func (*BitSet) Contains(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否包含另一个 BitSet
***
#### func (*BitSet) ContainsAny(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否包含另一个 BitSet 中的任意比特位
***
#### func (*BitSet) ContainsAll(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否包含另一个 BitSet 中的所有比特位
***
#### func (*BitSet) Intersect(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否与另一个 BitSet 有交集
***
#### func (*BitSet) Union(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否与另一个 BitSet 有并集
***
#### func (*BitSet) Difference(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否与另一个 BitSet 有差集
***
#### func (*BitSet) SymmetricDifference(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否与另一个 BitSet 有对称差集
***
#### func (*BitSet) Subset(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否为另一个 BitSet 的子集
***
#### func (*BitSet) Superset(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否为另一个 BitSet 的超集
***
#### func (*BitSet) Complement(other *BitSet[Bit]) bool
> 检查当前 BitSet 是否为另一个 BitSet 的补集
***
#### func (*BitSet) Max() Bit
> 返回当前 BitSet 中最大的比特位
***
#### func (*BitSet) Min() Bit
> 返回当前 BitSet 中最小的比特位
***
#### func (*BitSet) String() string
> 返回当前 BitSet 的字符串表示
***
#### func (*BitSet) MarshalJSON() []byte, error
> 实现 json.Marshaler 接口
***
#### func (*BitSet) UnmarshalJSON(data []byte) error
> 实现 json.Unmarshaler 接口
***
### LossCounter
```go
type LossCounter struct {
curr time.Time
loss []time.Duration
lossKey []string
}
```
#### func (*LossCounter) Record(name string)
> 记录一次损耗
***
#### func (*LossCounter) GetLoss(handler func (step int, name string, loss time.Duration))
> 获取损耗
***
#### func (*LossCounter) String() string
***
### Matcher
匹配器
```go
type Matcher[Value any, Result any] struct {
value Value
r Result
d bool
}
```
### Permission
```go
type Permission[Code generic.Integer, EntityID comparable] struct {
permissions map[EntityID]Code
l sync.RWMutex
}
```
### StackGo
用于获取上一个协程调用的堆栈信息
- 应当最先运行 Wait 函数,然后在其他协程中调用 Stack 函数或者 GiveUp 函数
- 适用于跨协程同步通讯,例如单线程的消息处理统计耗时打印堆栈信息
```go
type StackGo struct {
stack chan *struct{}
collect chan []byte
}
```
#### func (*StackGo) Wait()
> 等待收集消息堆栈
> - 在调用 Wait 函数后,当前协程将会被挂起,直到调用 Stack 或 GiveUp 函数
***
#### func (*StackGo) Stack() []byte
> 获取消息堆栈
> - 在调用 Wait 函数后调用该函数,将会返回上一个协程的堆栈信息
> - 在调用 GiveUp 函数后调用该函数,将会 panic
***
#### func (*StackGo) GiveUp()
> 放弃收集消息堆栈
> - 在调用 Wait 函数后调用该函数,将会放弃收集消息堆栈并且释放资源
> - 在调用 GiveUp 函数后调用 Stack 函数,将会 panic
***
### VerifyHandle
校验句柄
```go
type VerifyHandle[V any] struct {
handle func(V)
v V
hit bool
}
```
#### func (*VerifyHandle) PreCase(expression func () bool, value V, caseHandle func (verify *VerifyHandle[V]) bool) bool
> 先决校验用例,当 expression 成立时,将跳过 caseHandle 的执行,直接执行 handle 并返回 false
> - 常用于对前置参数的空指针校验,例如当 a 为 nil 时,不执行 a.B(),而是直接返回 false
***
#### func (*VerifyHandle) Case(expression bool, value V) *VerifyHandle[V]
> 校验用例,当 expression 成立时,将忽略后续 Case并将在 Do 时执行 handle返回 false
***
#### func (*VerifyHandle) Do() bool
> 执行校验,当校验失败时,将执行 handle并返回 false
***

180
utils/timer/README.md Normal file
View File

@ -0,0 +1,180 @@
# Timer
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/timer)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[RegSystemNewDayEvent](#RegSystemNewDayEvent)|注册系统新的一天事件
|[OnSystemNewDayEvent](#OnSystemNewDayEvent)|系统新的一天事件
|[RegOffsetTimeNewDayEvent](#RegOffsetTimeNewDayEvent)|注册偏移时间新的一天事件
|[OnOffsetTimeNewDayEvent](#OnOffsetTimeNewDayEvent)|偏移时间新的一天事件
|[WithCaller](#WithCaller)|通过其他的 handle 执行 Caller
|[WithMark](#WithMark)|通过特定的标记创建定时器
|[NewPool](#NewPool)|创建一个定时器池,当 tickerPoolSize 小于等于 0 时,将会引发 panic可指定为 DefaultTickerPoolSize
|[SetPoolSize](#SetPoolSize)|设置标准池定时器池大小
|[GetTicker](#GetTicker)|获取标准池中的一个定时器
> 结构体定义
|结构体|描述
|:--|:--
|[SystemNewDayEventHandle](#systemnewdayeventhandle)|暂无描述...
|[Option](#option)|暂无描述...
|[Pool](#pool)|定时器池
|[Scheduler](#scheduler)|调度器
|[Ticker](#ticker)|定时器
</details>
#### func RegSystemNewDayEvent(ticker *Ticker, name string, trigger bool, handle SystemNewDayEventHandle)
<span id="RegSystemNewDayEvent"></span>
> 注册系统新的一天事件
> - 建议全局注册一个事件后再另行拓展
> - 将特定 name 的定时任务注册到 ticker 中,在系统时间到达每天的 00:00:00 时触发,如果 trigger 为 true则立即触发一次
***
#### func OnSystemNewDayEvent(name string)
<span id="OnSystemNewDayEvent"></span>
> 系统新的一天事件
***
#### func RegOffsetTimeNewDayEvent(ticker *Ticker, name string, offset *offset.Time, trigger bool, handle OffsetTimeNewDayEventHandle)
<span id="RegOffsetTimeNewDayEvent"></span>
> 注册偏移时间新的一天事件
> - 建议全局注册一个事件后再另行拓展
> - 与 RegSystemNewDayEvent 类似,但是触发时间为 offset 时间到达每天的 00:00:00
***
#### func OnOffsetTimeNewDayEvent(name string)
<span id="OnOffsetTimeNewDayEvent"></span>
> 偏移时间新的一天事件
***
#### func WithCaller(handle func (name string, caller func ())) Option
<span id="WithCaller"></span>
> 通过其他的 handle 执行 Caller
***
#### func WithMark(mark string) Option
<span id="WithMark"></span>
> 通过特定的标记创建定时器
***
#### func NewPool(tickerPoolSize int) *Pool
<span id="NewPool"></span>
> 创建一个定时器池,当 tickerPoolSize 小于等于 0 时,将会引发 panic可指定为 DefaultTickerPoolSize
***
#### func SetPoolSize(size int)
<span id="SetPoolSize"></span>
> 设置标准池定时器池大小
> - 默认值为 DefaultTickerPoolSize当定时器池中的定时器不足时会自动创建新的定时器当定时器释放时会将多余的定时器进行释放否则将放入定时器池中
***
#### func GetTicker(size int, options ...Option) *Ticker
<span id="GetTicker"></span>
> 获取标准池中的一个定时器
***
### SystemNewDayEventHandle
```go
type SystemNewDayEventHandle struct{}
```
### Option
```go
type Option struct{}
```
### Pool
定时器池
```go
type Pool struct {
tickers []*Ticker
lock sync.Mutex
tickerPoolSize int
closed bool
}
```
#### func (*Pool) ChangePoolSize(size int) error
> 改变定时器池大小
> - 当传入的大小小于或等于 0 时,将会返回错误,并且不会发生任何改变
***
#### func (*Pool) GetTicker(size int, options ...Option) *Ticker
> 获取一个新的定时器
***
#### func (*Pool) Release()
> 释放定时器池的资源,释放后由其产生的 Ticker 在 Ticker.Release 后将不再回到池中,而是直接释放
> - 虽然定时器池已被释放,但是依旧可以产出 Ticker
***
### Scheduler
调度器
```go
type Scheduler struct {
name string
after time.Duration
interval time.Duration
total int
trigger int
kill bool
cbFunc reflect.Value
cbArgs []reflect.Value
timer *timingwheel.Timer
ticker *Ticker
lock sync.RWMutex
expr *cronexpr.Expression
}
```
#### func (*Scheduler) Name() string
> 获取调度器名称
***
#### func (*Scheduler) Next(prev time.Time) time.Time
> 获取下一次执行的时间
***
#### func (*Scheduler) Caller()
> 可由外部发起调用的执行函数
***
### Ticker
定时器
```go
type Ticker struct {
timer *Pool
wheel *timingwheel.TimingWheel
timers map[string]*Scheduler
lock sync.RWMutex
handle func(name string, caller func())
mark string
}
```
#### func (*Ticker) Mark() string
> 获取定时器的标记
> - 通常用于鉴别定时器来源
***
#### func (*Ticker) Release()
> 释放定时器,并将定时器重新放回 Pool 池中
***
#### func (*Ticker) StopTimer(name string)
> 停止特定名称的调度器
***
#### func (*Ticker) IsStopped(name string) bool
> 特定名称的调度器是否已停止
***
#### func (*Ticker) GetSchedulers() []string
> 获取所有调度器名称
***
#### func (*Ticker) Cron(name string, expression string, handleFunc interface {}, args ...interface {})
> 通过 cron 表达式设置一个调度器,当 cron 表达式错误时,将会引发 panic
***
#### func (*Ticker) CronByInstantly(name string, expression string, handleFunc interface {}, args ...interface {})
> 与 Cron 相同,但是会立即执行一次
***
#### func (*Ticker) After(name string, after time.Duration, handleFunc interface {}, args ...interface {})
> 设置一个在特定时间后运行一次的调度器
***
#### func (*Ticker) Loop(name string, after time.Duration, interval time.Duration, times int, handleFunc interface {}, args ...interface {})
> 设置一个在特定时间后反复运行的调度器
***

427
utils/times/README.md Normal file
View File

@ -0,0 +1,427 @@
# Times
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/times)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[CalcNextSec](#CalcNextSec)|计算下一个N秒在多少秒之后
|[CalcNextSecWithTime](#CalcNextSecWithTime)|计算下一个N秒在多少秒之后
|[CalcNextTimeWithRefer](#CalcNextTimeWithRefer)|根据参考时间计算下一个整点时间
|[IntervalFormatSet](#IntervalFormatSet)|针对 IntervalFormat 函数设置格式化内容
|[IntervalFormat](#IntervalFormat)|返回指定时间戳之间的间隔
|[GetMonthDays](#GetMonthDays)|获取一个时间当月共有多少天
|[WeekDay](#WeekDay)|获取一个时间是星期几
|[GetNextDayInterval](#GetNextDayInterval)|获取一个时间到下一天间隔多少秒
|[GetToday](#GetToday)|获取一个时间的今天
|[GetSecond](#GetSecond)|获取共有多少秒
|[IsSameDay](#IsSameDay)|两个时间是否是同一天
|[IsSameHour](#IsSameHour)|两个时间是否是同一小时
|[GetMondayZero](#GetMondayZero)|获取本周一零点
|[Date](#Date)|返回一个特定日期的时间
|[DateWithHMS](#DateWithHMS)|返回一个精确到秒的时间
|[GetDeltaDay](#GetDeltaDay)|获取两个时间需要加减的天数
|[GetDeltaWeek](#GetDeltaWeek)|获取两个时间需要加减的周数
|[GetHSMFromString](#GetHSMFromString)|从时间字符串中获取时分秒
|[GetTimeFromString](#GetTimeFromString)|将时间字符串转化为时间
|[GetDayZero](#GetDayZero)|获取 t 增加 day 天后的零点时间
|[GetYesterday](#GetYesterday)|获取昨天
|[GetDayLast](#GetDayLast)|获取某天的最后一刻
|[GetYesterdayLast](#GetYesterdayLast)|获取昨天最后一刻
|[GetMinuteStart](#GetMinuteStart)|获取一个时间的 0 秒
|[GetMinuteEnd](#GetMinuteEnd)|获取一个时间的 59 秒
|[GetHourStart](#GetHourStart)|获取一个时间的 0 分 0 秒
|[GetHourEnd](#GetHourEnd)|获取一个时间的 59 分 59 秒
|[GetMonthStart](#GetMonthStart)|获取一个时间的月初
|[GetMonthEnd](#GetMonthEnd)|获取一个时间的月末
|[GetYearStart](#GetYearStart)|获取一个时间的年初
|[GetYearEnd](#GetYearEnd)|获取一个时间的年末
|[NewStateLine](#NewStateLine)|创建一个从左向右由早到晚的状态时间线
|[SetGlobalTimeOffset](#SetGlobalTimeOffset)|设置全局时间偏移量
|[NowByNotOffset](#NowByNotOffset)|获取未偏移的当前时间
|[GetGlobalTimeOffset](#GetGlobalTimeOffset)|获取全局时间偏移量
|[ResetGlobalTimeOffset](#ResetGlobalTimeOffset)|重置全局时间偏移量
|[NewPeriod](#NewPeriod)|创建一个时间段
|[NewPeriodWindow](#NewPeriodWindow)|创建一个特定长度的时间窗口
|[NewPeriodWindowWeek](#NewPeriodWindowWeek)|创建一周长度的时间窗口,从周一零点开始至周日 23:59:59 结束
|[NewPeriodWithTimeArray](#NewPeriodWithTimeArray)|创建一个时间段
|[NewPeriodWithDayZero](#NewPeriodWithDayZero)|创建一个时间段,从 t 开始,持续到 day 天后的 0 点
|[NewPeriodWithDay](#NewPeriodWithDay)|创建一个时间段,从 t 开始,持续 day 天
|[NewPeriodWithHour](#NewPeriodWithHour)|创建一个时间段,从 t 开始,持续 hour 小时
|[NewPeriodWithMinute](#NewPeriodWithMinute)|创建一个时间段,从 t 开始,持续 minute 分钟
|[NewPeriodWithSecond](#NewPeriodWithSecond)|创建一个时间段,从 t 开始,持续 second 秒
|[NewPeriodWithMillisecond](#NewPeriodWithMillisecond)|创建一个时间段,从 t 开始,持续 millisecond 毫秒
|[NewPeriodWithMicrosecond](#NewPeriodWithMicrosecond)|创建一个时间段,从 t 开始,持续 microsecond 微秒
|[NewPeriodWithNanosecond](#NewPeriodWithNanosecond)|创建一个时间段,从 t 开始,持续 nanosecond 纳秒
> 结构体定义
|结构体|描述
|:--|:--
|[StateLine](#stateline)|状态时间线
|[Period](#period)|表示一个时间段
</details>
#### func CalcNextSec(sec int) int
<span id="CalcNextSec"></span>
> 计算下一个N秒在多少秒之后
***
#### func CalcNextSecWithTime(t time.Time, sec int) int
<span id="CalcNextSecWithTime"></span>
> 计算下一个N秒在多少秒之后
***
#### func CalcNextTimeWithRefer(now time.Time, refer time.Duration) time.Time
<span id="CalcNextTimeWithRefer"></span>
> 根据参考时间计算下一个整点时间
> - 假设当 now 为 14:15:16 参考时间为 10 分钟, 则返回 14:20:00
> - 假设当 now 为 14:15:16 参考时间为 20 分钟, 则返回 14:20:00
>
> 当 refer 小于 1 分钟时,将会返回当前时间
***
#### func IntervalFormatSet(intervalType int, str string)
<span id="IntervalFormatSet"></span>
> 针对 IntervalFormat 函数设置格式化内容
***
#### func IntervalFormat(time1 time.Time, time2 time.Time) string
<span id="IntervalFormat"></span>
> 返回指定时间戳之间的间隔
> - 使用传入的时间进行计算换算,将结果体现为几年前、几天前、几小时前、几分钟前、几秒前。
***
#### func GetMonthDays(t time.Time) int
<span id="GetMonthDays"></span>
> 获取一个时间当月共有多少天
***
#### func WeekDay(t time.Time) int
<span id="WeekDay"></span>
> 获取一个时间是星期几
> - 1 ~ 7
***
#### func GetNextDayInterval(t time.Time) time.Duration
<span id="GetNextDayInterval"></span>
> 获取一个时间到下一天间隔多少秒
***
#### func GetToday(t time.Time) time.Time
<span id="GetToday"></span>
> 获取一个时间的今天
***
#### func GetSecond(d time.Duration) int
<span id="GetSecond"></span>
> 获取共有多少秒
***
#### func IsSameDay(t1 time.Time, t2 time.Time) bool
<span id="IsSameDay"></span>
> 两个时间是否是同一天
***
#### func IsSameHour(t1 time.Time, t2 time.Time) bool
<span id="IsSameHour"></span>
> 两个时间是否是同一小时
***
#### func GetMondayZero(t time.Time) time.Time
<span id="GetMondayZero"></span>
> 获取本周一零点
***
#### func Date(year int, month time.Month, day int) time.Time
<span id="Date"></span>
> 返回一个特定日期的时间
***
#### func DateWithHMS(year int, month time.Month, day int, hour int, min int, sec int) time.Time
<span id="DateWithHMS"></span>
> 返回一个精确到秒的时间
***
#### func GetDeltaDay(t1 time.Time, t2 time.Time) int
<span id="GetDeltaDay"></span>
> 获取两个时间需要加减的天数
***
#### func GetDeltaWeek(t1 time.Time, t2 time.Time) int
<span id="GetDeltaWeek"></span>
> 获取两个时间需要加减的周数
***
#### func GetHSMFromString(timeStr string, layout string) (hour int, min int, sec int)
<span id="GetHSMFromString"></span>
> 从时间字符串中获取时分秒
***
#### func GetTimeFromString(timeStr string, layout string) time.Time
<span id="GetTimeFromString"></span>
> 将时间字符串转化为时间
***
#### func GetDayZero(t time.Time, day int) time.Time
<span id="GetDayZero"></span>
> 获取 t 增加 day 天后的零点时间
***
#### func GetYesterday(t time.Time) time.Time
<span id="GetYesterday"></span>
> 获取昨天
***
#### func GetDayLast(t time.Time) time.Time
<span id="GetDayLast"></span>
> 获取某天的最后一刻
> - 最后一刻即 23:59:59
***
#### func GetYesterdayLast(t time.Time) time.Time
<span id="GetYesterdayLast"></span>
> 获取昨天最后一刻
***
#### func GetMinuteStart(t time.Time) time.Time
<span id="GetMinuteStart"></span>
> 获取一个时间的 0 秒
***
#### func GetMinuteEnd(t time.Time) time.Time
<span id="GetMinuteEnd"></span>
> 获取一个时间的 59 秒
***
#### func GetHourStart(t time.Time) time.Time
<span id="GetHourStart"></span>
> 获取一个时间的 0 分 0 秒
***
#### func GetHourEnd(t time.Time) time.Time
<span id="GetHourEnd"></span>
> 获取一个时间的 59 分 59 秒
***
#### func GetMonthStart(t time.Time) time.Time
<span id="GetMonthStart"></span>
> 获取一个时间的月初
***
#### func GetMonthEnd(t time.Time) time.Time
<span id="GetMonthEnd"></span>
> 获取一个时间的月末
***
#### func GetYearStart(t time.Time) time.Time
<span id="GetYearStart"></span>
> 获取一个时间的年初
***
#### func GetYearEnd(t time.Time) time.Time
<span id="GetYearEnd"></span>
> 获取一个时间的年末
***
#### func NewStateLine(zero State) *StateLine[State]
<span id="NewStateLine"></span>
> 创建一个从左向右由早到晚的状态时间线
***
#### func SetGlobalTimeOffset(offset time.Duration)
<span id="SetGlobalTimeOffset"></span>
> 设置全局时间偏移量
***
#### func NowByNotOffset() time.Time
<span id="NowByNotOffset"></span>
> 获取未偏移的当前时间
***
#### func GetGlobalTimeOffset() time.Duration
<span id="GetGlobalTimeOffset"></span>
> 获取全局时间偏移量
***
#### func ResetGlobalTimeOffset()
<span id="ResetGlobalTimeOffset"></span>
> 重置全局时间偏移量
***
#### func NewPeriod(start time.Time, end time.Time) Period
<span id="NewPeriod"></span>
> 创建一个时间段
> - 如果 start 比 end 晚,则会自动交换两个时间
***
#### func NewPeriodWindow(t time.Time, size time.Duration) Period
<span id="NewPeriodWindow"></span>
> 创建一个特定长度的时间窗口
***
#### func NewPeriodWindowWeek(t time.Time) Period
<span id="NewPeriodWindowWeek"></span>
> 创建一周长度的时间窗口,从周一零点开始至周日 23:59:59 结束
***
#### func NewPeriodWithTimeArray(times [2]time.Time) Period
<span id="NewPeriodWithTimeArray"></span>
> 创建一个时间段
***
#### func NewPeriodWithDayZero(t time.Time, day int) Period
<span id="NewPeriodWithDayZero"></span>
> 创建一个时间段,从 t 开始,持续到 day 天后的 0 点
***
#### func NewPeriodWithDay(t time.Time, day int) Period
<span id="NewPeriodWithDay"></span>
> 创建一个时间段,从 t 开始,持续 day 天
***
#### func NewPeriodWithHour(t time.Time, hour int) Period
<span id="NewPeriodWithHour"></span>
> 创建一个时间段,从 t 开始,持续 hour 小时
***
#### func NewPeriodWithMinute(t time.Time, minute int) Period
<span id="NewPeriodWithMinute"></span>
> 创建一个时间段,从 t 开始,持续 minute 分钟
***
#### func NewPeriodWithSecond(t time.Time, second int) Period
<span id="NewPeriodWithSecond"></span>
> 创建一个时间段,从 t 开始,持续 second 秒
***
#### func NewPeriodWithMillisecond(t time.Time, millisecond int) Period
<span id="NewPeriodWithMillisecond"></span>
> 创建一个时间段,从 t 开始,持续 millisecond 毫秒
***
#### func NewPeriodWithMicrosecond(t time.Time, microsecond int) Period
<span id="NewPeriodWithMicrosecond"></span>
> 创建一个时间段,从 t 开始,持续 microsecond 微秒
***
#### func NewPeriodWithNanosecond(t time.Time, nanosecond int) Period
<span id="NewPeriodWithNanosecond"></span>
> 创建一个时间段,从 t 开始,持续 nanosecond 纳秒
***
### StateLine
状态时间线
```go
type StateLine[State generic.Basic] struct {
states []State
points []time.Time
trigger [][]func()
}
```
#### func (*StateLine) Check(missingAllowed bool, states ...State) bool
> 根据状态顺序检查时间线是否合法
> - missingAllowed: 是否允许状态缺失,如果为 true则状态可以不连续如果为 false则状态必须连续
>
> 状态不连续表示时间线中存在状态缺失,例如:
> - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 true则状态为 [1, 3, 5] 也是合法的
> - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 false则状态为 [1, 3, 5] 是不合法的
***
#### func (*StateLine) GetMissingStates(states ...State) []State
> 获取缺失的状态
***
#### func (*StateLine) HasState(state State) bool
> 检查时间线中是否包含指定状态
***
#### func (*StateLine) String() string
> 获取时间线的字符串表示
***
#### func (*StateLine) AddState(state State, t time.Time, onTrigger ...func ()) *StateLine[State]
> 添加一个状态到时间线中,状态不能与任一时间点重合,否则将被忽略
> - onTrigger: 该状态绑定的触发器,该触发器不会被主动执行,需要主动获取触发器执行
***
#### func (*StateLine) GetTimeByState(state State) time.Time
> 获取指定状态的时间点
***
#### func (*StateLine) GetNextTimeByState(state State) time.Time
> 获取指定状态的下一个时间点
***
#### func (*StateLine) GetLastState() State
> 获取最后一个状态
***
#### func (*StateLine) GetPrevTimeByState(state State) time.Time
> 获取指定状态的上一个时间点
***
#### func (*StateLine) GetIndexByState(state State) int
> 获取指定状态的索引
***
#### func (*StateLine) GetStateByTime(t time.Time) State
> 获取指定时间点的状态
***
#### func (*StateLine) GetTimeByIndex(index int) time.Time
> 获取指定索引的时间点
***
#### func (*StateLine) Move(d time.Duration) *StateLine[State]
> 时间线整体移动
***
#### func (*StateLine) GetNextStateTimeByIndex(index int) time.Time
> 获取指定索引的下一个时间点
***
#### func (*StateLine) GetPrevStateTimeByIndex(index int) time.Time
> 获取指定索引的上一个时间点
***
#### func (*StateLine) GetStateIndexByTime(t time.Time) int
> 获取指定时间点的索引
***
#### func (*StateLine) GetStateCount() int
> 获取状态数量
***
#### func (*StateLine) GetStateByIndex(index int) State
> 获取指定索引的状态
***
#### func (*StateLine) GetTriggerByTime(t time.Time) []func ()
> 获取指定时间点的触发器
***
#### func (*StateLine) GetTriggerByIndex(index int) []func ()
> 获取指定索引的触发器
***
#### func (*StateLine) GetTriggerByState(state State) []func ()
> 获取指定状态的触发器
***
#### func (*StateLine) AddTriggerToState(state State, onTrigger ...func ()) *StateLine[State]
> 给指定状态添加触发器
***
#### func (*StateLine) Range(handler func (index int, state State, t time.Time) bool)
> 按照时间顺序遍历时间线
***
#### func (*StateLine) RangeReverse(handler func (index int, state State, t time.Time) bool)
> 按照时间逆序遍历时间线
***
### Period
表示一个时间段
```go
type Period struct{}
```
#### func (Period) Start() time.Time
> 返回时间段的开始时间
***
#### func (Period) End() time.Time
> 返回时间段的结束时间
***
#### func (Period) Duration() time.Duration
> 返回时间段的持续时间
***
#### func (Period) Day() int
> 返回时间段的持续天数
***
#### func (Period) Hour() int
> 返回时间段的持续小时数
***
#### func (Period) Minute() int
> 返回时间段的持续分钟数
***
#### func (Period) Seconds() int
> 返回时间段的持续秒数
***
#### func (Period) Milliseconds() int
> 返回时间段的持续毫秒数
***
#### func (Period) Microseconds() int
> 返回时间段的持续微秒数
***
#### func (Period) Nanoseconds() int
> 返回时间段的持续纳秒数
***
#### func (Period) IsZero() bool
> 判断时间段是否为零值
***
#### func (Period) IsInvalid() bool
> 判断时间段是否无效
***
#### func (Period) IsBefore(t time.Time) bool
> 判断时间段是否在指定时间之前
***
#### func (Period) IsAfter(t time.Time) bool
> 判断时间段是否在指定时间之后
***
#### func (Period) IsBetween(t time.Time) bool
> 判断指定时间是否在时间段之间
***
#### func (Period) IsOngoing(t time.Time) bool
> 判断指定时间是否正在进行时
> - 如果时间段的开始时间在指定时间之前或者等于指定时间,且时间段的结束时间在指定时间之后,则返回 true
***
#### func (Period) IsBetweenOrEqual(t time.Time) bool
> 判断指定时间是否在时间段之间或者等于时间段的开始或结束时间
***
#### func (Period) IsBetweenOrEqualPeriod(t Period) bool
> 判断指定时间是否在时间段之间或者等于时间段的开始或结束时间
***
#### func (Period) IsOverlap(t Period) bool
> 判断时间段是否与指定时间段重叠
***

32
utils/xlsxtool/README.md Normal file
View File

@ -0,0 +1,32 @@
# Xlsxtool
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/xlsxtool)
![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat)
## 目录
列出了该 `package` 下所有的函数,可通过目录进行快捷跳转 ❤️
<details>
<summary>展开 / 折叠目录</summary
> 包级函数定义
|函数|描述
|:--|:--
|[GetSheetMatrix](#GetSheetMatrix)|将sheet转换为二维矩阵
> 结构体定义
|结构体|描述
|:--|:--
</details>
#### func GetSheetMatrix(sheet *xlsx.Sheet) *matrix.Matrix[*xlsx.Cell]
<span id="GetSheetMatrix"></span>
> 将sheet转换为二维矩阵
***