diff --git a/.github/images/pod.png b/.github/images/pod.png new file mode 100644 index 0000000..30a16c7 Binary files /dev/null and b/.github/images/pod.png differ diff --git a/.github/images/yc-cpu.png b/.github/images/yc-cpu.png new file mode 100644 index 0000000..65a32e1 Binary files /dev/null and b/.github/images/yc-cpu.png differ diff --git a/.github/images/yc-event.png b/.github/images/yc-event.png new file mode 100644 index 0000000..ddfa322 Binary files /dev/null and b/.github/images/yc-event.png differ diff --git a/.github/images/yc-memory.png b/.github/images/yc-memory.png new file mode 100644 index 0000000..bf73cfa Binary files /dev/null and b/.github/images/yc-memory.png differ diff --git a/.github/images/yc1.png b/.github/images/yc1.png new file mode 100644 index 0000000..30a6f35 Binary files /dev/null and b/.github/images/yc1.png differ diff --git a/.github/images/yc2.png b/.github/images/yc2.png new file mode 100644 index 0000000..aac82d9 Binary files /dev/null and b/.github/images/yc2.png differ diff --git a/README.md b/README.md index 6befa61..7d63835 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,53 @@ # Minotaur +Minotaur 是一个用于服务端开发的支持库,其中采用了大量泛型设计,主要被用于游戏服务器开发,但由于拥有大量通用的功能,也常被用于 WEB 开发。 +*** + [![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) -![](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat) -![](https://komarev.com/ghpvc/?username=kercylan98) +![license](https://img.shields.io/github/license/kercylan98/minotaur) -Minotaur 是一个基于 Golang 1.20 编写的服务端开发支持库,其中采用了大量泛型设计,主要被用于游戏服务器开发,但由于拥有大量通用的功能,也常被用于 WEB 开发。 +![go version](https://img.shields.io/github/go-mod/go-version/kercylan98/minotaur?logo=go&style=flat) +![tag](https://img.shields.io/github/v/tag/kercylan98/minotaur?logo=github&style=flat) +![views](https://komarev.com/ghpvc/?username=kercylan98&color=blue&style=flat) + +![email](https://img.shields.io/badge/Email-kercylan@gmail.com-green.svg?style=flat&logo=gmail&link=mailto:kercylan@gmail.com) +![qq-group](https://img.shields.io/badge/QQ%20Group-758219443-green.svg?style=flat&logo=tencent-qq&link=https://qm.qq.com/cgi-bin/qm/qr?k=WzRWJIDLzuJbH6-VjdFiTCd1_qA_Ug-D&jump_from=webapi&authKey=ktLEw3XyY9yO+i9rPbI6Fk0UA0uEhACcUidOFdblaiToZtbHcXyU7sFb31FEc9JJ&noverify=0) +![telegram](https://img.shields.io/badge/Telegram-ziv__siren-green.svg?style=flat&logo=telegram&link=https://telegram.me/ziv_siren) + +> - 这是支持快速搭建多功能游戏服务器及 HTTP 服务器的 `Golang` 服务端框架; +> - 网络传输基于 [`gorilla/websocket`](https://github.com/gorilla/websocket)、[`gin-gonic/gin`](https://github.com/gin-gonic/gin)、[`grpc/grpc-go`](https://github.com/grpc/grpc-go)、[`panjf2000/gnet`](https://github.com/panjf2000/gnet)、[`xtaci/kcp-go`](https://github.com/xtaci/kcp-go) 构建; +> - 该项目的目标是提供一个简单、高效、可扩展的游戏服务器框架,让开发者可以专注于游戏逻辑的开发,而不用花费大量时间在网络传输、配置导表、日志、监控等基础功能的开发上; + +*** +在 Minotaur 中不包括任何跨服实现,但支持基于多级路由器快速实现跨服功能。推荐使用 [`NATS.io`](https://nats.io/) 作为跨服消息中间件。 + - 目前已实践的弹幕游戏项目以 `NATS.io` 作为消息队列,实现了跨服、埋点日志收集等功能,部署在 `Kubernetes` 集群中; + - 该项目客户端与服务端采用 `WebSocket` 进行通讯,服务端暴露 `HTTP` 接口接收互动数据消息回调,通过负载均衡器进入 `Kubernetes` 集群中的 `Minotaur` 服务,最终通过 `NATS.io` 消息队列转发至对应所在的 `Pod` 中进行处理; + +
+关于 Pod 配置参数及非极限压测数据 + +> 本次压测 `Pod` 扩容数量为 1,但由于压测连接是最开始就建立好的,所以该扩容的 `Pod` 并没有接受到压力。 +> 理论上来说该 `Pod` 也应该接受 `HTTP` 回调压力,实测过程中,这个扩容的 `Pod` 没有接受到任何压力 + +**Pod 配置参数** + +![pod](.github/images/pod.png) + +**压测结果** + +![压测数据](.github/images/yc1.png) +![压测数据](.github/images/yc2.png) + +**监控数据** + +![事件](./.github/images/yc-event.png) +![CPU](./.github/images/yc-cpu.png) +![内存](./.github/images/yc-memory.png) + +
+ +*** ## 特色内容 ```mermaid diff --git a/server/README.md b/server/README.md index bb0d216..25df78f 100644 --- a/server/README.md +++ b/server/README.md @@ -47,6 +47,8 @@ server 提供了包含多种网络类型的服务器实现 |[WithWebsocketMessageType](#WithWebsocketMessageType)|设置仅支持特定类型的Websocket消息 |[WithPProf](#WithPProf)|通过性能分析工具PProf创建服务器 |[New](#New)|根据特定网络类型创建一个服务器 +|[LoadData](#LoadData)|加载绑定的服务器数据 +|[BindData](#BindData)|绑定数据到特定服务器 |[BindService](#BindService)|绑定服务到特定 Server,被绑定的服务将会在 Server 初始化时执行 Service.OnInit 方法 @@ -515,6 +517,16 @@ func TestNew(t *testing.T) { +*** +#### func LoadData\[T any\](srv *Server, name string, data any) T + +> 加载绑定的服务器数据 + +*** +#### func BindData(srv *Server, name string, data any) + +> 绑定数据到特定服务器 + *** #### func BindService(srv *Server, services ...Service) @@ -1340,6 +1352,7 @@ type Server struct { systemSignal chan os.Signal closeChannel chan struct{} multipleRuntimeErrorChan chan error + data map[string]any messageCounter atomic.Int64 addr string network Network @@ -1347,6 +1360,18 @@ type Server struct { services []func() } ``` + + +#### func (*Server) LoadData(name string, data any) any +> 加载绑定的服务器数据 + +*** + + +#### func (*Server) BindData(name string, data any) +> 绑定数据到特定服务器 + +*** #### func (*Server) Run(addr string) (err error) diff --git a/utils/collection/README.md b/utils/collection/README.md index 4c5f566..64f38b0 100644 --- a/utils/collection/README.md +++ b/utils/collection/README.md @@ -22,6 +22,10 @@ collection 定义了各种对于集合操作有用的各种函数 |[CloneMapN](#CloneMapN)|通过创建一个新 map 并将 m 的元素复制到新 map 的方式来克隆 map 为 n 个 map |[CloneSlices](#CloneSlices)|对 slices 中的每一项元素进行克隆,最终返回一个新的二维切片 |[CloneMaps](#CloneMaps)|对 maps 中的每一项元素进行克隆,最终返回一个新的 map 切片 +|[EqualSlice](#EqualSlice)|检查两个切片是否相等,当 handler 返回 true 时,表示 slice1 中的某个元素和 slice2 中的某个元素相匹配 +|[EqualComparableSlice](#EqualComparableSlice)|检查两个切片的值是否相同 +|[EqualMap](#EqualMap)|检查两个 map 是否相等,当 handler 返回 true 时,表示 map1 中的某个元素和 map2 中的某个元素相匹配 +|[EqualComparableMap](#EqualComparableMap)|检查两个 map 的值是否相同 |[InSlice](#InSlice)|检查 v 是否被包含在 slice 中,当 handler 返回 true 时,表示 v 和 slice 中的某个元素相匹配 |[InComparableSlice](#InComparableSlice)|检查 v 是否被包含在 slice 中 |[AllInSlice](#AllInSlice)|检查 values 中的所有元素是否均被包含在 slice 中,当 handler 返回 true 时,表示 values 中的某个元素和 slice 中的某个元素相匹配 @@ -50,6 +54,9 @@ collection 定义了各种对于集合操作有用的各种函数 |[AnyValueInMaps](#AnyValueInMaps)|检查 maps 中的任意一个元素是否包含 value 中的任意一个元素,当 handler 返回 true 时,表示 value 中的某个元素和 maps 中的某个元素相匹配 |[KeyInAllMaps](#KeyInAllMaps)|检查 key 是否被包含在 maps 的每一个元素中 |[AnyKeyInAllMaps](#AnyKeyInAllMaps)|检查 maps 中的每一个元素是否均包含 keys 中任意一个元素 +|[ConvertSliceToBatches](#ConvertSliceToBatches)|将切片 s 转换为分批次的切片,当 batchSize 小于等于 0 或者 s 长度为 0 时,将会返回 nil +|[ConvertMapKeysToBatches](#ConvertMapKeysToBatches)|将映射的键转换为分批次的切片,当 batchSize 小于等于 0 或者 m 长度为 0 时,将会返回 nil +|[ConvertMapValuesToBatches](#ConvertMapValuesToBatches)|将映射的值转换为分批次的切片,当 batchSize 小于等于 0 或者 m 长度为 0 时,将会返回 nil |[ConvertSliceToAny](#ConvertSliceToAny)|将切片转换为任意类型的切片 |[ConvertSliceToIndexMap](#ConvertSliceToIndexMap)|将切片转换为索引为键的映射 |[ConvertSliceToIndexOnlyMap](#ConvertSliceToIndexOnlyMap)|将切片转换为索引为键的映射 @@ -99,6 +106,17 @@ collection 定义了各种对于集合操作有用的各种函数 |[FindMin2MaxFromComparableMap](#FindMin2MaxFromComparableMap)|获取 map 中的最小值和最大值 |[FindMin2MaxFromMap](#FindMin2MaxFromMap)|获取 map 中的最小值和最大值 |[SwapSlice](#SwapSlice)|将切片中的两个元素进行交换 +|[LoopSlice](#LoopSlice)|迭代切片 slice 中的每一个函数,并将索引和值传递给 f 函数 +|[ReverseLoopSlice](#ReverseLoopSlice)|逆序迭代切片 slice 中的每一个函数,并将索引和值传递给 f 函数 +|[LoopMap](#LoopMap)|迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByOrderedKeyAsc](#LoopMapByOrderedKeyAsc)|按照键的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByOrderedKeyDesc](#LoopMapByOrderedKeyDesc)|按照键的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByOrderedValueAsc](#LoopMapByOrderedValueAsc)|按照值的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByOrderedValueDesc](#LoopMapByOrderedValueDesc)|按照值的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByKeyGetterAsc](#LoopMapByKeyGetterAsc)|按照键的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByValueGetterAsc](#LoopMapByValueGetterAsc)|按照值的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByKeyGetterDesc](#LoopMapByKeyGetterDesc)|按照键的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +|[LoopMapByValueGetterDesc](#LoopMapByValueGetterDesc)|按照值的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 |[MappingFromSlice](#MappingFromSlice)|将切片中的元素进行转换 |[MappingFromMap](#MappingFromMap)|将 map 中的元素进行转换 |[MergeSlices](#MergeSlices)|合并切片 @@ -491,6 +509,214 @@ func TestCloneMaps(t *testing.T) { +*** +#### func EqualSlice\[S ~[]V, V any\](slice1 S, slice2 S, handler ComparisonHandler[V]) bool + +> 检查两个切片是否相等,当 handler 返回 true 时,表示 slice1 中的某个元素和 slice2 中的某个元素相匹配 +> - 当两个切片的容量不同时,不会影响最终的比较结果 + +**示例代码:** + +```go + +func ExampleEqualSlice() { + s1 := []int{1, 2, 3} + s2 := []int{1} + s3 := []int{1, 2, 3} + fmt.Println(collection.EqualSlice(s1, s2, func(source, target int) bool { + return source == target + })) + fmt.Println(collection.EqualSlice(s1, s3, func(source, target int) bool { + return source == target + })) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestEqualSlice(t *testing.T) { + var cases = []struct { + name string + input []int + inputV []int + expected bool + }{{"TestEqualSlice_NonEmptySliceEqual", []int{1, 2, 3}, []int{1, 2, 3}, true}, {"TestEqualSlice_NonEmptySliceNotEqual", []int{1, 2, 3}, []int{1, 2}, false}, {"TestEqualSlice_EmptySlice", []int{}, []int{}, true}, {"TestEqualSlice_NilSlice", nil, nil, true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var actual = collection.EqualSlice(c.input, c.inputV, func(source, target int) bool { + return source == target + }) + if actual != c.expected { + t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "not as expected") + } + }) + } +} + +``` + + +
+ + +*** +#### func EqualComparableSlice\[S ~[]V, V comparable\](slice1 S, slice2 S) bool + +> 检查两个切片的值是否相同 +> - 当两个切片的容量不同时,不会影响最终的比较结果 + +**示例代码:** + +```go + +func ExampleEqualComparableSlice() { + s1 := []int{1, 2, 3} + s2 := []int{1} + s3 := []int{1, 2, 3} + fmt.Println(collection.EqualComparableSlice(s1, s2)) + fmt.Println(collection.EqualComparableSlice(s1, s3)) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestEqualComparableSlice(t *testing.T) { + var cases = []struct { + name string + input []int + inputV []int + expected bool + }{{"TestEqualComparableSlice_NonEmptySliceEqual", []int{1, 2, 3}, []int{1, 2, 3}, true}, {"TestEqualComparableSlice_NonEmptySliceNotEqual", []int{1, 2, 3}, []int{1, 2}, false}, {"TestEqualComparableSlice_EmptySlice", []int{}, []int{}, true}, {"TestEqualComparableSlice_NilSlice", nil, nil, true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var actual = collection.EqualComparableSlice(c.input, c.inputV) + if actual != c.expected { + t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "not as expected") + } + }) + } +} + +``` + + +
+ + +*** +#### func EqualMap\[M ~map[K]V, K comparable, V any\](map1 M, map2 M, handler ComparisonHandler[V]) bool + +> 检查两个 map 是否相等,当 handler 返回 true 时,表示 map1 中的某个元素和 map2 中的某个元素相匹配 +> - 当两个 map 的容量不同时,不会影响最终的比较结果 + +**示例代码:** + +```go + +func ExampleEqualMap() { + m1 := map[string]int{"a": 1, "b": 2} + m2 := map[string]int{"a": 1} + m3 := map[string]int{"a": 1, "b": 2} + fmt.Println(collection.EqualMap(m1, m2, func(source, target int) bool { + return source == target + })) + fmt.Println(collection.EqualMap(m1, m3, func(source, target int) bool { + return source == target + })) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestEqualMap(t *testing.T) { + var cases = []struct { + name string + input map[int]int + inputV map[int]int + expected bool + }{{"TestEqualMap_NonEmptyMapEqual", map[int]int{1: 1, 2: 2}, map[int]int{1: 1, 2: 2}, true}, {"TestEqualMap_NonEmptyMapNotEqual", map[int]int{1: 1, 2: 2}, map[int]int{1: 1}, false}, {"TestEqualMap_EmptyMap", map[int]int{}, map[int]int{}, true}, {"TestEqualMap_NilMap", nil, nil, true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var actual = collection.EqualMap(c.input, c.inputV, func(source, target int) bool { + return source == target + }) + if actual != c.expected { + t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "not as expected") + } + }) + } +} + +``` + + +
+ + +*** +#### func EqualComparableMap\[M ~map[K]V, K comparable, V comparable\](map1 M, map2 M) bool + +> 检查两个 map 的值是否相同 +> - 当两个 map 的容量不同时,不会影响最终的比较结果 + +**示例代码:** + +```go + +func ExampleEqualComparableMap() { + m1 := map[string]int{"a": 1, "b": 2} + m2 := map[string]int{"a": 1} + m3 := map[string]int{"a": 1, "b": 2} + fmt.Println(collection.EqualComparableMap(m1, m2)) + fmt.Println(collection.EqualComparableMap(m1, m3)) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestEqualComparableMap(t *testing.T) { + var cases = []struct { + name string + input map[int]int + inputV map[int]int + expected bool + }{{"TestEqualComparableMap_NonEmptyMapEqual", map[int]int{1: 1, 2: 2}, map[int]int{1: 1, 2: 2}, true}, {"TestEqualComparableMap_NonEmptyMapNotEqual", map[int]int{1: 1, 2: 2}, map[int]int{1: 1}, false}, {"TestEqualComparableMap_EmptyMap", map[int]int{}, map[int]int{}, true}, {"TestEqualComparableMap_NilMap", nil, nil, true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var actual = collection.EqualComparableMap(c.input, c.inputV) + if actual != c.expected { + t.Fatalf("%s failed, expected: %v, actual: %v, error: %s", c.name, c.expected, actual, "not as expected") + } + }) + } +} + +``` + + +
+ + *** #### func InSlice\[S ~[]V, V any\](slice S, v V, handler ComparisonHandler[V]) bool @@ -1813,6 +2039,158 @@ func TestAnyKeyInAllMaps(t *testing.T) { +*** +#### func ConvertSliceToBatches\[S ~[]V, V any\](s S, batchSize int) []S + +> 将切片 s 转换为分批次的切片,当 batchSize 小于等于 0 或者 s 长度为 0 时,将会返回 nil + +**示例代码:** + +```go + +func ExampleConvertSliceToBatches() { + result := collection.ConvertSliceToBatches([]int{1, 2, 3}, 2) + for _, v := range result { + fmt.Println(v) + } +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestConvertSliceToBatches(t *testing.T) { + var cases = []struct { + name string + input []int + batch int + expected [][]int + }{{name: "TestConvertSliceToBatches_NonEmpty", input: []int{1, 2, 3}, batch: 2, expected: [][]int{{1, 2}, {3}}}, {name: "TestConvertSliceToBatches_Empty", input: []int{}, batch: 2, expected: nil}, {name: "TestConvertSliceToBatches_Nil", input: nil, batch: 2, expected: nil}, {name: "TestConvertSliceToBatches_NonPositive", input: []int{1, 2, 3}, batch: 0, expected: nil}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + actual := collection.ConvertSliceToBatches(c.input, c.batch) + if len(actual) != len(c.expected) { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + for i := 0; i < len(actual); i++ { + av, ev := actual[i], c.expected[i] + if len(av) != len(ev) { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + for j := 0; j < len(av); j++ { + aj, ej := av[j], ev[j] + if reflect.TypeOf(aj).Kind() != reflect.TypeOf(ej).Kind() { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + if aj != ej { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + } + } + }) + } +} + +``` + + +
+ + +*** +#### func ConvertMapKeysToBatches\[M ~map[K]V, K comparable, V any\](m M, batchSize int) [][]K + +> 将映射的键转换为分批次的切片,当 batchSize 小于等于 0 或者 m 长度为 0 时,将会返回 nil + +**示例代码:** + +```go + +func ExampleConvertMapKeysToBatches() { + result := collection.ConvertMapKeysToBatches(map[int]int{1: 1, 2: 2, 3: 3}, 2) + fmt.Println(len(result)) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestConvertMapKeysToBatches(t *testing.T) { + var cases = []struct { + name string + input map[int]int + batch int + expected [][]int + }{{name: "TestConvertMapKeysToBatches_NonEmpty", input: map[int]int{1: 1, 2: 2, 3: 3}, batch: 2, expected: [][]int{{1, 2}, {3}}}, {name: "TestConvertMapKeysToBatches_Empty", input: map[int]int{}, batch: 2, expected: nil}, {name: "TestConvertMapKeysToBatches_Nil", input: nil, batch: 2, expected: nil}, {name: "TestConvertMapKeysToBatches_NonPositive", input: map[int]int{1: 1, 2: 2, 3: 3}, batch: 0, expected: nil}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + actual := collection.ConvertMapKeysToBatches(c.input, c.batch) + if len(actual) != len(c.expected) { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + }) + } +} + +``` + + +
+ + +*** +#### func ConvertMapValuesToBatches\[M ~map[K]V, K comparable, V any\](m M, batchSize int) [][]V + +> 将映射的值转换为分批次的切片,当 batchSize 小于等于 0 或者 m 长度为 0 时,将会返回 nil + +**示例代码:** + +```go + +func ExampleConvertMapValuesToBatches() { + result := collection.ConvertMapValuesToBatches(map[int]int{1: 1, 2: 2, 3: 3}, 2) + fmt.Println(len(result)) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestConvertMapValuesToBatches(t *testing.T) { + var cases = []struct { + name string + input map[int]int + batch int + expected [][]int + }{{name: "TestConvertMapValuesToBatches_NonEmpty", input: map[int]int{1: 1, 2: 2, 3: 3}, batch: 2, expected: [][]int{{1, 2}, {3}}}, {name: "TestConvertMapValuesToBatches_Empty", input: map[int]int{}, batch: 2, expected: nil}, {name: "TestConvertMapValuesToBatches_Nil", input: nil, batch: 2, expected: nil}, {name: "TestConvertMapValuesToBatches_NonPositive", input: map[int]int{1: 1, 2: 2, 3: 3}, batch: 0, expected: nil}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + actual := collection.ConvertMapValuesToBatches(c.input, c.batch) + if len(actual) != len(c.expected) { + t.Errorf("expected: %v, actual: %v", c.expected, actual) + } + }) + } +} + +``` + + +
+ + *** #### func ConvertSliceToAny\[S ~[]V, V any\](s S) []any @@ -2090,6 +2468,7 @@ func TestConvertSliceToBoolMap(t *testing.T) { func ExampleConvertMapKeysToSlice() { result := collection.ConvertMapKeysToSlice(map[int]int{1: 1, 2: 2, 3: 3}) + sort.Ints(result) for i, v := range result { fmt.Println(i, v) } @@ -4273,6 +4652,669 @@ func TestSwapSlice(t *testing.T) { +*** +#### func LoopSlice\[S ~[]V, V any\](slice S, f func (i int, val V) bool) + +> 迭代切片 slice 中的每一个函数,并将索引和值传递给 f 函数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopSlice() { + var result []int + collection.LoopSlice([]int{1, 2, 3, 4, 5}, func(i int, val int) bool { + result = append(result, val) + if uint(i) == 1 { + return false + } + return true + }) + fmt.Println(result) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopSlice(t *testing.T) { + var cases = []struct { + name string + in []int + out []int + breakIndex uint + }{{"TestLoopSlice_Part", []int{1, 2, 3, 4, 5}, []int{1, 2}, 2}, {"TestLoopSlice_All", []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}, 0}, {"TestLoopSlice_Empty", []int{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.LoopSlice(c.in, func(i int, val int) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopSlice(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func ReverseLoopSlice\[S ~[]V, V any\](slice S, f func (i int, val V) bool) + +> 逆序迭代切片 slice 中的每一个函数,并将索引和值传递给 f 函数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleReverseLoopSlice() { + var result []int + collection.ReverseLoopSlice([]int{1, 2, 3, 4, 5}, func(i int, val int) bool { + result = append(result, val) + if uint(i) == 1 { + return false + } + return true + }) + fmt.Println(result) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestReverseLoopSlice(t *testing.T) { + var cases = []struct { + name string + in []int + out []int + breakIndex uint + }{{"TestReverseLoopSlice_Part", []int{1, 2, 3, 4, 5}, []int{5, 4}, 2}, {"TestReverseLoopSlice_All", []int{1, 2, 3, 4, 5}, []int{5, 4, 3, 2, 1}, 0}, {"TestReverseLoopSlice_Empty", []int{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.ReverseLoopSlice(c.in, func(i int, val int) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == uint(len(c.in))-c.breakIndex { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("ReverseLoopSlice(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMap\[M ~map[K]V, K comparable, V any\](m M, f func (i int, key K, val V) bool) + +> 迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - m 的迭代顺序是不确定的,因此每次迭代的顺序可能不同 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMap() { + var result []int + collection.LoopMap(map[string]int{"a": 1, "b": 2, "c": 3}, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{1, 2, 3})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMap(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out map[int]string + breakIndex uint + }{{"TestLoopMap_Part", map[int]string{1: "1", 2: "2", 3: "3"}, map[int]string{1: "1", 2: "2"}, 2}, {"TestLoopMap_All", map[int]string{1: "1", 2: "2", 3: "3"}, map[int]string{1: "1", 2: "2", 3: "3"}, 0}, {"TestLoopMap_Empty", map[int]string{}, map[int]string{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result = make(map[int]string) + collection.LoopMap(c.in, func(i int, key int, val string) bool { + result[key] = val + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableMap(result, c.out) { + t.Errorf("LoopMap(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByOrderedKeyAsc\[M ~map[K]V, K generic.Ordered, V any\](m M, f func (i int, key K, val V) bool) + +> 按照键的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByOrderedKeyAsc() { + var result []int + collection.LoopMapByOrderedKeyAsc(map[string]int{"a": 1, "b": 2, "c": 3}, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{1, 2, 3})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByOrderedKeyAsc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []int + breakIndex uint + }{{"TestLoopMapByOrderedKeyAsc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []int{1, 2}, 2}, {"TestLoopMapByOrderedKeyAsc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []int{1, 2, 3}, 0}, {"TestLoopMapByOrderedKeyAsc_Empty", map[int]string{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.LoopMapByOrderedKeyAsc(c.in, func(i int, key int, val string) bool { + result = append(result, key) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByOrderedKeyAsc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByOrderedKeyDesc\[M ~map[K]V, K generic.Ordered, V any\](m M, f func (i int, key K, val V) bool) + +> 按照键的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByOrderedKeyDesc() { + var result []int + collection.LoopMapByOrderedKeyDesc(map[string]int{"a": 1, "b": 2, "c": 3}, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{3, 2, 1})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByOrderedKeyDesc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []int + breakIndex uint + }{{"TestLoopMapByOrderedKeyDesc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []int{3, 2}, 2}, {"TestLoopMapByOrderedKeyDesc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []int{3, 2, 1}, 0}, {"TestLoopMapByOrderedKeyDesc_Empty", map[int]string{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.LoopMapByOrderedKeyDesc(c.in, func(i int, key int, val string) bool { + result = append(result, key) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByOrderedKeyDesc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByOrderedValueAsc\[M ~map[K]V, K comparable, V generic.Ordered\](m M, f func (i int, key K, val V) bool) + +> 按照值的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByOrderedValueAsc() { + var result []int + collection.LoopMapByOrderedValueAsc(map[string]int{"a": 1, "b": 2, "c": 3}, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{1, 2, 3})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByOrderedValueAsc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []string + breakIndex uint + }{{"TestLoopMapByOrderedValueAsc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"1", "2"}, 2}, {"TestLoopMapByOrderedValueAsc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"1", "2", "3"}, 0}, {"TestLoopMapByOrderedValueAsc_Empty", map[int]string{}, []string{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []string + collection.LoopMapByOrderedValueAsc(c.in, func(i int, key int, val string) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByOrderedValueAsc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByOrderedValueDesc\[M ~map[K]V, K comparable, V generic.Ordered\](m M, f func (i int, key K, val V) bool) + +> 按照值的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByOrderedValueDesc() { + var result []int + collection.LoopMapByOrderedValueDesc(map[string]int{"a": 1, "b": 2, "c": 3}, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{3, 2, 1})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByOrderedValueDesc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []string + breakIndex uint + }{{"TestLoopMapByOrderedValueDesc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"3", "2"}, 2}, {"TestLoopMapByOrderedValueDesc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"3", "2", "1"}, 0}, {"TestLoopMapByOrderedValueDesc_Empty", map[int]string{}, []string{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []string + collection.LoopMapByOrderedValueDesc(c.in, func(i int, key int, val string) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByOrderedValueDesc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByKeyGetterAsc\[M ~map[K]V, K comparable, V comparable, N generic.Ordered\](m M, getter func (k K) N, f func (i int, key K, val V) bool) + +> 按照键的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByKeyGetterAsc() { + var m = map[string]int{"a": 1, "b": 2, "c": 3} + var result []int + collection.LoopMapByKeyGetterAsc(m, func(k string) int { + return m[k] + }, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{1, 2, 3})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByKeyGetterAsc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []int + breakIndex uint + }{{"TestLoopMapByKeyGetterAsc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []int{1, 2}, 2}, {"TestLoopMapByKeyGetterAsc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []int{1, 2, 3}, 0}, {"TestLoopMapByKeyGetterAsc_Empty", map[int]string{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.LoopMapByKeyGetterAsc(c.in, func(key int) int { + return key + }, func(i int, key int, val string) bool { + result = append(result, key) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByKeyGetterAsc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByValueGetterAsc\[M ~map[K]V, K comparable, V any, N generic.Ordered\](m M, getter func (v V) N, f func (i int, key K, val V) bool) + +> 按照值的升序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByValueGetterAsc() { + var m = map[string]int{"a": 1, "b": 2, "c": 3} + var result []int + collection.LoopMapByValueGetterAsc(m, func(v int) int { + return v + }, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{1, 2, 3})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByValueGetterAsc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []string + breakIndex uint + }{{"TestLoopMapByValueGetterAsc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"1", "2"}, 2}, {"TestLoopMapByValueGetterAsc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"1", "2", "3"}, 0}, {"TestLoopMapByValueGetterAsc_Empty", map[int]string{}, []string{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []string + collection.LoopMapByValueGetterAsc(c.in, func(val string) string { + return val + }, func(i int, key int, val string) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByValueGetterAsc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByKeyGetterDesc\[M ~map[K]V, K comparable, V comparable, N generic.Ordered\](m M, getter func (k K) N, f func (i int, key K, val V) bool) + +> 按照键的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByKeyGetterDesc() { + var m = map[string]int{"a": 1, "b": 2, "c": 3} + var result []int + collection.LoopMapByKeyGetterDesc(m, func(k string) int { + return m[k] + }, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{3, 2, 1})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByKeyGetterDesc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []int + breakIndex uint + }{{"TestLoopMapByKeyGetterDesc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []int{3, 2}, 2}, {"TestLoopMapByKeyGetterDesc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []int{3, 2, 1}, 0}, {"TestLoopMapByKeyGetterDesc_Empty", map[int]string{}, []int{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []int + collection.LoopMapByKeyGetterDesc(c.in, func(key int) int { + return key + }, func(i int, key int, val string) bool { + result = append(result, key) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByKeyGetterDesc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + +*** +#### func LoopMapByValueGetterDesc\[M ~map[K]V, K comparable, V any, N generic.Ordered\](m M, getter func (v V) N, f func (i int, key K, val V) bool) + +> 按照值的降序迭代 m 中的每一个函数,并将键和值传递给 f 函数 +> - 该函数会在 f 中传入一个从 0 开始的索引,用于表示当前迭代的次数 +> - 迭代过程将在 f 函数返回 false 时中断 + +**示例代码:** + +```go + +func ExampleLoopMapByValueGetterDesc() { + var m = map[string]int{"a": 1, "b": 2, "c": 3} + var result []int + collection.LoopMapByValueGetterDesc(m, func(v int) int { + return v + }, func(i int, key string, val int) bool { + result = append(result, val) + return true + }) + fmt.Println(collection.AllInComparableSlice(result, []int{3, 2, 1})) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestLoopMapByValueGetterDesc(t *testing.T) { + var cases = []struct { + name string + in map[int]string + out []string + breakIndex uint + }{{"TestLoopMapByValueGetterDesc_Part", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"3", "2"}, 2}, {"TestLoopMapByValueGetterDesc_All", map[int]string{1: "1", 2: "2", 3: "3"}, []string{"3", "2", "1"}, 0}, {"TestLoopMapByValueGetterDesc_Empty", map[int]string{}, []string{}, 0}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var result []string + collection.LoopMapByValueGetterDesc(c.in, func(val string) string { + return val + }, func(i int, key int, val string) bool { + result = append(result, val) + if c.breakIndex != 0 && uint(i) == c.breakIndex-1 { + return false + } + return true + }) + if !collection.EqualComparableSlice(result, c.out) { + t.Errorf("LoopMapByValueGetterDesc(%v) got %v, want %v", c.in, result, c.out) + } + }) + } +} + +``` + + +
+ + *** #### func MappingFromSlice\[S ~[]V, NS []N, V any, N any\](slice S, handler func (value V) N) NS diff --git a/utils/huge/README.md b/utils/huge/README.md index c79ece4..627fcaa 100644 --- a/utils/huge/README.md +++ b/utils/huge/README.md @@ -18,8 +18,7 @@ |:--|:-- |[NewFloat](#NewFloat)|创建一个 Float |[NewFloatByString](#NewFloatByString)|通过字符串创建一个 Float -|[NewInt](#NewInt)|创建一个 Int -|[NewIntByString](#NewIntByString)|通过字符串创建一个 Int +|[NewInt](#NewInt)|创建一个 Int 对象,该对象的值为 x > 类型定义 @@ -45,15 +44,88 @@ > - 如果字符串不是一个合法的数字,则返回 0 *** -#### func NewInt\[T generic.Number\](x T) *Int +#### func NewInt\[T generic.Basic\](x T) *Int -> 创建一个 Int +> 创建一个 Int 对象,该对象的值为 x + +**示例代码:** + +该案例展示了 NewInt 对各种基本类型的支持及用法 + + +```go + +func ExampleNewInt() { + fmt.Println(huge.NewInt("12345678900000000")) + fmt.Println(huge.NewInt(1234567890)) + fmt.Println(huge.NewInt(true)) + fmt.Println(huge.NewInt(123.123)) + fmt.Println(huge.NewInt(byte(1))) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestNewInt(t *testing.T) { + var cases = []struct { + name string + nil bool + in int64 + mul int64 + want string + }{{name: "TestNewIntNegative", in: -1, want: "-1"}, {name: "TestNewIntZero", in: 0, want: "0"}, {name: "TestNewIntPositive", in: 1, want: "1"}, {name: "TestNewIntMax", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestNewIntMin", in: -9223372036854775808, want: "-9223372036854775808"}, {name: "TestNewIntMulNegative", in: -9223372036854775808, mul: 10000000, want: "-92233720368547758080000000"}, {name: "TestNewIntMulPositive", in: 9223372036854775807, mul: 10000000, want: "92233720368547758070000000"}, {name: "TestNewIntNil", nil: true, want: "0"}, {name: "TestNewIntNilMul", nil: true, mul: 10000000, want: "0"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var got *huge.Int + switch { + case c.nil: + if c.mul > 0 { + got = huge.NewInt(0).MulInt64(c.mul) + } + case c.mul == 0: + got = huge.NewInt(c.in) + default: + got = huge.NewInt(c.in).MulInt64(c.mul) + } + if s := got.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, got.String()) + } else { + t.Log(s) + } + }) + } + t.Run("TestNewIntFromString", func(t *testing.T) { + if got := huge.NewInt("1234567890123456789012345678901234567890"); got.String() != "1234567890123456789012345678901234567890" { + t.Fatalf("want: %s, got: %s", "1234567890123456789012345678901234567890", got.String()) + } + }) + t.Run("TestNewIntFromInt", func(t *testing.T) { + if got := huge.NewInt(1234567890); got.String() != "1234567890" { + t.Fatalf("want: %s, got: %s", "1234567890", got.String()) + } + }) + t.Run("TestNewIntFromBool", func(t *testing.T) { + if got := huge.NewInt(true); got.String() != "1" { + t.Fatalf("want: %s, got: %s", "1", got.String()) + } + }) + t.Run("TestNewIntFromFloat", func(t *testing.T) { + if got := huge.NewInt(1234567890.1234567890); got.String() != "1234567890" { + t.Fatalf("want: %s, got: %s", "1234567890", got.String()) + } + }) +} + +``` + + +
-*** -#### func NewIntByString(i string) *Int - -> 通过字符串创建一个 Int -> - 如果字符串不是一个合法的数字,则返回 0 *** @@ -190,71 +262,689 @@ type Int big.Int #### func (*Int) Copy() *Int +> 拷贝当前 Int 对象 + +**示例代码:** + +```go + +func ExampleInt_Copy() { + var a = huge.NewInt(1234567890) + var b = a.Copy().SetInt64(9876543210) + fmt.Println(a) + fmt.Println(b) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestInt_Copy(t *testing.T) { + var cases = []struct { + name string + in int64 + want string + }{{name: "TestIntCopyNegative", in: -1, want: "-1"}, {name: "TestIntCopyZero", in: 0, want: "0"}, {name: "TestIntCopyPositive", in: 1, want: "1"}, {name: "TestIntCopyMax", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntCopyMin", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in = huge.NewInt(c.in) + var got = in.Copy() + if in.Int64() != c.in { + t.Fatalf("want: %d, got: %d", c.in, in.Int64()) + } + if s := got.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, got.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) Set(i *Int) *Int +> 设置当前 Int 对象的值为 i + +**示例代码:** + +```go + +func ExampleInt_Set() { + var a = huge.NewInt(1234567890) + var b = huge.NewInt(9876543210) + fmt.Println(a) + a.Set(b) + fmt.Println(a) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestInt_Set(t *testing.T) { + var cases = []struct { + name string + in int64 + want string + }{{name: "TestIntSetNegative", in: -1, want: "-1"}, {name: "TestIntSetZero", in: 0, want: "0"}, {name: "TestIntSetPositive", in: 1, want: "1"}, {name: "TestIntSetMax", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntSetMin", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.Set(huge.NewInt(c.in)) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ + +*** + + +#### func (*Int) SetString(i string) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetString(t *testing.T) { + var cases = []struct { + name string + in string + want string + }{{name: "TestIntSetStringNegative", in: "-1", want: "-1"}, {name: "TestIntSetStringZero", in: "0", want: "0"}, {name: "TestIntSetStringPositive", in: "1", want: "1"}, {name: "TestIntSetStringMax", in: "9223372036854775807", want: "9223372036854775807"}, {name: "TestIntSetStringMin", in: "-9223372036854775808", want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetString(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetInt(i int) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetInt(t *testing.T) { + var cases = []struct { + name string + in int64 + want string + }{{name: "TestIntSetIntNegative", in: -1, want: "-1"}, {name: "TestIntSetIntZero", in: 0, want: "0"}, {name: "TestIntSetIntPositive", in: 1, want: "1"}, {name: "TestIntSetIntMax", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntSetIntMin", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetInt64(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetInt8(i int8) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetInt8(t *testing.T) { + var cases = []struct { + name string + in int8 + want string + }{{name: "TestIntSetInt8Negative", in: -1, want: "-1"}, {name: "TestIntSetInt8Zero", in: 0, want: "0"}, {name: "TestIntSetInt8Positive", in: 1, want: "1"}, {name: "TestIntSetInt8Max", in: 127, want: "127"}, {name: "TestIntSetInt8Min", in: -128, want: "-128"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetInt8(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetInt16(i int16) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetInt16(t *testing.T) { + var cases = []struct { + name string + in int16 + want string + }{{name: "TestIntSetInt16Negative", in: -1, want: "-1"}, {name: "TestIntSetInt16Zero", in: 0, want: "0"}, {name: "TestIntSetInt16Positive", in: 1, want: "1"}, {name: "TestIntSetInt16Max", in: 32767, want: "32767"}, {name: "TestIntSetInt16Min", in: -32768, want: "-32768"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetInt16(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetInt32(i int32) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetInt32(t *testing.T) { + var cases = []struct { + name string + in int32 + want string + }{{name: "TestIntSetInt32Negative", in: -1, want: "-1"}, {name: "TestIntSetInt32Zero", in: 0, want: "0"}, {name: "TestIntSetInt32Positive", in: 1, want: "1"}, {name: "TestIntSetInt32Max", in: 2147483647, want: "2147483647"}, {name: "TestIntSetInt32Min", in: -2147483648, want: "-2147483648"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetInt32(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetInt64(i int64) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetInt64(t *testing.T) { + var cases = []struct { + name string + in int64 + want string + }{{name: "TestIntSetInt64Negative", in: -1, want: "-1"}, {name: "TestIntSetInt64Zero", in: 0, want: "0"}, {name: "TestIntSetInt64Positive", in: 1, want: "1"}, {name: "TestIntSetInt64Max", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntSetInt64Min", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetInt64(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetUint(i uint) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetUint(t *testing.T) { + var cases = []struct { + name string + in uint64 + want string + }{{name: "TestIntSetUintNegative", in: 0, want: "0"}, {name: "TestIntSetUintZero", in: 0, want: "0"}, {name: "TestIntSetUintPositive", in: 1, want: "1"}, {name: "TestIntSetUintMax", in: 18446744073709551615, want: "18446744073709551615"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetUint64(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetUint8(i uint8) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetUint8(t *testing.T) { + var cases = []struct { + name string + in uint8 + want string + }{{name: "TestIntSetUint8Negative", in: 0, want: "0"}, {name: "TestIntSetUint8Zero", in: 0, want: "0"}, {name: "TestIntSetUint8Positive", in: 1, want: "1"}, {name: "TestIntSetUint8Max", in: 255, want: "255"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetUint8(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetUint16(i uint16) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetUint16(t *testing.T) { + var cases = []struct { + name string + in uint16 + want string + }{{name: "TestIntSetUint16Negative", in: 0, want: "0"}, {name: "TestIntSetUint16Zero", in: 0, want: "0"}, {name: "TestIntSetUint16Positive", in: 1, want: "1"}, {name: "TestIntSetUint16Max", in: 65535, want: "65535"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetUint16(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetUint32(i uint32) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetUint32(t *testing.T) { + var cases = []struct { + name string + in uint32 + want string + }{{name: "TestIntSetUint32Negative", in: 0, want: "0"}, {name: "TestIntSetUint32Zero", in: 0, want: "0"}, {name: "TestIntSetUint32Positive", in: 1, want: "1"}, {name: "TestIntSetUint32Max", in: 4294967295, want: "4294967295"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetUint32(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) SetUint64(i uint64) *Int +> 设置当前 Int 对象的值为 i + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetUint64(t *testing.T) { + var cases = []struct { + name string + in uint64 + want string + }{{name: "TestIntSetUint64Negative", in: 0, want: "0"}, {name: "TestIntSetUint64Zero", in: 0, want: "0"}, {name: "TestIntSetUint64Positive", in: 1, want: "1"}, {name: "TestIntSetUint64Max", in: 18446744073709551615, want: "18446744073709551615"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetUint64(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ + +*** + + +#### func (*Int) SetFloat32(i float32) *Int +> 设置当前 Int 对象的值为 i 向下取整后的值 + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetFloat32(t *testing.T) { + var cases = []struct { + name string + in float32 + want string + }{{name: "TestIntSetFloat32Negative", in: -1.1, want: "-1"}, {name: "TestIntSetFloat32Zero", in: 0, want: "0"}, {name: "TestIntSetFloat32Positive", in: 1.1, want: "1"}, {name: "TestIntSetFloat32Max", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntSetFloat32Min", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetFloat32(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ + +*** + + +#### func (*Int) SetFloat64(i float64) *Int +> 设置当前 Int 对象的值为 i 向下取整后的值 + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetFloat64(t *testing.T) { + var cases = []struct { + name string + in float64 + want string + }{{name: "TestIntSetFloat64Negative", in: -1.1, want: "-1"}, {name: "TestIntSetFloat64Zero", in: 0, want: "0"}, {name: "TestIntSetFloat64Positive", in: 1.1, want: "1"}, {name: "TestIntSetFloat64Max", in: 9223372036854775807, want: "9223372036854775807"}, {name: "TestIntSetFloat64Min", in: -9223372036854775808, want: "-9223372036854775808"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetFloat64(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ + +*** + + +#### func (*Int) SetBool(i bool) *Int +> 设置当前 Int 对象的值为 i,当 i 为 true 时,值为 1,当 i 为 false 时,值为 0 + +
+查看 / 收起单元测试 + + +```go + +func TestInt_SetBool(t *testing.T) { + var cases = []struct { + name string + in bool + want string + }{{name: "TestIntSetBoolFalse", in: false, want: "0"}, {name: "TestIntSetBoolTrue", in: true, want: "1"}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var in *huge.Int + in = in.SetBool(c.in) + if s := in.String(); s != c.want { + t.Fatalf("want: %s, got: %s", c.want, in.String()) + } else { + t.Log(s) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) IsZero() bool +> 判断当前 Int 对象的值是否为 0 + +
+查看 / 收起单元测试 + + +```go + +func TestInt_IsZero(t *testing.T) { + var cases = []struct { + name string + in int64 + want bool + }{{name: "TestIntIsZeroNegative", in: -1, want: false}, {name: "TestIntIsZeroZero", in: 0, want: true}, {name: "TestIntIsZeroPositive", in: 1, want: false}, {name: "TestIntIsZeroMax", in: 9223372036854775807, want: false}, {name: "TestIntIsZeroMin", in: -9223372036854775808, want: false}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + if got := huge.NewInt(c.in).IsZero(); got != c.want { + t.Fatalf("want: %t, got: %t", c.want, got) + } + }) + } +} + +``` + + +
+ *** #### func (*Int) ToBigint() *big.Int +> 转换为 *big.Int + +
+查看 / 收起单元测试 + + +```go + +func TestInt_ToBigint(t *testing.T) { + var cases = []struct { + name string + in int64 + want *big.Int + }{{name: "TestIntToBigintNegative", in: -1, want: big.NewInt(-1)}, {name: "TestIntToBigintZero", in: 0, want: big.NewInt(0)}, {name: "TestIntToBigintPositive", in: 1, want: big.NewInt(1)}, {name: "TestIntToBigintMax", in: 9223372036854775807, want: big.NewInt(9223372036854775807)}, {name: "TestIntToBigintMin", in: -9223372036854775808, want: big.NewInt(-9223372036854775808)}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + if got := huge.NewInt(c.in).ToBigint(); got.Cmp(c.want) != 0 { + t.Fatalf("want: %s, got: %s", c.want.String(), got.String()) + } + }) + } +} + +``` + + +
+ *** @@ -266,46 +956,49 @@ type Int big.Int #### func (*Int) GreaterThan(i *Int) bool -> 大于 +> 检查 slf 是否大于 i *** #### func (*Int) GreaterThanOrEqualTo(i *Int) bool -> 大于或等于 +> 检查 slf 是否大于或等于 i *** #### func (*Int) LessThan(i *Int) bool -> 小于 +> 检查 slf 是否小于 i *** #### func (*Int) LessThanOrEqualTo(i *Int) bool -> 小于或等于 +> 检查 slf 是否小于或等于 i *** #### func (*Int) EqualTo(i *Int) bool -> 等于 +> 检查 slf 是否等于 i *** #### func (*Int) Int64() int64 +> 转换为 int64 类型进行返回 *** #### func (*Int) String() string +> 转换为 string 类型进行返回 *** #### func (*Int) Add(i *Int) *Int +> 使用 i 对 slf 进行加法运算,slf 的值会变为运算后的值。返回 slf *** diff --git a/utils/super/README.md b/utils/super/README.md index b0f1093..8b40832 100644 --- a/utils/super/README.md +++ b/utils/super/README.md @@ -19,6 +19,8 @@ |[NewBitSet](#NewBitSet)|通过指定的 Bit 位创建一个 BitSet |[TryWriteChannel](#TryWriteChannel)|尝试写入 channel,如果 channel 无法写入则忽略,返回是否写入成功 |[TryWriteChannelByHandler](#TryWriteChannelByHandler)|尝试写入 channel,如果 channel 无法写入则执行 handler +|[TryReadChannel](#TryReadChannel)|尝试读取 channel,如果 channel 无法读取则忽略,返回是否读取成功 +|[TryReadChannelByHandler](#TryReadChannelByHandler)|尝试读取 channel,如果 channel 无法读取则执行 handler |[RegError](#RegError)|通过错误码注册错误,返回错误的引用 |[RegErrorRef](#RegErrorRef)|通过错误码注册错误,返回错误的引用 |[GetError](#GetError)|通过错误引用获取错误码和真实错误信息,如果错误不存在则返回 0,如果错误引用不存在则返回原本的错误 @@ -107,6 +109,50 @@ #### func NewBitSet\[Bit generic.Integer\](bits ...Bit) *BitSet[Bit] > 通过指定的 Bit 位创建一个 BitSet +> - 当指定的 Bit 位存在负数时,将会 panic + +**示例代码:** + +```go + +func ExampleNewBitSet() { + var bs = super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9) + bs.Set(10) + fmt.Println(bs.Bits()) +} + +``` + +
+查看 / 收起单元测试 + + +```go + +func TestNewBitSet(t *testing.T) { + var cases = []struct { + name string + in []int + shouldPanic bool + }{{name: "normal", in: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}}, {name: "empty", in: make([]int, 0)}, {name: "nil", in: nil}, {name: "negative", in: []int{-1, -2}, shouldPanic: true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil && !c.shouldPanic { + t.Fatalf("panic: %v", r) + } + }() + bs := super.NewBitSet(c.in...) + t.Log(bs) + }) + } +} + +``` + + +
+ *** #### func TryWriteChannel\[T any\](ch chan T, data T) bool @@ -120,6 +166,18 @@ > 尝试写入 channel,如果 channel 无法写入则执行 handler > - 无法写入的情况包括:channel 已满、channel 已关闭 +*** +#### func TryReadChannel\[T any\](ch chan T) (v T, suc bool) + +> 尝试读取 channel,如果 channel 无法读取则忽略,返回是否读取成功 +> - 无法读取的情况包括:channel 已空、channel 已关闭 + +*** +#### func TryReadChannelByHandler\[T any\](ch chan T, handler func (ch chan T) T) (v T) + +> 尝试读取 channel,如果 channel 无法读取则执行 handler +> - 无法读取的情况包括:channel 已空、channel 已关闭 + *** #### func RegError(code int, message string) error @@ -757,6 +815,18 @@ type BitSet[Bit generic.Integer] struct { #### func (*BitSet) Set(bit Bit) *BitSet[Bit] > 将指定的位 bit 设置为 1 +**示例代码:** + +```go + +func ExampleBitSet_Set() { + var bs = super.NewBitSet[int]() + bs.Set(10) + fmt.Println(bs.Bits()) +} + +``` +
查看 / 收起单元测试 @@ -764,11 +834,29 @@ type BitSet[Bit generic.Integer] struct { ```go func TestBitSet_Set(t *testing.T) { - bs := super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - bs.Set(11) - bs.Set(12) - bs.Set(13) - t.Log(bs) + var cases = []struct { + name string + in []int + shouldPanic bool + }{{name: "normal", in: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}}, {name: "empty", in: make([]int, 0)}, {name: "nil", in: nil}, {name: "negative", in: []int{-1, -2}, shouldPanic: true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil && !c.shouldPanic { + t.Fatalf("panic: %v", r) + } + }() + bs := super.NewBitSet[int]() + for _, bit := range c.in { + bs.Set(bit) + } + for _, bit := range c.in { + if !bs.Has(bit) { + t.Fatalf("bit %v not set", bit) + } + } + }) + } } ``` @@ -783,6 +871,18 @@ func TestBitSet_Set(t *testing.T) { #### func (*BitSet) Del(bit Bit) *BitSet[Bit] > 将指定的位 bit 设置为 0 +**示例代码:** + +```go + +func ExampleBitSet_Del() { + var bs = super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9) + bs.Del(1) + fmt.Println(bs.Bits()) +} + +``` +
查看 / 收起单元测试 @@ -790,12 +890,32 @@ func TestBitSet_Set(t *testing.T) { ```go func TestBitSet_Del(t *testing.T) { - bs := super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - bs.Del(11) - bs.Del(12) - bs.Del(13) - bs.Del(10) - t.Log(bs) + var cases = []struct { + name string + in []int + shouldPanic bool + }{{name: "normal", in: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}}, {name: "empty", in: make([]int, 0)}, {name: "nil", in: nil}, {name: "negative", in: []int{-1, -2}, shouldPanic: true}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil && !c.shouldPanic { + t.Fatalf("panic: %v", r) + } + }() + bs := super.NewBitSet[int]() + for _, bit := range c.in { + bs.Set(bit) + } + for _, bit := range c.in { + bs.Del(bit) + } + for _, bit := range c.in { + if bs.Has(bit) { + t.Fatalf("bit %v not del", bit) + } + } + }) + } } ``` @@ -811,6 +931,21 @@ func TestBitSet_Del(t *testing.T) { > 将 BitSet 中的比特位集合缩小到最小 > - 正常情况下当 BitSet 中的比特位超出 64 位时,将自动增长,当 BitSet 中的比特位数量减少时,可以使用该方法将 BitSet 中的比特位集合缩小到最小 +**示例代码:** + +```go + +func ExampleBitSet_Shrink() { + var bs = super.NewBitSet(111, 222, 333, 444) + fmt.Println(bs.Cap()) + bs.Del(444) + fmt.Println(bs.Cap()) + bs.Shrink() + fmt.Println(bs.Cap()) +} + +``` +
查看 / 收起单元测试 @@ -818,13 +953,22 @@ func TestBitSet_Del(t *testing.T) { ```go func TestBitSet_Shrink(t *testing.T) { - bs := super.NewBitSet(63) - t.Log(bs.Cap()) - bs.Set(200) - t.Log(bs.Cap()) - bs.Del(200) - bs.Shrink() - t.Log(bs.Cap()) + var cases = []struct { + name string + in []int + }{{name: "normal", in: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}}, {name: "empty", in: make([]int, 0)}, {name: "nil", in: nil}} + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + bs := super.NewBitSet(c.in...) + for _, v := range c.in { + bs.Del(v) + } + bs.Shrink() + if bs.Cap() != 0 { + t.Fatalf("cap %v != 0", bs.Cap()) + } + }) + } } ``` @@ -839,24 +983,70 @@ func TestBitSet_Shrink(t *testing.T) { #### func (*BitSet) Cap() int > 返回当前 BitSet 中可以表示的最大比特位数量 +**示例代码:** + +```go + +func ExampleBitSet_Cap() { + var bs = super.NewBitSet(63) + fmt.Println(bs.Cap()) +} + +``` + *** #### func (*BitSet) Has(bit Bit) bool > 检查指定的位 bit 是否被设置为 1 +**示例代码:** + +```go + +func ExampleBitSet_Has() { + var bs = super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9) + fmt.Println(bs.Has(1)) + fmt.Println(bs.Has(10)) +} + +``` + *** #### func (*BitSet) Clear() *BitSet[Bit] > 清空所有的比特位 +**示例代码:** + +```go + +func ExampleBitSet_Clear() { + var bs = super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9) + bs.Clear() + fmt.Println(bs.Bits()) +} + +``` + *** #### func (*BitSet) Len() int > 返回当前 BitSet 中被设置的比特位数量 +**示例代码:** + +```go + +func ExampleBitSet_Len() { + var bs = super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9) + fmt.Println(bs.Len()) +} + +``` + ***