1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

108 Commits

Author SHA1 Message Date
dudaodong
66efe61834 release v2.1.16 2023-03-01 10:08:53 +08:00
dudaodong
94f7f3e0e5 doc: add new function docs 2023-02-28 15:03:02 +08:00
dudaodong
9d2c9806d1 feat: add ContainBy function 2023-02-24 14:19:10 +08:00
dudaodong
e523d4af6e doc: add doc for FilterMap and FlatMap 2023-02-24 11:23:02 +08:00
dudaodong
f3801bcd8f feat: add FlatMap 2023-02-24 11:14:59 +08:00
dudaodong
5767aad303 feat: add FilterMap 2023-02-24 10:55:27 +08:00
dudaodong
f7aaa1ed2a fix: fix issue #75 2023-02-23 11:43:41 +08:00
dudaodong
ef19a414bc doc: fix doc error 2023-02-23 10:58:43 +08:00
dudaodong
65704dea06 doc: fix doc error 2023-02-23 10:57:48 +08:00
dudaodong
5eac358bb0 doc: format code in doc file 2023-02-22 17:00:46 +08:00
dudaodong
8e36ef5cef doc: add doc for new map functions 2023-02-22 16:59:01 +08:00
dudaodong
21b0d2ec0e doc: add doc for WordCount and SplitWords function 2023-02-22 16:13:41 +08:00
dudaodong
32ca975204 feat: add OmitBy, OmitByKeys, OmitByValues 2023-02-21 14:52:10 +08:00
dudaodong
ec740e442c feat: add WordCount 2023-02-21 14:27:00 +08:00
dudaodong
ed98ad53ec feat: add SplitWords 2023-02-21 14:16:36 +08:00
dudaodong
af7b9d2710 doc: add doc for CopyProperties function 2023-02-20 14:10:55 +08:00
dudaodong
f08b368001 fix: update param type of CopyProperties 2023-02-20 14:04:45 +08:00
dudaodong
be8a0558f8 test: add examples for CopyProperties function 2023-02-20 12:00:49 +08:00
dudaodong
46de539e22 feat: add CopyProperties for merge properties between structs 2023-02-20 11:48:30 +08:00
dudaodong
36fb3abe9e test: add examples for maputil package function 2023-02-19 16:59:21 +08:00
dudaodong
fee8d325b7 doc: add doc for Pad function 2023-02-19 12:58:14 +08:00
dudaodong
8784be1583 feat: add Pad function 2023-02-19 12:37:26 +08:00
dudaodong
84cd68de7f fix: fix bugs of PadEnd and PadStart 2023-02-19 12:34:39 +08:00
dudaodong
a774c060ce feat: add MapKeys and MapValues 2023-02-17 15:41:58 +08:00
dudaodong
730f061b95 feat: add Entries FromEntries Transform 2023-02-17 15:24:46 +08:00
dudaodong
2eb08f3404 feat: add FilterByValues function 2023-02-17 11:59:44 +08:00
dudaodong
4c1496b648 feat: add FilterByKeys function 2023-02-17 11:57:09 +08:00
dudaodong
c2ae784f27 feat: add ValuesBy function 2023-02-17 11:48:11 +08:00
dudaodong
e71cecefea feat: add KeysBy function 2023-02-17 11:40:20 +08:00
dudaodong
572e53aa14 doc: add go playground demo for xerror package 2023-02-16 14:28:50 +08:00
dudaodong
ca9ecb9c8a update go playground demo 2023-02-16 14:10:24 +08:00
dudaodong
8bf0786abe release v2.1.15 2023-02-16 12:02:34 +08:00
dudaodong
61cb8395e3 doc: update doc for xerror package 2023-02-15 14:41:56 +08:00
dudaodong
dde8a41daf doc: update doc for xerror package 2023-02-15 14:41:41 +08:00
dudaodong
d7518e01af doc: fix ExampleXError_StackTrace bug 2023-02-15 12:04:14 +08:00
dudaodong
be9fa7acaa doc: update doc for xerror package 2023-02-15 11:58:33 +08:00
dudaodong
2629a731cc doc: update doc for xerror package 2023-02-15 11:53:21 +08:00
dudaodong
54c7f90b7f test: add examples for xerror package 2023-02-15 10:39:51 +08:00
dudaodong
770bc88b88 doc: update doc for xerror package 2023-02-15 10:14:26 +08:00
dudaodong
4cc1722f81 feat: fix AesEcbEncrypt and AesEcbDecrypt 2023-02-14 16:42:25 +08:00
dudaodong
d0260b2841 feat: add XError to support more contextual error handling 2023-02-14 16:32:57 +08:00
dudaodong
57bd64cae7 feat: add stack 2023-02-14 10:21:38 +08:00
dudaodong
c383719496 doc: add doc for DeepClone function 2023-02-12 19:24:56 +08:00
dudaodong
4b196a72b1 feat: add DeepClone 2023-02-10 15:50:28 +08:00
dudaodong
888381a06c doc: add drop and sort related function doc 2023-02-10 10:53:41 +08:00
dudaodong
a554eb7ef4 doc: add doc for sort function 2023-02-10 10:42:38 +08:00
dudaodong
26ff90122b doc: add doc for Drop function 2023-02-10 10:31:02 +08:00
dudaodong
75b27c6540 feat: add IsSortedByKey 2023-02-10 10:10:57 +08:00
dudaodong
a7e77fa98d feat: add IsSorted 2023-02-09 19:30:11 +08:00
dudaodong
abf392117a feat: add IsAscending, Isdescending 2023-02-09 19:25:58 +08:00
dudaodong
d231d9f572 feat: add DropRightWhile 2023-02-09 17:53:26 +08:00
dudaodong
97447d058e test: add test and example for DropWhile 2023-02-09 17:46:40 +08:00
dudaodong
040e112aa6 feat: add DropRight and DropWhile 2023-02-09 17:38:31 +08:00
dudaodong
afb021b4b5 feat: add Max, Min for stream 2023-02-08 15:20:29 +08:00
dudaodong
5075774000 feat: add Sorted for stream 2023-02-08 15:07:09 +08:00
dudaodong
6bba44dc50 feat: add Concat for stream 2023-02-07 10:47:28 +08:00
dudaodong
422022c74d feat: add Range for stream 2023-02-07 10:36:07 +08:00
dudaodong
87fcf97e2d feat: add FindFirst, Reverse for stream 2023-02-07 10:24:19 +08:00
dudaodong
05d1f348d4 refactor: update constant names 2023-02-06 19:39:31 +08:00
dudaodong
6f2f1f3004 fix: IsZeroValue support pointer 2023-02-06 19:36:36 +08:00
dudaodong
9cd9d1aeb5 release v2.1.14 2023-02-06 17:42:13 +08:00
dudaodong
71b27c0aa9 feat: add ForEach, Reduce for stream 2023-02-06 17:40:54 +08:00
dudaodong
09a379ec6d feat: add ForEach, Reduce for stream 2023-02-06 17:38:33 +08:00
dudaodong
b4b9b03835 feat: add NoneMatch, AllMatch, AnyMatch for stream 2023-02-06 17:24:17 +08:00
dudaodong
48c7794b01 feat: add Limit method of stream 2023-02-06 17:08:36 +08:00
dudaodong
8e3911833d doc: normalize documents 2023-02-06 11:42:03 +08:00
dudaodong
ebe494051b doc: add doc for some new methods of list 2023-02-06 11:35:32 +08:00
dudaodong
c35bda6a65 feat: add ListToMap for list 2023-02-06 11:06:46 +08:00
dudaodong
1fe4cdc429 feat: add Difference and SymmetricDifference for list 2023-02-06 10:55:42 +08:00
dudaodong
6a79e322e3 Merge branch 'main' into v2 2023-02-06 10:00:02 +08:00
Cai Zhijiang
17e8d2bb6d 部分城市有4位区号+8位号码 (#69) 2023-02-06 09:47:21 +08:00
燕归来
325be0d6a1 feat: add func Iterator, ForEach, RetainAll and DeleteAll for List structure (#71) 2023-02-06 09:46:25 +08:00
dudaodong
ea0f96a8c0 feat: add Skip for stream 2023-01-30 16:56:33 +08:00
dudaodong
82cbb54787 feat: add FromChannel for create stream 2023-01-17 16:47:20 +08:00
dudaodong
585d33cafa feat: add Generate for create stream 2023-01-17 16:31:44 +08:00
dudaodong
bc4cf35e15 feat: add Filter, Map, Count for stream 2023-01-17 14:59:47 +08:00
dudaodong
a3bc20af1d feat: add Distinct 2023-01-17 11:39:05 +08:00
dudaodong
61338b6b46 feat: add Stream package 2023-01-17 11:25:15 +08:00
dudaodong
bc3c080ac3 doc: normalize document 2023-01-15 12:43:00 +08:00
dudaodong
d3fab15af3 refactor: clean structure for netutil package 2023-01-14 14:39:06 +08:00
dudaodong
6e3e411d46 doc: normalize document 2023-01-14 12:48:39 +08:00
dudaodong
f976941e36 doc: normalize document 2023-01-14 12:32:27 +08:00
dudaodong
4c5524354c doc: normalize documents 2023-01-13 14:36:33 +08:00
dudaodong
2c6e9a3fb9 doc: format document 2023-01-13 11:01:22 +08:00
dudaodong
5f2c3edff4 doc: format document 2023-01-13 10:57:40 +08:00
dudaodong
b422d98702 doc: format document 2023-01-13 10:48:21 +08:00
dudaodong
6f27e0bfbf doc: format document 2023-01-13 10:47:47 +08:00
dudaodong
ce3b6b461e doc: format document 2023-01-13 10:43:16 +08:00
dudaodong
0d6ad4f0d2 doc: format document 2023-01-13 10:41:47 +08:00
dudaodong
c875a7f8b8 doc: format document 2023-01-13 10:39:39 +08:00
dudaodong
0c62d117a1 doc: format document 2023-01-13 10:12:37 +08:00
dudaodong
c260ce493d doc: normalize documents 2023-01-12 15:44:34 +08:00
dudaodong
9ffe96d3ef update readme file 2023-01-12 11:32:43 +08:00
dudaodong
d4bba76dc8 fix: fix ExampleSchedule failed 2023-01-09 11:25:14 +08:00
dudaodong
adaa3ebc43 Merge branch 'main' into v2 2023-01-09 11:16:13 +08:00
dudaodong
61d38ae3b8 doc: update doc for algorithm package 2023-01-09 11:15:25 +08:00
dudaodong
c85d910044 add playground demo 2023-01-09 11:02:41 +08:00
dudaodong
d95a7c6101 fix: fix example function bug in function package 2023-01-08 21:09:41 +08:00
dudaodong
bce3641ec6 fix: fix example function bug in datetime package 2023-01-08 21:04:39 +08:00
dudaodong
ceb134b2fd fix: fix example function bug in datetime package 2023-01-08 21:01:05 +08:00
dudaodong
4b9b1d32c5 release v2.1.13 2023-01-08 20:45:43 +08:00
dudaodong
395e0883c7 fix: fix example test failed of CreateFile 2023-01-08 20:44:23 +08:00
dudaodong
a930511054 test&doc: add example and update doc for xerror package 2023-01-08 20:36:32 +08:00
dudaodong
7380721ccc test&doc: add example and update doc for xerror package 2023-01-08 20:36:17 +08:00
dudaodong
936011dc3b fix: fix bug in file test 2023-01-08 20:25:11 +08:00
dudaodong
bc0ee08f38 test&doc: add example and update doc for datetime package 2023-01-08 20:16:04 +08:00
dudaodong
f1afd753d4 test&doc: add example and update doc for netutil package 2023-01-08 16:57:03 +08:00
dudaodong
b05a0a91c3 test&doc: add example and update doc for netutil package 2023-01-08 16:54:29 +08:00
97 changed files with 16928 additions and 6831 deletions

355
README.md
View File

@@ -1,10 +1,10 @@
<div align=center> <div align=center>
<a href="https://uvdream.github.io/lancet-docs/en/"><img src="./logo.png" width="200" height="200"/></a> <img src="./logo.png" width="200" height="200"/>
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.12-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.1.16-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -24,7 +24,7 @@ English | [简体中文](./README_zh-CN.md)
## Feature ## Feature
- 👏 Comprehensive, efficient and reusable. - 👏 Comprehensive, efficient and reusable.
- 💪 300+ go util functions, support string, slice, datetime, net, crypt... - 💪 400+ go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depend on the go standard library. - 💅 Only depend on the go standard library.
- 🌍 Unit test for every exported function. - 🌍 Unit test for every exported function.
@@ -38,10 +38,10 @@ English | [简体中文](./README_zh-CN.md)
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
``` ```
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.5. </b> 2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.7. </b>
```go ```go
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x go get github.com/duke-git/lancet@v1.3.7 // below go1.18, install latest version of v1.x.x
``` ```
## Usage ## Usage
@@ -113,6 +113,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
[[play](https://go.dev/play/p/Anozfr8ZLH3)] [[play](https://go.dev/play/p/Anozfr8ZLH3)]
- **<big>LinearSearch</big>** : returns the index of target in slice base on equal function. - **<big>LinearSearch</big>** : returns the index of target in slice base on equal function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)]
[[play](https://go.dev/play/p/IsS7rgn5s3x)]
- **<big>LRUCache</big>** : implements memory cache with lru algorithm. - **<big>LRUCache</big>** : implements memory cache with lru algorithm.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)]
[[play](https://go.dev/play/p/-EZjgOURufP)] [[play](https://go.dev/play/p/-EZjgOURufP)]
@@ -127,24 +128,34 @@ import "github.com/duke-git/lancet/v2/concurrency"
- **<big>NewChannel</big>** : create a Channel pointer instance. - **<big>NewChannel</big>** : create a Channel pointer instance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)]
[[play](https://go.dev/play/p/7aB4KyMMp9A)]
- **<big>Bridge</big>** : link multiply channels into one channel. - **<big>Bridge</big>** : link multiply channels into one channel.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)]
[[play](https://go.dev/play/p/qmWSy1NVF-Y)]
- **<big>FanIn</big>** : merge multiple channels into one channel. - **<big>FanIn</big>** : merge multiple channels into one channel.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)]
[[play](https://go.dev/play/p/2VYFMexEvTm)]
- **<big>Generate</big>** : creates a channel, then put values into the channel. - **<big>Generate</big>** : creates a channel, then put values into the channel.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)]
[[play](https://go.dev/play/p/7aB4KyMMp9A)]
- **<big>Or</big>** : read one or more channels into one channel, will close when any readin channel is closed. - **<big>Or</big>** : read one or more channels into one channel, will close when any readin channel is closed.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)]
[[play](https://go.dev/play/p/Wqz9rwioPww)]
- **<big>OrDone</big>** : read a channel into another channel, will close until cancel context. - **<big>OrDone</big>** : read a channel into another channel, will close until cancel context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)]
[[play](https://go.dev/play/p/lm_GoS6aDjo)]
- **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context. - **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)]
[[play](https://go.dev/play/p/k5N_ALVmYjE)]
- **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context. - **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)]
[[play](https://go.dev/play/p/4J1zAWttP85)]
- **<big>Take</big>** : create a channel whose values are taken from another channel with limit number. - **<big>Take</big>** : create a channel whose values are taken from another channel with limit number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)]
[[play](https://go.dev/play/p/9Utt-1pDr2J)]
- **<big>Tee</big>** : split one chanel into two channels, until cancel the context. - **<big>Tee</big>** : split one chanel into two channels, until cancel the context.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
[[play](https://go.dev/play/p/3TQPKnCirrP)]
### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator... ### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
@@ -162,7 +173,7 @@ import "github.com/duke-git/lancet/v2/condition"
[[play](https://go.dev/play/p/W1SSUmt6pvr)] [[play](https://go.dev/play/p/W1SSUmt6pvr)]
- **<big>Or</big>** : returns false if neither a nor b is truthy. - **<big>Or</big>** : returns false if neither a nor b is truthy.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)]
[[play](https://go.dev/play/p/UlQTxHaeEkq)]] [[play](https://go.dev/play/p/UlQTxHaeEkq)]]
- **<big>Xor</big>** : returns true if a or b but not both is truthy. - **<big>Xor</big>** : returns true if a or b but not both is truthy.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)]
[[play](https://go.dev/play/p/gObZrW7ZbG8)] [[play](https://go.dev/play/p/gObZrW7ZbG8)]
@@ -235,6 +246,12 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>DecodeByte</big>** : decode byte slice data to target object. - **<big>DecodeByte</big>** : decode byte slice data to target object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)]
[[play](https://go.dev/play/p/zI6xsmuQRbn)] [[play](https://go.dev/play/p/zI6xsmuQRbn)]
- **<big>DeepClone</big>** : creates a deep copy of passed item, can't clone unexported field of struct.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DeepClone)]
[[play](https://go.dev/play/p/j4DP5dquxnk)]
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
### 5. Cryptor package is for data encryption and decryption. ### 5. Cryptor package is for data encryption and decryption.
@@ -340,8 +357,6 @@ import "github.com/duke-git/lancet/v2/cryptor"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)]
[[play](https://go.dev/play/p/uef0q1fz53I)] [[play](https://go.dev/play/p/uef0q1fz53I)]
### 6. Datetime package supports date and time format and compare. ### 6. Datetime package supports date and time format and compare.
```go ```go
@@ -350,36 +365,99 @@ import "github.com/duke-git/lancet/v2/datetime"
#### Function list: #### Function list:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddDay) - **<big>AddDay</big>** : add or sub day to the time.
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddDay)]
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddMinute) [[play](https://go.dev/play/p/dIGbs_uTdFa)]
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute) - **<big>AddHour</big>** : add or sub day to the time.
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddHour)]
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay) [[play](https://go.dev/play/p/rcMjd7OCsi5)]
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek) - **<big>AddMinute</big>** : add or sub day to the time.
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddMinute)]
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear) [[play](https://go.dev/play/p/nT1heB1KUUK)]
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute) - **<big>BeginOfMinute</big>** : return the date time at the begin of minute of specific date.
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)]
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay) [[play](https://go.dev/play/p/ieOLVJ9CiFT)]
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek) - **<big>BeginOfHour</big>** : return the date time at the begin of hour of specific date.
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)]
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear) [[play](https://go.dev/play/p/GhdGFnDWpYs)]
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDate) - **<big>BeginOfDay</big>** : return the date time at the begin of day of specific date.
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowTime) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)]
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime) [[play](https://go.dev/play/p/94m_UT6cWs9)]
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp) - **<big>BeginOfWeek</big>** : return the date time at the begin of week of specific date.
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNightTimestamp) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)]
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatTimeToStr) [[play](https://go.dev/play/p/ynjoJPz7VNV)]
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatStrToTime) - **<big>BeginOfMonth</big>** : return the date time at the begin of month of specific date.
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnix) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)]
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnixNow) [[play](https://go.dev/play/p/bWXVFsmmzwL)]
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewFormat) - **<big>BeginOfYear</big>** : return the date time at the begin of year of specific date.
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewISO8601) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)]
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToUnix) [[play](https://go.dev/play/p/i326DSwLnV8)]
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormat) - **<big>EndOfMinute</big>** : return the date time at the end of minute of specific date.
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormatForTpl) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)]
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601) [[play](https://go.dev/play/p/yrL5wGzPj4z)]
- **<big>EndOfHour</big>** : return the date time at the end of hour of specific date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)]
[[play](https://go.dev/play/p/6ce3j_6cVqN)]
- **<big>EndOfDay</big>** : return the date time at the end of day of specific date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)]
[[play](https://go.dev/play/p/eMBOvmq5Ih1)]
- **<big>EndOfWeek</big>** : return the date time at the end of week of specific date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)]
[[play](https://go.dev/play/p/i08qKXD9flf)]
- **<big>EndOfMonth</big>** : return the date time at the end of month of specific date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)]
[[play](https://go.dev/play/p/_GWh10B3Nqi)]
- **<big>EndOfYear</big>** : return the date time at the end of year of specific date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)]
[[play](https://go.dev/play/p/G01cKlMCvNm)]
- **<big>GetNowDate</big>** : return format yyyy-mm-dd of current date.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDate)]
[[play](https://go.dev/play/p/PvfkPpcpBBf)]
- **<big>GetNowTime</big>** : return format hh-mm-ss of current time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowTime)]
[[play](https://go.dev/play/p/l7BNxCkTmJS)]
- **<big>GetNowDateTime</big>** : return format yyyy-mm-dd hh-mm-ss of current datetime.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime)]
[[play](https://go.dev/play/p/pI4AqngD0al)]
- **<big>GetZeroHourTimestamp</big>** : return timestamp of zero hour (timestamp of 00:00).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp)]
[[play](https://go.dev/play/p/QmL2oIaGE3q)]
- **<big>GetNightTimestamp</big>** : return timestamp of zero hour (timestamp of 23:59).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNightTimestamp)]
[[play](https://go.dev/play/p/UolysR3MYP1)]
- **<big>FormatTimeToStr</big>** : convert time to string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatTimeToStr)]
[[play](https://go.dev/play/p/_Ia7M8H_OvE)]
- **<big>FormatStrToTime</big>** : convert string to time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatStrToTime)]
[[play](https://go.dev/play/p/1h9FwdU8ql4)]
- **<big>NewUnix</big>** : return unix timestamp of specific time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnix)]
[[play](https://go.dev/play/p/psoSuh_kLRt)]
- **<big>NewUnixNow</big>** : return unix timestamp of current time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnixNow)]
[[play](https://go.dev/play/p/U4PPx-9D0oz)]
- **<big>NewFormat</big>** : return unix timestamp of specific time string, t should be "yyyy-mm-dd hh:mm:ss".
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>NewISO8601</big>** : return unix timestamp of specific iso8601 time string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewISO8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
- **<big>ToUnix</big>** : return unix timestamp.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToUnix)]
[[play](https://go.dev/play/p/_LUiwAdocjy)]
- **<big>ToFormat</big>** : return the time string 'yyyy-mm-dd hh:mm:ss' of unix time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>ToFormatForTpl</big>** : return the time string which format is specific tpl.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormatForTpl)]
[[play](https://go.dev/play/p/nyXxXcQJ8L5)]
- **<big>ToIso8601</big>** : return iso8601 time string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. ### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
@@ -413,8 +491,6 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
- **<big>Hashmap</big>** : hash map structure. - **<big>Hashmap</big>** : hash map structure.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)]
### 8. Fileutil package implements some basic functions for file operations. ### 8. Fileutil package implements some basic functions for file operations.
```go ```go
@@ -497,8 +573,10 @@ import "github.com/duke-git/lancet/v2/function"
[[play](https://go.dev/play/p/0HqUDIFZ3IL)] [[play](https://go.dev/play/p/0HqUDIFZ3IL)]
- **<big>CurryFn</big>** : make a curry function. - **<big>CurryFn</big>** : make a curry function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#CurryFn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#CurryFn)]
[[play](https://go.dev/play/p/5HopfDwANKX)]
- **<big>Compose</big>** : compose the functions from right to left. - **<big>Compose</big>** : compose the functions from right to left.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)]
[[play](https://go.dev/play/p/KKfugD4PKYF)]
- **<big>Delay</big>** : call the function after delayed time. - **<big>Delay</big>** : call the function after delayed time.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)]
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)] [[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
@@ -513,7 +591,7 @@ import "github.com/duke-git/lancet/v2/function"
[[play](https://go.dev/play/p/mPdUVvj6HD6)] [[play](https://go.dev/play/p/mPdUVvj6HD6)]
- **<big>Watcher</big>** : Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution. - **<big>Watcher</big>** : Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 11. Maputil package includes some functions to manipulate map. ### 11. Maputil package includes some functions to manipulate map.
@@ -530,12 +608,24 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Filter</big>** : iterates over map, return a new map contains all key and value pairs pass the predicate function. - **<big>Filter</big>** : iterates over map, return a new map contains all key and value pairs pass the predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)]
[[play](https://go.dev/play/p/fSvF3wxuNG7)] [[play](https://go.dev/play/p/fSvF3wxuNG7)]
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps. - **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
[[play](https://go.dev/play/p/Zld0oj3sjcC)] [[play](https://go.dev/play/p/Zld0oj3sjcC)]
- **<big>Keys</big>** : returns a slice of the map's keys. - **<big>Keys</big>** : returns a slice of the map's keys.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)]
[[play](https://go.dev/play/p/xNB5bTb97Wd)] [[play](https://go.dev/play/p/xNB5bTb97Wd)]
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
- **<big>Merge</big>** : merge maps, next key will overwrite previous key. - **<big>Merge</big>** : merge maps, next key will overwrite previous key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
[[play](https://go.dev/play/p/H95LENF1uB-)] [[play](https://go.dev/play/p/H95LENF1uB-)]
@@ -545,6 +635,18 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Values</big>** : returns a slice of the map's values. - **<big>Values</big>** : returns a slice of the map's values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)]
[[play](https://go.dev/play/p/CBKdUc5FTW6)] [[play](https://go.dev/play/p/CBKdUc5FTW6)]
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
- **<big>Transform</big>** : transform a map to another type map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common. - **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)] [[play](https://go.dev/play/p/N9qgYg_Ho6f)]
@@ -583,6 +685,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/N9qgYg_Ho6f)] [[play](https://go.dev/play/p/N9qgYg_Ho6f)]
- **<big>Percent</big>** : calculate the percentage of value to total. - **<big>Percent</big>** : calculate the percentage of value to total.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)]
[[play](https://go.dev/play/p/QQM9B13coSP)]
- **<big>RoundToFloat</big>** : round up to n decimal places for float64. - **<big>RoundToFloat</big>** : round up to n decimal places for float64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)]
[[play](https://go.dev/play/p/ghyb528JRJL)] [[play](https://go.dev/play/p/ghyb528JRJL)]
@@ -601,26 +704,62 @@ import "github.com/duke-git/lancet/v2/netutil"
#### Function list: #### Function list:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString) - **<big>ConvertMapToQueryString</big>** : convert map to sorted url query string.
- [EncodeUrl](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#EncodeUrl) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString)]
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp) [[play](https://go.dev/play/p/jnNt_qoSnRi)]
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps) - **<big>EncodeUrl</big>** : encode url(?a=1&b=[2] -> ?a=1&b=%5B2%5D).
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#EncodeUrl)]
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo) [[play](https://go.dev/play/p/bsZ6BRC4uKI)]
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetRequestPublicIp) - **<big>GetInternalIp</big>** : return internal ipv4.
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp)]
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsInternalIP) [[play](https://go.dev/play/p/5mbu-gFp7ei)]
- [HttpRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpRequest) - **<big>GetIps</big>** : return all ipv4 of current system.
- [HttpClient](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpClient) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)]
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest) [[play](https://go.dev/play/p/NUFfcEmukx1)]
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse) - **<big>GetMacAddrs</big>** : return mac address of current system.
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)]
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet) [[play](https://go.dev/play/p/Rq9UUBS_Xp1)]
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete) - **<big>GetPublicIpInfo</big>** : return [public ip information](http://ip-api.com/json/).
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)]
- [HttpPut<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut) [[play](https://go.dev/play/p/YDxIfozsRHR)]
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch) - **<big>GetRequestPublicIp</big>** : return the http request public ip.
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetRequestPublicIp)]
[[play](https://go.dev/play/p/kxU-YDc_eBo)]
- **<big>IsPublicIP</big>** : verify a ip is public or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)]
[[play](https://go.dev/play/p/nmktSQpJZnn)]
- **<big>IsInternalIP</big>** : verify an ip is intranet or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsInternalIP)]
[[play](https://go.dev/play/p/sYGhXbgO4Cb)]
- **<big>HttpRequest</big>** : a composed http request used for HttpClient send request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>HttpClient</big>** : a http client tool, used for sending http request
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpClient)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>SendRequest</big>** : send http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>DecodeResponse</big>** : decode http response into target object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>StructToUrlValues</big>** : convert struct to url valuse.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)]
[[play](https://go.dev/play/p/pFqMkM40w9z)]
- **<big>HttpGet<sup>deprecated</sup></big>** : send get http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)]
- **<big>HttpDelete<sup>deprecated</sup></big>** : send delete http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)]
- **<big>HttpPost<sup>deprecated</sup></big>** : send post http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)]
- **<big>HttpPut<sup>deprecated</sup></big>** : send put http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)]
- **<big>HttpPatch<sup>deprecated</sup></big>** : send patch http request.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)]
- **<big>ParseHttpResponse</big>** : decode http response into target object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
### 14. Random package implements some basic functions to generate random int and string. ### 14. Random package implements some basic functions to generate random int and string.
@@ -636,7 +775,7 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>RandInt</big>** : generate random int number between min and max. - **<big>RandInt</big>** : generate random int number between min and max.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)]
[[play](https://go.dev/play/p/pXyyAAI5YxD)] [[play](https://go.dev/play/p/pXyyAAI5YxD)]
- **<big>RandString</big>** : generate random string of specified length. - **<big>RandString</big>** : generate random string of specific length.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)]
[[play](https://go.dev/play/p/W2xvRUXA7Mi)] [[play](https://go.dev/play/p/W2xvRUXA7Mi)]
- **<big>RandUpper</big>** : generate a random upper case string. - **<big>RandUpper</big>** : generate a random upper case string.
@@ -645,7 +784,7 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>RandLower</big>** : generate a random lower case string. - **<big>RandLower</big>** : generate a random lower case string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)]
[[play](https://go.dev/play/p/XJtZ471cmtI)] [[play](https://go.dev/play/p/XJtZ471cmtI)]
- **<big>RandNumeral</big>** : generate a random numeral string of specified length. - **<big>RandNumeral</big>** : generate a random numeral string of specific length.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)]
[[play](https://go.dev/play/p/g4JWVpHsJcf)] [[play](https://go.dev/play/p/g4JWVpHsJcf)]
- **<big>RandNumeralOrLetter</big>** : generate a random numeral or letter string. - **<big>RandNumeralOrLetter</big>** : generate a random numeral or letter string.
@@ -679,8 +818,6 @@ import "github.com/duke-git/lancet/v2/retry"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)] [[play](https://go.dev/play/p/ssfVeU2SwLO)]
### 16. Slice contains some functions to manipulate slice. ### 16. Slice contains some functions to manipulate slice.
```go ```go
@@ -695,6 +832,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Contain</big>** : check if the value is in the slice or not. - **<big>Contain</big>** : check if the value is in the slice or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)]
[[play](https://go.dev/play/p/_454yEHcNjf)] [[play](https://go.dev/play/p/_454yEHcNjf)]
- **<big>ContainBy</big>** : returns true if predicate function return true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not. - **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
[[play](https://go.dev/play/p/bcuQ3UT6Sev)] [[play](https://go.dev/play/p/bcuQ3UT6Sev)]
@@ -725,9 +864,18 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>DeleteAt</big>** : delete the element of slice from specific start index to end index - 1. - **<big>DeleteAt</big>** : delete the element of slice from specific start index to end index - 1.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)] [[play](https://go.dev/play/p/pJ-d6MUWcvK)]
- **<big>Drop</big>** : creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0. - **<big>Drop</big>** : drop n elements from the start of a slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)] [[play](https://go.dev/play/p/jnPO2yQsT8H)]
- **<big>DropRight</big>** : drop n elements from the end of a slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DropRight)]
[[play](https://go.dev/play/p/8bcXvywZezG)]
- **<big>DropWhile</big>** : drop n elements from the start of a slice while predicate function returns true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DropWhile)]
[[play](https://go.dev/play/p/4rt252UV_qs)]
- **<big>DropRightWhile</big>** : drop n elements from the end of a slice while predicate function returns true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DropRightWhile)]
[[play](https://go.dev/play/p/6wyK3zMY56e)]
- **<big>Equal</big>** : checks if two slices are equal: the same length and all elements' order and value are equal. - **<big>Equal</big>** : checks if two slices are equal: the same length and all elements' order and value are equal.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)]
[[play](https://go.dev/play/p/WcRQJ37ifPa)] [[play](https://go.dev/play/p/WcRQJ37ifPa)]
@@ -740,6 +888,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Filter</big>** : iterates over elements of slice, returning an slice of all elements pass the predicate function. - **<big>Filter</big>** : iterates over elements of slice, returning an slice of all elements pass the predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)]
[[play](https://go.dev/play/p/SdPna-7qK4T)] [[play](https://go.dev/play/p/SdPna-7qK4T)]
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function. - **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
[[play](https://go.dev/play/p/CBKeBoHVLgq)] [[play](https://go.dev/play/p/CBKeBoHVLgq)]
@@ -752,6 +902,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>FlattenDeep</big>** : flattens slice recursive to one level. - **<big>FlattenDeep</big>** : flattens slice recursive to one level.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)]
[[play](https://go.dev/play/p/yjYNHPyCFaF)] [[play](https://go.dev/play/p/yjYNHPyCFaF)]
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element. - **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
[[play](https://go.dev/play/p/DrPaa4YsHRF)] [[play](https://go.dev/play/p/DrPaa4YsHRF)]
@@ -803,6 +955,18 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Shuffle</big>** : shuffle the slice. - **<big>Shuffle</big>** : shuffle the slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)]
[[play](https://go.dev/play/p/YHvhnWGU3Ge)] [[play](https://go.dev/play/p/YHvhnWGU3Ge)]
- **<big>IsAscending</big>** : Checks if a slice is ascending order.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IsAscending)]
[[play](https://go.dev/play/p/9CtsFjet4SH)]
- **<big>IsDescending</big>** : Checks if a slice is descending order.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IsDescending)]
[[play](https://go.dev/play/p/U_LljFXma14)]
- **<big>IsSorted</big>** : Checks if a slice is sorted (ascending or descending).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IsSorted)]
[[play](https://go.dev/play/p/nCE8wPLwSA-)]
- **<big>IsSortedByKey</big>** : Checks if a slice is sorted by iteratee function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IsSortedByKey)]
[[play](https://go.dev/play/p/tUoGB7DOHI4)]
- **<big>Sort</big>** : sorts a slice of any ordered type(number or string). - **<big>Sort</big>** : sorts a slice of any ordered type(number or string).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Sort)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Sort)]
[[play](https://go.dev/play/p/V9AVjzf_4Fk)] [[play](https://go.dev/play/p/V9AVjzf_4Fk)]
@@ -857,15 +1021,15 @@ import "github.com/duke-git/lancet/v2/strutil"
#### Function list: #### Function list:
- **<big>After</big>** : returns the substring after the first occurrence of a specified string in the source string. - **<big>After</big>** : returns the substring after the first occurrence of a specific string in the source string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)]
[[play](https://go.dev/play/p/RbCOQqCDA7m)] [[play](https://go.dev/play/p/RbCOQqCDA7m)]
- **<big>AfterLast</big>** : returns the substring after the last occurrence of a specified string in the source string. [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)] - **<big>AfterLast</big>** : returns the substring after the last occurrence of a specific string in the source string. [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)]
[[play](https://go.dev/play/p/1TegARrb8Yn)] [[play](https://go.dev/play/p/1TegARrb8Yn)]
- **<big>Before</big>** : returns the substring before the first occurrence of a specified string in the source string. - **<big>Before</big>** : returns the substring before the first occurrence of a specific string in the source string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)]
[[play](https://go.dev/play/p/JAWTZDS4F5w)] [[play](https://go.dev/play/p/JAWTZDS4F5w)]
- **<big>BeforeLast</big>** : returns the substring before the last occurrence of a specified string in the source string. - **<big>BeforeLast</big>** : returns the substring before the last occurrence of a specific string in the source string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)]
[[play](https://go.dev/play/p/pJfXXAoG_Te)] [[play](https://go.dev/play/p/pJfXXAoG_Te)]
- **<big>CamelCase</big>** : coverts source string to its camelCase string. - **<big>CamelCase</big>** : coverts source string to its camelCase string.
@@ -889,6 +1053,8 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>UpperFirst</big>** : converts the first character of string to upper case. - **<big>UpperFirst</big>** : converts the first character of string to upper case.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)]
[[play](https://go.dev/play/p/sBbBxRbs8MM)] [[play](https://go.dev/play/p/sBbBxRbs8MM)]
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size. - **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
[[play](https://go.dev/play/p/9xP8rN0vz--)] [[play](https://go.dev/play/p/9xP8rN0vz--)]
@@ -907,14 +1073,19 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>SplitEx</big>** : split a given string which can control the result slice contains empty string or not. - **<big>SplitEx</big>** : split a given string which can control the result slice contains empty string or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)]
[[play](https://go.dev/play/p/Us-ySSbWh-3)] [[play](https://go.dev/play/p/Us-ySSbWh-3)]
- **<big>Substring</big>** : returns a substring of the specified length starting at the specified offset position. - **<big>Substring</big>** : returns a substring of the specific length starting at the specific offset position.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)]
[[play](https://go.dev/play/p/q3sM6ehnPDp)]
- **<big>Wrap</big>** : wrap a string with given string. - **<big>Wrap</big>** : wrap a string with given string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)]
[[play](https://go.dev/play/p/KoZOlZDDt9y)] [[play](https://go.dev/play/p/KoZOlZDDt9y)]
- **<big>Unwrap</big>** : unwrap a given string from anther string. will change source string. - **<big>Unwrap</big>** : unwrap a given string from anther string. will change source string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)]
[[play](https://go.dev/play/p/Ec2q4BzCpG-)] [[play](https://go.dev/play/p/Ec2q4BzCpG-)]
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
### 19. System package contain some functions about os, runtime, shell command. ### 19. System package contain some functions about os, runtime, shell command.
@@ -1052,8 +1223,46 @@ import "github.com/duke-git/lancet/v2/xerror"
``` ```
#### Function list: #### Function list:
- **<big>New</big>** : creates a new XError pointer instance with message.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>Wrap</big>** : creates a new XError pointer instance based on error object, and add message.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>Unwrap</big>** : returns unwrapped XError from err by errors.As. If no XError, returns nil.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Unwrap)]
[[play](https://go.dev/play/p/LKMLep723tu)]
- **<big>XError_Wrap</big>** : creates a new XError and copy message and id to new one.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>XError_Unwrap</big>** : Compatible with github.com/pkg/errors.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Unwrap)]
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
- **<big>XError_With</big>** : adds key and value related to the XError object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_With)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_Id</big>** : sets XError object id to check equality in XError.Is.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Id)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Is</big>** : checks if target error is XError and Error.id of two errors are matched.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Is)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Values</big>** : returns map of key and value that is set by XError.With function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Values)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_StackTrace</big>** : returns stack trace which is compatible with pkg/errors.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_StackTrace)]
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
- **<big>XError_Info</big>** : returns information of xerror, which can be printed.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Info)]
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
- **<big>XError_Error</big>** : implements standard error interface.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Error)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>TryUnwrap</big>** : check if err is nil then it returns a valid value. If err is not nil, TryUnwrap panics with err.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
[[play](https://go.dev/play/p/acyZVkNZEeW)]
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Unwrap)
## How to Contribute ## How to Contribute

View File

@@ -1,10 +1,10 @@
<div align=center> <div align=center>
<a href="https://uvdream.github.io/lancet-docs/"><img src="./logo.png" width="200" height="200"/><a/> <img src="./logo.png" width="200" height="200"/>
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.12-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.1.16-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -23,7 +23,7 @@
## 特性 ## 特性
- 👏 全面、高效、可复用 - 👏 全面、高效、可复用
- 💪 300+常用 go 工具函数,支持 string、slice、datetime、net、crypt... - 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
- 💅 只依赖 go 标准库 - 💅 只依赖 go 标准库
- 🌍 所有导出函数单元测试覆盖率 100% - 🌍 所有导出函数单元测试覆盖率 100%
@@ -37,10 +37,10 @@
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
``` ```
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.5。</b> 2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.7。</b>
```go ```go
go get github.com/duke-git/lancet@v1.3.5 // 使用go1.18以下版本, 必须安装v1.x.x版本 go get github.com/duke-git/lancet@v1.3.7 // 使用go1.18以下版本, 必须安装v1.x.x版本
``` ```
## 用法 ## 用法
@@ -51,7 +51,7 @@ lancet 是以包的结构组织代码的,使用时需要导入相应的包名
import "github.com/duke-git/lancet/v2/strutil" import "github.com/duke-git/lancet/v2/strutil"
``` ```
## 例 ##
此处以字符串工具函数 Reverse逆序字符串为例需要导入 strutil 包: 此处以字符串工具函数 Reverse逆序字符串为例需要导入 strutil 包:
@@ -112,6 +112,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
[[play](https://go.dev/play/p/Anozfr8ZLH3)] [[play](https://go.dev/play/p/Anozfr8ZLH3)]
- **<big>LinearSearch</big>** : 基于传入的相等函数返回切片中目标值的索引。(线性查找) - **<big>LinearSearch</big>** : 基于传入的相等函数返回切片中目标值的索引。(线性查找)
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)]
[[play](https://go.dev/play/p/IsS7rgn5s3x)]
- **<big>LRUCache</big>** : 应用 lru 算法实现内存缓存. - **<big>LRUCache</big>** : 应用 lru 算法实现内存缓存.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)]
[[play](https://go.dev/play/p/-EZjgOURufP)] [[play](https://go.dev/play/p/-EZjgOURufP)]
@@ -126,24 +127,34 @@ import "github.com/duke-git/lancet/v2/concurrency"
- **<big>NewChannel</big>** : 返回一个 Channel 指针实例。 - **<big>NewChannel</big>** : 返回一个 Channel 指针实例。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)]
[[play](https://go.dev/play/p/7aB4KyMMp9A)]
- **<big>Bridge</big>** : 将多个 channel 链接到一个 channel直到取消上下文。 - **<big>Bridge</big>** : 将多个 channel 链接到一个 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)]
[[play](https://go.dev/play/p/qmWSy1NVF-Y)]
- **<big>FanIn</big>** : 将多个 channel 合并为一个 channel直到取消上下文。 - **<big>FanIn</big>** : 将多个 channel 合并为一个 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)]
[[play](https://go.dev/play/p/2VYFMexEvTm)]
- **<big>Generate</big>** : 根据传入的值,生成 channel。 - **<big>Generate</big>** : 根据传入的值,生成 channel。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)]
[[play](https://go.dev/play/p/7aB4KyMMp9A)]
- **<big>Or</big>** : 将一个或多个 channel 读取到一个 channel 中,当任何读取 channel 关闭时将结束读取。 - **<big>Or</big>** : 将一个或多个 channel 读取到一个 channel 中,当任何读取 channel 关闭时将结束读取。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)]
[[play](https://go.dev/play/p/Wqz9rwioPww)]
- **<big>OrDone</big>** : 将一个 channel 读入另一个 channel直到取消上下文。 - **<big>OrDone</big>** : 将一个 channel 读入另一个 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)]
[[play](https://go.dev/play/p/lm_GoS6aDjo)]
- **<big>Repeat</big>** : 返回一个 channel将参数`values`重复放入 channel直到取消上下文。 - **<big>Repeat</big>** : 返回一个 channel将参数`values`重复放入 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)]
[[play](https://go.dev/play/p/k5N_ALVmYjE)]
- **<big>RepeatFn</big>** : 返回一个 channel重复执行函数 fn并将结果放入返回的 channel直到取消上下文。 - **<big>RepeatFn</big>** : 返回一个 channel重复执行函数 fn并将结果放入返回的 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)]
[[play](https://go.dev/play/p/4J1zAWttP85)]
- **<big>Take</big>** : 返回一个 channel其值从另一个 channel 获取,直到取消上下文。 - **<big>Take</big>** : 返回一个 channel其值从另一个 channel 获取,直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)]
[[play](https://go.dev/play/p/9Utt-1pDr2J)]
- **<big>Tee</big>** : 将一个 channel 分成两个 channel直到取消上下文。 - **<big>Tee</big>** : 将一个 channel 分成两个 channel直到取消上下文。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)]
[[play](https://go.dev/play/p/3TQPKnCirrP)]
### 3. condition 包含一些用于条件判断的函数。 ### 3. condition 包含一些用于条件判断的函数。
@@ -234,6 +245,12 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>DecodeByte</big>** : 解码字节切片到目标对象,目标对象需要传入一个指针实例。 - **<big>DecodeByte</big>** : 解码字节切片到目标对象,目标对象需要传入一个指针实例。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)]
[[play](https://go.dev/play/p/zI6xsmuQRbn)] [[play](https://go.dev/play/p/zI6xsmuQRbn)]
- **<big>DeepClone</big>** : 创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DeepClone)]
[[play](https://go.dev/play/p/j4DP5dquxnk)]
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
### 5. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。 ### 5. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
@@ -349,36 +366,98 @@ import "github.com/duke-git/lancet/v2/datetime"
#### 函数列表: #### 函数列表:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay) - **<big>AddDay</big>** : 将日期加/减天数。
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay)]
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute) [[play](https://go.dev/play/p/dIGbs_uTdFa)]
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute) - **<big>AddHour</big>** : 将日期加/减小时数。
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour)]
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay) [[play](https://go.dev/play/p/rcMjd7OCsi5)]
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek) - **<big>AddMinute</big>** : 将日期加/减分钟数。
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute)]
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear) [[play](https://go.dev/play/p/nT1heB1KUUK)]
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute) - **<big>BeginOfMinute</big>** : 返回指定时间的分钟开始时间。
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfMinute)]
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay) [[play](https://go.dev/play/p/ieOLVJ9CiFT)]
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek) - **<big>BeginOfHour</big>** : 返回指定时间的小时开始时间。
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfHour)]
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear) [[play](https://go.dev/play/p/GhdGFnDWpYs)]
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate) - **<big>BeginOfDay</big>** : 返回指定时间的当天开始时间。
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfDay)]
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime) [[play](https://go.dev/play/p/94m_UT6cWs9)]
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp) - **<big>BeginOfWeek</big>** : 返回指定时间的每周开始时间,默认开始时间星期日。
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfWeek)]
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr) [[play](https://go.dev/play/p/ynjoJPz7VNV)]
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime) - **<big>BeginOfMonth</big>** : 返回指定时间的当月开始时间。
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfMonth)]
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow) [[play](https://go.dev/play/p/bWXVFsmmzwL)]
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat) - **<big>BeginOfYear</big>** : 返回指定时间的当年开始时间。
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfYear)]
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix) [[play](https://go.dev/play/p/i326DSwLnV8)]
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat) - **<big>EndOfMinute</big>** : 返回指定时间的分钟结束时间。
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl) [[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfMinute)]
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601) [[play](https://go.dev/play/p/yrL5wGzPj4z)]
- **<big>EndOfHour</big>** : 返回指定时间的小时结束时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfHour)]
[[play](https://go.dev/play/p/6ce3j_6cVqN)]
- **<big>EndOfDay</big>** : 返回指定时间的当天结束时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfDay)]
[[play](https://go.dev/play/p/eMBOvmq5Ih1)]
- **<big>EndOfWeek</big>** : 返回指定时间的星期结束时间,默认结束时间星期六。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfWeek)]
[[play](https://go.dev/play/p/i08qKXD9flf)]
- **<big>EndOfMonth</big>** : 返回指定时间的月份结束时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfMonth)]
[[play](https://go.dev/play/p/_GWh10B3Nqi)]
- **<big>EndOfYear</big>** : 返回指定时间的年份结束时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#EndOfYear)]
[[play](https://go.dev/play/p/G01cKlMCvNm)]
- **<big>GetNowDate</big>** : 获取当天日期返回格式yyyy-mm-dd。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate)]
[[play](https://go.dev/play/p/PvfkPpcpBBf)]
- **<big>GetNowTime</big>** : 获取当时时间返回格式hh:mm:ss。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime)]
[[play](https://go.dev/play/p/l7BNxCkTmJS)]
- **<big>GetNowDateTime</big>** : 获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)]
[[play](https://go.dev/play/p/pI4AqngD0al)]
- **<big>GetZeroHourTimestamp</big>** : 获取零时时间戳(timestamp of 00:00)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)]
[[play](https://go.dev/play/p/QmL2oIaGE3q)]
- **<big>GetNightTimestamp</big>** : 获取午夜时间戳(timestamp of 23:59)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp)]
[[play](https://go.dev/play/p/UolysR3MYP1)]
- **<big>FormatTimeToStr</big>** : 将日期格式化成字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr)]
[[play](https://go.dev/play/p/_Ia7M8H_OvE)]
- **<big>FormatStrToTime</big>** : 将字符串格式化成时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)]
[[play](https://go.dev/play/p/1h9FwdU8ql4)]
- **<big>NewUnix</big>** : 创建一个unix时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)]
[[play](https://go.dev/play/p/psoSuh_kLRt)]
- **<big>NewUnixNow</big>** : 创建一个当前时间的unix时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)]
[[play](https://go.dev/play/p/U4PPx-9D0oz)]
- **<big>NewFormat</big>** : 创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>NewISO8601</big>** : 创建一个iso8601格式时间字符串的unix时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
- **<big>ToUnix</big>** : 返回unix时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)]
[[play](https://go.dev/play/p/_LUiwAdocjy)]
- **<big>ToFormat</big>** : 返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>ToFormatForTpl</big>** : 返回tpl格式指定的日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)]
[[play](https://go.dev/play/p/nyXxXcQJ8L5)]
- **<big>ToIso8601</big>** : 返回iso8601日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
### 7. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph. ### 7. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
@@ -497,8 +576,10 @@ import "github.com/duke-git/lancet/v2/function"
[[play](https://go.dev/play/p/0HqUDIFZ3IL)] [[play](https://go.dev/play/p/0HqUDIFZ3IL)]
- **<big>CurryFn</big>** : 创建柯里化函数。 - **<big>CurryFn</big>** : 创建柯里化函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#CurryFn)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#CurryFn)]
[[play](https://go.dev/play/p/5HopfDwANKX)]
- **<big>Compose</big>** : 从右至左组合函数列表fnList返回组合后的函数。 - **<big>Compose</big>** : 从右至左组合函数列表fnList返回组合后的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)]
[[play](https://go.dev/play/p/KKfugD4PKYF)]
- **<big>Delay</big>** : 延迟delay时间后调用函数。 - **<big>Delay</big>** : 延迟delay时间后调用函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)]
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)] [[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
@@ -513,6 +594,7 @@ import "github.com/duke-git/lancet/v2/function"
[[play](https://go.dev/play/p/mPdUVvj6HD6)] [[play](https://go.dev/play/p/mPdUVvj6HD6)]
- **<big>Watcher</big>** : Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 - **<big>Watcher</big>** : Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 11. maputil 包括一些操作 map 的函数. ### 11. maputil 包括一些操作 map 的函数.
@@ -529,12 +611,24 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Filter</big>** : 迭代 map 中的每对 key 和 value返回 map其中的 key 和 value 符合 predicate 函数。 - **<big>Filter</big>** : 迭代 map 中的每对 key 和 value返回 map其中的 key 和 value 符合 predicate 函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)]
[[play](https://go.dev/play/p/fSvF3wxuNG7)] [[play](https://go.dev/play/p/fSvF3wxuNG7)]
- **<big>FilterByKeys</big>** : 迭代map, 返回一个新map其key都是给定的key值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
- **<big>FilterByValues</big>** : 迭代map, 返回一个新map其value都是给定的value值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
- **<big>OmitBy</big>** : Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
- **<big>OmitByKeys</big>** : FilterByKeys的反向操作, 迭代map, 返回一个新map其key不包括给定的key值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
- **<big>OmitByValues</big>** : FilterByValues的反向操作, 迭代map, 返回一个新map其value不包括给定的value值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
- **<big>Intersect</big>** : 多个 map 的交集操作。 - **<big>Intersect</big>** : 多个 map 的交集操作。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
[[play](https://go.dev/play/p/Zld0oj3sjcC)] [[play](https://go.dev/play/p/Zld0oj3sjcC)]
- **<big>Keys</big>** : 返回 map 中所有 key 组成的切片。 - **<big>Keys</big>** : 返回 map 中所有 key 组成的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)]
[[play](https://go.dev/play/p/xNB5bTb97Wd)] [[play](https://go.dev/play/p/xNB5bTb97Wd)]
- **<big>KeysBy</big>** : 创建一个切片其元素是每个map的key调用mapper函数的结果。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。 - **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
[[play](https://go.dev/play/p/H95LENF1uB-)] [[play](https://go.dev/play/p/H95LENF1uB-)]
@@ -544,7 +638,19 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Values</big>** : 返回 map 中所有 values 组成的切片 - **<big>Values</big>** : 返回 map 中所有 values 组成的切片
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)]
[[play](https://go.dev/play/p/CBKdUc5FTW6)] [[play](https://go.dev/play/p/CBKdUc5FTW6)]
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key - **<big>ValuesBy</big>** : 创建一个切片其元素是每个map的value调用mapper函数的结果
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
- **<big>MapKeys</big>** : 操作map的每个key然后转为新的map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
- **<big>MapValues</big>** : 操作map的每个value然后转为新的map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
- **<big>Entries</big>** : 将map转换为键/值对切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
- **<big>FromEntries</big>** : 基于键/值对的切片创建map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
- **<big>Transform</big>** : 将map转换为其他类型的map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
- **<big>IsDisjoint</big>** : 验证两个map是否具有不同的key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)] [[play](https://go.dev/play/p/N9qgYg_Ho6f)]
@@ -582,6 +688,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/N9qgYg_Ho6f)] [[play](https://go.dev/play/p/N9qgYg_Ho6f)]
- **<big>Percent</big>** : 计算百分比,可以指定保留 n 位小数。 - **<big>Percent</big>** : 计算百分比,可以指定保留 n 位小数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)]
[[play](https://go.dev/play/p/QQM9B13coSP)]
- **<big>RoundToFloat</big>** : 四舍五入,保留 n 位小数,返回 float64。 - **<big>RoundToFloat</big>** : 四舍五入,保留 n 位小数,返回 float64。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)]
[[play](https://go.dev/play/p/ghyb528JRJL)] [[play](https://go.dev/play/p/ghyb528JRJL)]
@@ -600,26 +707,63 @@ import "github.com/duke-git/lancet/v2/netutil"
#### 函数列表: #### 函数列表:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString) - **<big>ConvertMapToQueryString</big>** : 将map转换成http查询字符串。
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)]
- [EncodeUrl](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#EncodeUrl) [[play](https://go.dev/play/p/jnNt_qoSnRi)]
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps) - **<big>EncodeUrl</big>** : 编码url query string的值(?a=1&b=[2] -> ?a=1&b=%5B2%5D)。
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#EncodeUrl)]
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo) [[play](https://go.dev/play/p/bsZ6BRC4uKI)]
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp) - **<big>GetInternalIp</big>** : 获取内部ipv4。
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)]
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP) [[play](https://go.dev/play/p/5mbu-gFp7ei)]
- [HttpRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpRequest) - **<big>GetIps</big>** : 获取系统ipv4地址列表。
- [HttpClient](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpClient) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetIps)]
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest) [[play](https://go.dev/play/p/NUFfcEmukx1)]
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse) - **<big>GetMacAddrs</big>** : 获取系统mac地址列。
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetMacAddrs)]
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet) [[play](https://go.dev/play/p/Rq9UUBS_Xp1)]
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete) - **<big>GetPublicIpInfo</big>** : 获取[公网ip信息](http://ip-api.com/json/).
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)]
- [HttpPut<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut) [[play](https://go.dev/play/p/YDxIfozsRHR)]
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch) - **<big>GetRequestPublicIp</big>** : 获取http请求ip。
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse) [[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp)]
[[play](https://go.dev/play/p/kxU-YDc_eBo)]
- **<big>IsPublicIP</big>** : 判断ip是否是公共ip。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)]
[[play](https://go.dev/play/p/nmktSQpJZnn)]
- **<big>IsInternalIP</big>** : 判断ip是否是局域网ip。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)]
[[play](https://go.dev/play/p/sYGhXbgO4Cb)]
- **<big>HttpRequest</big>** : 用于抽象HTTP请求实体的结构。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>HttpClient</big>** : 用于发送HTTP请求。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpClient)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>SendRequest</big>** : 发送http请求。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>DecodeResponse</big>** : 解析http响应体到目标结构体。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>StructToUrlValues</big>** : 将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)]
[[play](https://go.dev/play/p/pFqMkM40w9z)]
- **<big>HttpGet<sup>deprecated</sup></big>** : 发送http get请求已弃用SendRequest代替
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)]
- **<big>HttpDelete<sup>deprecated</sup></big>** : 发送http delete请求已弃用SendRequest代替
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)]
- **<big>HttpPost<sup>deprecated</sup></big>** : 发送http post请求已弃用SendRequest代替
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)]
- **<big>HttpPut<sup>deprecated</sup></big>** : 发送http put请求已弃用SendRequest代替
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)]
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送http patch请求已弃用SendRequest代替
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)]
- **<big>ParseHttpResponse</big>** : 解析http响应体到目标结构体。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。 ### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
@@ -695,6 +839,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Contain</big>** : 判断slice是否包含value。 - **<big>Contain</big>** : 判断slice是否包含value。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)]
[[play](https://go.dev/play/p/_454yEHcNjf)] [[play](https://go.dev/play/p/_454yEHcNjf)]
- **<big>ContainBy</big>** : 根据predicate函数判断切片是否包含某个值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
- **<big>ContainSubSlice</big>** : 判断slice是否包含subslice。 - **<big>ContainSubSlice</big>** : 判断slice是否包含subslice。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
[[play](https://go.dev/play/p/bcuQ3UT6Sev)] [[play](https://go.dev/play/p/bcuQ3UT6Sev)]
@@ -725,9 +871,18 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。 - **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)] [[play](https://go.dev/play/p/pJ-d6MUWcvK)]
- **<big>Drop</big>** : 创建一个切片当n > 0时从开头删除n个元素或者当n < 0时从结尾删除n个元素。 - **<big>Drop</big>** : 从切片头部删除n个元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)] [[play](https://go.dev/play/p/jnPO2yQsT8H)]
- **<big>DropRight</big>** : 从切片尾部删除n个元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRight)]
[[play](https://go.dev/play/p/8bcXvywZezG)]
- **<big>DropWhile</big>** : 从切片的头部删除n个元素这个n个元素满足predicate函数返回true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropWhile)]
[[play](https://go.dev/play/p/4rt252UV_qs)]
- **<big>DropRightWhile</big>** : 从切片的尾部删除n个元素这个n个元素满足predicate函数返回true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRightWhile)]
[[play](https://go.dev/play/p/6wyK3zMY56e)]
- **<big>Equal</big>** : 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。 - **<big>Equal</big>** : 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Equal)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Equal)]
[[play](https://go.dev/play/p/WcRQJ37ifPa)] [[play](https://go.dev/play/p/WcRQJ37ifPa)]
@@ -740,6 +895,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Filter</big>** : 返回切片中通过predicate函数真值测试的所有元素。 - **<big>Filter</big>** : 返回切片中通过predicate函数真值测试的所有元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)]
[[play](https://go.dev/play/p/SdPna-7qK4T)] [[play](https://go.dev/play/p/SdPna-7qK4T)]
- **<big>FilterMap</big>** : 返回一个将filter和map操作应用于给定切片的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
- **<big>Find</big>** : 遍历切片的元素返回第一个通过predicate函数真值测试的元素。 - **<big>Find</big>** : 遍历切片的元素返回第一个通过predicate函数真值测试的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
[[play](https://go.dev/play/p/CBKeBoHVLgq)] [[play](https://go.dev/play/p/CBKeBoHVLgq)]
@@ -752,6 +909,8 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>FlattenDeep</big>** : 将多维切片递归展平到一层。 - **<big>FlattenDeep</big>** : 将多维切片递归展平到一层。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlattenDeep)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlattenDeep)]
[[play](https://go.dev/play/p/yjYNHPyCFaF)] [[play](https://go.dev/play/p/yjYNHPyCFaF)]
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用iteratee函数。 - **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用iteratee函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
[[play](https://go.dev/play/p/DrPaa4YsHRF)] [[play](https://go.dev/play/p/DrPaa4YsHRF)]
@@ -803,6 +962,18 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。 - **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)]
[[play](https://go.dev/play/p/YHvhnWGU3Ge)] [[play](https://go.dev/play/p/YHvhnWGU3Ge)]
- **<big>IsAscending</big>** : 检查切片元素是否按升序排列。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsAscending)]
[[play](https://go.dev/play/p/9CtsFjet4SH)]
- **<big>IsDescending</big>** : 检查切片元素是否按降序排列。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsDescending)]
[[play](https://go.dev/play/p/U_LljFXma14)]
- **<big>IsSorted</big>** : 检查切片元素是否是有序的(升序或降序)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSorted)]
[[play](https://go.dev/play/p/nCE8wPLwSA-)]
- **<big>IsSortedByKey</big>** : 通过iteratee函数检查切片元素是否是有序的。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSortedByKey)]
[[play](https://go.dev/play/p/tUoGB7DOHI4)]
- **<big>Sort</big>** : 对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。 - **<big>Sort</big>** : 对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Sort)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Sort)]
[[play](https://go.dev/play/p/V9AVjzf_4Fk)] [[play](https://go.dev/play/p/V9AVjzf_4Fk)]
@@ -891,6 +1062,8 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>UpperFirst</big>** : 将字符串的第一个字符转换为大写形式。 - **<big>UpperFirst</big>** : 将字符串的第一个字符转换为大写形式。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)]
[[play](https://go.dev/play/p/sBbBxRbs8MM)] [[play](https://go.dev/play/p/sBbBxRbs8MM)]
- **<big>Pad</big>** : 如果字符串长度短于size则在左右两侧填充字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。 - **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
[[play](https://go.dev/play/p/9xP8rN0vz--)] [[play](https://go.dev/play/p/9xP8rN0vz--)]
@@ -911,12 +1084,17 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/Us-ySSbWh-3)] [[play](https://go.dev/play/p/Us-ySSbWh-3)]
- **<big>Substring</big>** : 根据指定的位置和长度截取子字符串。 - **<big>Substring</big>** : 根据指定的位置和长度截取子字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)]
[[play](https://go.dev/play/p/q3sM6ehnPDp)]
- **<big>Wrap</big>** : 用给定字符包裹传入的字符串 - **<big>Wrap</big>** : 用给定字符包裹传入的字符串
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)]
[[play](https://go.dev/play/p/KoZOlZDDt9y)] [[play](https://go.dev/play/p/KoZOlZDDt9y)]
- **<big>Unwrap</big>** : 从另一个字符串中解开一个给定的字符串。 将更改源字符串。 - **<big>Unwrap</big>** : 从另一个字符串中解开一个给定的字符串。 将更改源字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)]
[[play](https://go.dev/play/p/Ec2q4BzCpG-)] [[play](https://go.dev/play/p/Ec2q4BzCpG-)]
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
### 18. system 包含 os, runtime, shell command 的相关函数。 ### 18. system 包含 os, runtime, shell command 的相关函数。
@@ -1056,7 +1234,46 @@ import "github.com/duke-git/lancet/v2/xerror"
#### 函数列表: #### 函数列表:
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap) - **<big>New</big>** : 创建XError对象实例。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#New)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>Wrap</big>** : 根据error对象创建XError对象实例可添加message。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>Unwrap</big>** : 从error对象中解构出XError。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)]
[[play](https://go.dev/play/p/LKMLep723tu)]
- **<big>XError_Wrap</big>** : 创建新的XError对象并将消息和id复制到新的对象中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>XError_Unwrap</big>** : 解构XEerror为error对象。适配github.com/pkg/errors。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Unwrap)]
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
- **<big>XError_With</big>** : 添加与XError对象的键和值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_With)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_Id</big>** : 设置XError对象的id。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Id)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Is</big>** : 检查目标error是否为XError两个错误中的error.id是否匹配。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Is)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Values</big>** : 返回由With设置的键和值的映射。将合并所有XError键和值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Values)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_StackTrace</big>** : 返回与pkg/error兼容的堆栈信息。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_StackTrace)]
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
- **<big>XError_Info</big>** : 返回可打印的XError对象信息。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Info)]
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
- **<big>XError_Error</big>** : 实现标准库的error接口。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Error)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>TryUnwrap</big>** : 检查error, 如果err为nil则展开则它返回一个有效值如果err不是nil则Unwrap使用err发生panic。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
[[play](https://go.dev/play/p/acyZVkNZEeW)]
## 如何贡献代码 ## 如何贡献代码

View File

@@ -10,7 +10,7 @@ import "github.com/duke-git/lancet/v2/lancetconstraints"
// LinearSearch return the index of target in slice base on equal function. // LinearSearch return the index of target in slice base on equal function.
// If not found return -1 // If not found return -1
// Play: Todo // Play: https://go.dev/play/p/IsS7rgn5s3x
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int { func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
for i, v := range slice { for i, v := range slice {
if equal(v, target) { if equal(v, target) {

View File

@@ -20,7 +20,7 @@ func NewChannel[T any]() *Channel[T] {
} }
// Generate creates channel, then put values into the channel. // Generate creates channel, then put values into the channel.
// Play: Todo // Play: https://go.dev/play/p/7aB4KyMMp9A
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T { func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T) dataStream := make(chan T)
@@ -40,7 +40,7 @@ func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
} }
// Repeat create channel, put values into the channel repeatly until cancel the context. // Repeat create channel, put values into the channel repeatly until cancel the context.
// Play: Todo // Play: https://go.dev/play/p/k5N_ALVmYjE
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T { func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T) dataStream := make(chan T)
@@ -61,7 +61,7 @@ func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel // RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
// until close context. // until close context.
// Play: Todo // Play: https://go.dev/play/p/4J1zAWttP85
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T { func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
dataStream := make(chan T) dataStream := make(chan T)
@@ -79,7 +79,7 @@ func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
} }
// Take create a channel whose values are taken from another channel with limit number. // Take create a channel whose values are taken from another channel with limit number.
// Play: Todo // Play: https://go.dev/play/p/9Utt-1pDr2J
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T { func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
takeStream := make(chan T) takeStream := make(chan T)
@@ -99,7 +99,7 @@ func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int)
} }
// FanIn merge multiple channels into one channel. // FanIn merge multiple channels into one channel.
// Play: Todo // Play: https://go.dev/play/p/2VYFMexEvTm
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T { func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
out := make(chan T) out := make(chan T)
@@ -127,7 +127,7 @@ func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
} }
// Tee split one chanel into two channels, until cancel the context. // Tee split one chanel into two channels, until cancel the context.
// Play: Todo // Play: https://go.dev/play/p/3TQPKnCirrP
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) { func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
out1 := make(chan T) out1 := make(chan T)
out2 := make(chan T) out2 := make(chan T)
@@ -154,7 +154,7 @@ func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
} }
// Bridge link multiply channels into one channel. // Bridge link multiply channels into one channel.
// Play: Todo // Play: https://go.dev/play/p/qmWSy1NVF-Y
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T { func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
valStream := make(chan T) valStream := make(chan T)
@@ -186,7 +186,7 @@ func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-c
} }
// Or read one or more channels into one channel, will close when any readin channel is closed. // Or read one or more channels into one channel, will close when any readin channel is closed.
// Play: Todo // Play: https://go.dev/play/p/Wqz9rwioPww
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T { func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
switch len(channels) { switch len(channels) {
case 0: case 0:
@@ -220,7 +220,7 @@ func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
} }
// OrDone read a channel into another channel, will close until cancel context. // OrDone read a channel into another channel, will close until cancel context.
// Play: Todo // Play: https://go.dev/play/p/lm_GoS6aDjo
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T { func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
valStream := make(chan T) valStream := make(chan T)

View File

@@ -9,6 +9,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/gob" "encoding/gob"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math" "math"
"reflect" "reflect"
@@ -324,3 +325,62 @@ func DecodeByte(data []byte, target any) error {
decoder := gob.NewDecoder(buffer) decoder := gob.NewDecoder(buffer)
return decoder.Decode(target) return decoder.Decode(target)
} }
// DeepClone creates a deep copy of passed item.
// can't clone unexported field of struct
// Play: https://go.dev/play/p/j4DP5dquxnk
func DeepClone[T any](src T) T {
c := cloner{
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
}
result := c.clone(reflect.ValueOf(src))
if result.Kind() == reflect.Invalid {
var zeroValue T
return zeroValue
}
return result.Interface().(T)
}
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// Play: todo
func CopyProperties[T, U any](dst T, src U) (err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(fmt.Sprintf("%v", e))
}
}()
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("CopyProperties: param dst should be struct pointer")
}
if srcType.Kind() == reflect.Ptr {
srcType, srcValue = srcType.Elem(), srcValue.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("CopyProperties: param src should be a struct or struct pointer")
}
dstType, dstValue = dstType.Elem(), dstValue.Elem()
propertyNums := dstType.NumField()
for i := 0; i < propertyNums; i++ {
property := dstType.Field(i)
propertyValue := srcValue.FieldByName(property.Name)
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
continue
}
if dstValue.Field(i).CanSet() {
dstValue.Field(i).Set(propertyValue)
}
}
return nil
}

View File

@@ -252,3 +252,88 @@ func ExampleDecodeByte() {
// Output: // Output:
// abc // abc
} }
func ExampleDeepClone() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
func ExampleCopyProperties() {
type Address struct {
Country string
ZipCode string
}
type User struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
type Employee struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
employee1 := Employee{}
CopyProperties(&employee1, &user)
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
CopyProperties(&employee2, &user)
fmt.Println(employee1)
fmt.Println(employee2)
// Output:
// {user001 10 Admin {CN 001} [a b] 0}
// {user001 10 Admin {CN 001} [a b] 500}
}

View File

@@ -0,0 +1,216 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package convertor implements some functions to convert data.
package convertor
import "reflect"
type cloner struct {
ptrs map[reflect.Type]map[uintptr]reflect.Value
}
// clone return a duplicate of passed item.
func (c *cloner) clone(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Invalid:
return reflect.ValueOf(nil)
// bool
case reflect.Bool:
return reflect.ValueOf(v.Bool())
//int
case reflect.Int:
return reflect.ValueOf(int(v.Int()))
case reflect.Int8:
return reflect.ValueOf(int8(v.Int()))
case reflect.Int16:
return reflect.ValueOf(int16(v.Int()))
case reflect.Int32:
return reflect.ValueOf(int32(v.Int()))
case reflect.Int64:
return reflect.ValueOf(v.Int())
// uint
case reflect.Uint:
return reflect.ValueOf(uint(v.Uint()))
case reflect.Uint8:
return reflect.ValueOf(uint8(v.Uint()))
case reflect.Uint16:
return reflect.ValueOf(uint16(v.Uint()))
case reflect.Uint32:
return reflect.ValueOf(uint32(v.Uint()))
case reflect.Uint64:
return reflect.ValueOf(v.Uint())
// float
case reflect.Float32:
return reflect.ValueOf(float32(v.Float()))
case reflect.Float64:
return reflect.ValueOf(v.Float())
// complex
case reflect.Complex64:
return reflect.ValueOf(complex64(v.Complex()))
case reflect.Complex128:
return reflect.ValueOf(v.Complex())
// string
case reflect.String:
return reflect.ValueOf(v.String())
// array
case reflect.Array, reflect.Slice:
return c.cloneArray(v)
// map
case reflect.Map:
return c.cloneMap(v)
// Ptr
case reflect.Ptr:
return c.clonePtr(v)
// struct
case reflect.Struct:
return c.cloneStruct(v)
// func
case reflect.Func:
return v
// interface
case reflect.Interface:
return c.clone(v.Elem())
}
return reflect.Zero(v.Type())
}
func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
arr := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
val := c.clone(v.Index(i))
if val.IsValid() {
continue
}
item := arr.Index(i)
if !item.CanSet() {
continue
}
item.Set(val.Convert(item.Type()))
}
return arr
}
func (c *cloner) cloneMap(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
clonedMap := reflect.MakeMap(v.Type())
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
clonedKey := c.clone(key)
clonedValue := c.clone(value)
if !isNillable(clonedKey) || !clonedKey.IsNil() {
clonedKey = clonedKey.Convert(key.Type())
}
if (!isNillable(clonedValue) || !clonedValue.IsNil()) && clonedValue.IsValid() {
clonedValue = clonedValue.Convert(value.Type())
}
if !clonedValue.IsValid() {
clonedValue = reflect.Zero(clonedMap.Type().Elem())
}
clonedMap.SetMapIndex(clonedKey, clonedValue)
}
return clonedMap
}
func isNillable(v reflect.Value) bool {
switch v.Kind() {
case reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func:
return true
}
return false
}
func (c *cloner) clonePtr(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
var newVal reflect.Value
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
newVal = c.clone(v.Elem())
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
clonedPtr := reflect.New(newVal.Type())
clonedPtr.Elem().Set(newVal)
return clonedPtr
}
func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
clonedStructPtr := reflect.New(v.Type())
clonedStruct := clonedStructPtr.Elem()
if v.CanAddr() {
ptrs := c.ptrs[clonedStructPtr.Type()]
if ptrs == nil {
ptrs = make(map[uintptr]reflect.Value)
c.ptrs[clonedStructPtr.Type()] = ptrs
}
ptrs[v.UnsafeAddr()] = clonedStructPtr
}
for i := 0; i < v.NumField(); i++ {
newStructValue := clonedStruct.Field(i)
if !newStructValue.CanSet() {
continue
}
clonedVal := c.clone(v.Field(i))
if !clonedVal.IsValid() {
continue
}
newStructValue.Set(clonedVal.Convert(newStructValue.Type()))
}
return clonedStruct
}

View File

@@ -2,6 +2,7 @@ package convertor
import ( import (
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"testing" "testing"
@@ -253,3 +254,97 @@ func TestDecodeByte(t *testing.T) {
assert.IsNil(err) assert.IsNil(err)
assert.Equal("abc", obj) assert.Equal("abc", obj)
} }
func TestDeepClone(t *testing.T) {
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for i, item := range cases {
cloned := DeepClone(item)
t.Log(cloned)
if &cloned == &item {
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
}
if !reflect.DeepEqual(item, cloned) {
t.Fatalf("[TestDeepClone case #%d failed] unequal objects", i)
}
}
}
func TestCopyProperties(t *testing.T) {
assert := internal.NewAssert(t, "TestCopyProperties")
type Address struct {
Country string
ZipCode string
}
type User struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
type Employee struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
employee1 := Employee{}
err := CopyProperties(&employee1, &user)
assert.IsNil(err)
assert.Equal("user001", employee1.Name)
assert.Equal("Admin", employee1.Role)
assert.Equal("CN", employee1.Addr.Country)
assert.Equal(0, employee1.salary)
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
err = CopyProperties(&employee2, &user)
assert.IsNil(err)
assert.Equal("user001", employee2.Name)
assert.Equal("Admin", employee2.Role)
assert.Equal("CN", employee2.Addr.Country)
assert.Equal(500, employee2.salary)
}

View File

@@ -2,11 +2,11 @@ package cryptor
import "bytes" import "bytes"
func generateAesKey(key []byte) []byte { func generateAesKey(key []byte, size int) []byte {
genKey := make([]byte, 16) genKey := make([]byte, size)
copy(genKey, key) copy(genKey, key)
for i := 16; i < len(key); { for i := size; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 { for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i] genKey[j] ^= key[i]
} }
} }

View File

@@ -23,6 +23,11 @@ import (
// len(key) should be 16, 24 or 32. // len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j // Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbEncrypt(data, key []byte) []byte { func AesEcbEncrypt(data, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
length := (len(data) + aes.BlockSize) / aes.BlockSize length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize) plain := make([]byte, length*aes.BlockSize)
@@ -34,7 +39,7 @@ func AesEcbEncrypt(data, key []byte) []byte {
} }
encrypted := make([]byte, len(plain)) encrypted := make([]byte, len(plain))
cipher, _ := aes.NewCipher(generateAesKey(key)) cipher, _ := aes.NewCipher(generateAesKey(key, size))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be]) cipher.Encrypt(encrypted[bs:be], plain[bs:be])
@@ -47,7 +52,11 @@ func AesEcbEncrypt(data, key []byte) []byte {
// len(key) should be 16, 24 or 32. // len(key) should be 16, 24 or 32.
// Play: https://go.dev/play/p/jT5irszHx-j // Play: https://go.dev/play/p/jT5irszHx-j
func AesEcbDecrypt(encrypted, key []byte) []byte { func AesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := aes.NewCipher(generateAesKey(key)) size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
decrypted := make([]byte, len(encrypted)) decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {

View File

@@ -6,6 +6,8 @@ package datastructure
import ( import (
"reflect" "reflect"
"github.com/duke-git/lancet/v2/iterator"
) )
// List is a linear table, implemented with slice. // List is a linear table, implemented with slice.
@@ -316,6 +318,43 @@ func (l *List[T]) Intersection(other *List[T]) *List[T] {
return result return result
} }
// Difference returns the difference between two collections.
// return a list whose element in the original list, not in the given list.
func (l *List[T]) Difference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SymmetricDifference oppoiste operation of intersection function.
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T] {
result := NewList(make([]T, 0))
intersectList := l.Intersection(other)
for _, v := range l.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
for _, v := range other.data {
if !intersectList.Contain(v) {
result.data = append(result.data, v)
}
}
return result
}
// SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive. // SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] { func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
data := l.data[fromIndex:toIndex] data := l.data[fromIndex:toIndex]
@@ -323,3 +362,57 @@ func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
copy(subList, data) copy(subList, data)
return NewList(subList) return NewList(subList)
} }
// ForEach performs the given action for each element of the list.
func (l *List[T]) ForEach(consumer func(T)) {
for _, it := range l.data {
consumer(it)
}
}
// RetainAll retains only the elements in this list that are contained in the given list.
func (l *List[T]) RetainAll(list *List[T]) bool {
return l.batchRemove(list, true)
}
// DeleteAll removes from this list all of its elements that are contained in the given list.
func (l *List[T]) DeleteAll(list *List[T]) bool {
return l.batchRemove(list, false)
}
func (l *List[T]) batchRemove(list *List[T], complement bool) bool {
var (
w = 0
data = l.data
size = len(data)
)
for i := 0; i < size; i++ {
if list.Contain(data[i]) == complement {
data[w] = data[i]
w++
}
}
if w != size {
l.data = data[:w]
return true
}
return false
}
// Iterator returns an iterator over the elements in this list in proper sequence.
func (l *List[T]) Iterator() iterator.Iterator[T] {
return iterator.FromSlice(l.data)
}
// ListToMap convert a list to a map based on iteratee function.
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, list.Size())
for _, item := range list.data {
k, v := iteratee(item)
result[k] = v
}
return result
}

View File

@@ -328,6 +328,28 @@ func TestIntersection(t *testing.T) {
assert.Equal(true, expected.Equal(list3)) assert.Equal(true, expected.Equal(list3))
} }
func TestDifference(t *testing.T) {
assert := internal.NewAssert(t, "TestDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3})
list3 := list1.Difference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSymmetricDifference(t *testing.T) {
assert := internal.NewAssert(t, "TestSymmetricDifference")
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
expected := NewList([]int{3, 4})
list3 := list1.SymmetricDifference(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) { func TestSubSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestSubSlice") assert := internal.NewAssert(t, "TestSubSlice")
@@ -357,3 +379,84 @@ func TestDeleteIf(t *testing.T) {
assert.Equal([]int{2, 3, 4}, list.Data()) assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(0, count) assert.Equal(0, count)
} }
func TestForEach(t *testing.T) {
assert := internal.NewAssert(t, "TestForEach")
list := NewList([]int{1, 2, 3, 4})
rs := make([]int, 0)
list.ForEach(func(i int) {
rs = append(rs, i)
})
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestRetainAll(t *testing.T) {
assert := internal.NewAssert(t, "TestRetainAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
assert.Equal([]int{1, 2}, list.Data())
assert.Equal([]int{2, 3}, list1.Data())
assert.Equal([]int{1, 2}, list2.Data())
}
func TestDeleteAll(t *testing.T) {
assert := internal.NewAssert(t, "TestDeleteAll")
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal([]int{1, 4}, list1.Data())
assert.Equal([]int{3, 4}, list2.Data())
}
func TestIterator(t *testing.T) {
assert := internal.NewAssert(t, "TestIterator")
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
rs := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
rs = append(rs, item)
}
assert.Equal([]int{1, 2, 3, 4}, rs)
}
func TestListToMap(t *testing.T) {
assert := internal.NewAssert(t, "ListToMap")
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
expected := map[int]bool{1: false, 2: true, 3: true, 4: true}
assert.Equal(expected, result)
}

View File

@@ -9,17 +9,20 @@ type theTime struct {
unix int64 unix int64
} }
// NewUnixNow return unix timestamp of current time // NewUnixNow return unix timestamp of current time.
// Play: https://go.dev/play/p/U4PPx-9D0oz
func NewUnixNow() *theTime { func NewUnixNow() *theTime {
return &theTime{unix: time.Now().Unix()} return &theTime{unix: time.Now().Unix()}
} }
// NewUnix return unix timestamp of specified time // NewUnix return unix timestamp of specified time.
// Play: https://go.dev/play/p/psoSuh_kLRt
func NewUnix(unix int64) *theTime { func NewUnix(unix int64) *theTime {
return &theTime{unix: unix} return &theTime{unix: unix}
} }
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss" // NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".
// Play: https://go.dev/play/p/VkW08ZOaXPZ
func NewFormat(t string) (*theTime, error) { func NewFormat(t string) (*theTime, error) {
timeLayout := "2006-01-02 15:04:05" timeLayout := "2006-01-02 15:04:05"
loc := time.FixedZone("CST", 8*3600) loc := time.FixedZone("CST", 8*3600)
@@ -30,7 +33,8 @@ func NewFormat(t string) (*theTime, error) {
return &theTime{unix: tt.Unix()}, nil return &theTime{unix: tt.Unix()}, nil
} }
// NewISO8601 return unix timestamp of specified iso8601 time string // NewISO8601 return unix timestamp of specified iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
func NewISO8601(iso8601 string) (*theTime, error) { func NewISO8601(iso8601 string) (*theTime, error) {
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC) t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
if err != nil { if err != nil {
@@ -39,22 +43,26 @@ func NewISO8601(iso8601 string) (*theTime, error) {
return &theTime{unix: t.Unix()}, nil return &theTime{unix: t.Unix()}, nil
} }
// ToUnix return unix timestamp // ToUnix return unix timestamp.
// Play: https://go.dev/play/p/_LUiwAdocjy
func (t *theTime) ToUnix() int64 { func (t *theTime) ToUnix() int64 {
return t.unix return t.unix
} }
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time // ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time.
// Play: https://go.dev/play/p/VkW08ZOaXPZ
func (t *theTime) ToFormat() string { func (t *theTime) ToFormat() string {
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05") return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
} }
// ToFormatForTpl return the time string which format is specified tpl // ToFormatForTpl return the time string which format is specified tpl.
// Play: https://go.dev/play/p/nyXxXcQJ8L5
func (t *theTime) ToFormatForTpl(tpl string) string { func (t *theTime) ToFormatForTpl(tpl string) string {
return time.Unix(t.unix, 0).Format(tpl) return time.Unix(t.unix, 0).Format(tpl)
} }
// ToFormatForTpl return iso8601 time string // ToFormatForTpl return iso8601 time string.
// Play: https://go.dev/play/p/mkhOHQkdeA2
func (t *theTime) ToIso8601() string { func (t *theTime) ToIso8601() string {
return time.Unix(t.unix, 0).Format(time.RFC3339) return time.Unix(t.unix, 0).Format(time.RFC3339)
} }

View File

@@ -19,9 +19,6 @@ func TestToUnix(t *testing.T) {
func TestToFormat(t *testing.T) { func TestToFormat(t *testing.T) {
assert := internal.NewAssert(t, "TestToFormat") assert := internal.NewAssert(t, "TestToFormat")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05") tm, err := NewFormat("2022-03-18 17:04:05")
assert.IsNil(err) assert.IsNil(err)

View File

@@ -54,54 +54,64 @@ func init() {
} }
} }
// AddMinute add or sub minute to the time // AddMinute add or sub minute to the time.
// Play: https://go.dev/play/p/nT1heB1KUUK
func AddMinute(t time.Time, minute int64) time.Time { func AddMinute(t time.Time, minute int64) time.Time {
return t.Add(time.Minute * time.Duration(minute)) return t.Add(time.Minute * time.Duration(minute))
} }
// AddHour add or sub hour to the time // AddHour add or sub hour to the time.
// Play: https://go.dev/play/p/rcMjd7OCsi5
func AddHour(t time.Time, hour int64) time.Time { func AddHour(t time.Time, hour int64) time.Time {
return t.Add(time.Hour * time.Duration(hour)) return t.Add(time.Hour * time.Duration(hour))
} }
// AddDay add or sub day to the time // AddDay add or sub day to the time.
// Play: https://go.dev/play/p/dIGbs_uTdFa
func AddDay(t time.Time, day int64) time.Time { func AddDay(t time.Time, day int64) time.Time {
return t.Add(24 * time.Hour * time.Duration(day)) return t.Add(24 * time.Hour * time.Duration(day))
} }
// GetNowDate return format yyyy-mm-dd of current date // GetNowDate return format yyyy-mm-dd of current date.
// Play: https://go.dev/play/p/PvfkPpcpBBf
func GetNowDate() string { func GetNowDate() string {
return time.Now().Format("2006-01-02") return time.Now().Format("2006-01-02")
} }
// GetNowTime return format hh-mm-ss of current time // GetNowTime return format hh-mm-ss of current time.
// Play: https://go.dev/play/p/l7BNxCkTmJS
func GetNowTime() string { func GetNowTime() string {
return time.Now().Format("15:04:05") return time.Now().Format("15:04:05")
} }
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime // GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime.
// Play: https://go.dev/play/p/pI4AqngD0al
func GetNowDateTime() string { func GetNowDateTime() string {
return time.Now().Format("2006-01-02 15:04:05") return time.Now().Format("2006-01-02 15:04:05")
} }
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00) // GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
// Play: https://go.dev/play/p/QmL2oIaGE3q
func GetZeroHourTimestamp() int64 { func GetZeroHourTimestamp() int64 {
ts := time.Now().Format("2006-01-02") ts := time.Now().Format("2006-01-02")
t, _ := time.Parse("2006-01-02", ts) t, _ := time.Parse("2006-01-02", ts)
return t.UTC().Unix() - 8*3600 return t.UTC().Unix() - 8*3600
} }
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59) // GetNightTimestamp return timestamp of zero hour (timestamp of 23:59).
// Play: https://go.dev/play/p/UolysR3MYP1
func GetNightTimestamp() int64 { func GetNightTimestamp() int64 {
return GetZeroHourTimestamp() + 86400 - 1 return GetZeroHourTimestamp() + 86400 - 1
} }
// FormatTimeToStr convert time to string // FormatTimeToStr convert time to string.
// Play: https://go.dev/play/p/_Ia7M8H_OvE
func FormatTimeToStr(t time.Time, format string) string { func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format]) return t.Format(timeFormat[format])
} }
// FormatStrToTime convert string to time // FormatStrToTime convert string to time.
// Play: https://go.dev/play/p/1h9FwdU8ql4
func FormatStrToTime(str, format string) (time.Time, error) { func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format] v, ok := timeFormat[format]
if !ok { if !ok {
@@ -111,43 +121,50 @@ func FormatStrToTime(str, format string) (time.Time, error) {
return time.Parse(v, str) return time.Parse(v, str)
} }
// BeginOfMinute return beginning minute time of day // BeginOfMinute return beginning minute time of day.
// Play: https://go.dev/play/p/ieOLVJ9CiFT
func BeginOfMinute(t time.Time) time.Time { func BeginOfMinute(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location()) return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
} }
// EndOfMinute return end minute time of day // EndOfMinute return end minute time of day.
// Play: https://go.dev/play/p/yrL5wGzPj4z
func EndOfMinute(t time.Time) time.Time { func EndOfMinute(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location()) return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
} }
// BeginOfHour return beginning hour time of day // BeginOfHour return beginning hour time of day.
// Play: https://go.dev/play/p/GhdGFnDWpYs
func BeginOfHour(t time.Time) time.Time { func BeginOfHour(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location()) return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
} }
// EndOfHour return end hour time of day // EndOfHour return end hour time of day.
// Play: https://go.dev/play/p/6ce3j_6cVqN
func EndOfHour(t time.Time) time.Time { func EndOfHour(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location()) return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
} }
// BeginOfDay return beginning hour time of day // BeginOfDay return beginning hour time of day.
// Play: https://go.dev/play/p/94m_UT6cWs9
func BeginOfDay(t time.Time) time.Time { func BeginOfDay(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location()) return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
} }
// EndOfDay return end time of day // EndOfDay return end time of day.
// Play: https://go.dev/play/p/eMBOvmq5Ih1
func EndOfDay(t time.Time) time.Time { func EndOfDay(t time.Time) time.Time {
y, m, d := t.Date() y, m, d := t.Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location()) return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
} }
// BeginOfWeek return beginning week, default week begin from Sunday // BeginOfWeek return beginning week, default week begin from Sunday.
// Play: https://go.dev/play/p/ynjoJPz7VNV
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time { func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
var beginFromWeekday = time.Sunday var beginFromWeekday = time.Sunday
if len(beginFrom) > 0 { if len(beginFrom) > 0 {
@@ -161,7 +178,8 @@ func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
return beginOfWeek return beginOfWeek
} }
// EndOfWeek return end week time, default week end with Saturday // EndOfWeek return end week time, default week end with Saturday.
// Play: https://go.dev/play/p/i08qKXD9flf
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time { func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
var endWithWeekday = time.Saturday var endWithWeekday = time.Saturday
if len(endWith) > 0 { if len(endWith) > 0 {
@@ -175,24 +193,28 @@ func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
return endWithWeek return endWithWeek
} }
// BeginOfMonth return beginning of month // BeginOfMonth return beginning of month.
// Play: https://go.dev/play/p/bWXVFsmmzwL
func BeginOfMonth(t time.Time) time.Time { func BeginOfMonth(t time.Time) time.Time {
y, m, _ := t.Date() y, m, _ := t.Date()
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location()) return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
} }
// EndOfMonth return end of month // EndOfMonth return end of month.
// Play: https://go.dev/play/p/_GWh10B3Nqi
func EndOfMonth(t time.Time) time.Time { func EndOfMonth(t time.Time) time.Time {
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond) return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
} }
// BeginOfYear return beginning of year // BeginOfYear return the date time at the begin of year.
// Play: https://go.dev/play/p/i326DSwLnV8
func BeginOfYear(t time.Time) time.Time { func BeginOfYear(t time.Time) time.Time {
y, _, _ := t.Date() y, _, _ := t.Date()
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location()) return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
} }
// EndOfYear return end of year // EndOfYear return the date time at the end of year.
// Play: https://go.dev/play/p/G01cKlMCvNm
func EndOfYear(t time.Time) time.Time { func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond) return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
} }

View File

@@ -0,0 +1,323 @@
package datetime
import (
"fmt"
"reflect"
"time"
)
func ExampleAddDay() {
now := time.Now()
tomorrow := AddDay(now, 1)
diff1 := tomorrow.Sub(now)
yesterday := AddDay(now, -1)
diff2 := yesterday.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 24h0m0s
// -24h0m0s
}
func ExampleAddHour() {
now := time.Now()
after2Hours := AddHour(now, 2)
diff1 := after2Hours.Sub(now)
before2Hours := AddHour(now, -2)
diff2 := before2Hours.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2h0m0s
// -2h0m0s
}
func ExampleAddMinute() {
now := time.Now()
after2Minutes := AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
before2Minutes := AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2m0s
// -2m0s
}
func ExampleGetNowDate() {
result := GetNowDate()
expected := time.Now().Format("2006-01-02")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowTime() {
result := GetNowTime()
expected := time.Now().Format("15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
func ExampleGetNowDateTime() {
result := GetNowDateTime()
expected := time.Now().Format("2006-01-02 15:04:05")
fmt.Println(result == expected)
// Output:
// true
}
// func ExampleGetZeroHourTimestamp() {
// ts := GetZeroHourTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673107200
// }
// func ExampleGetNightTimestamp() {
// ts := GetNightTimestamp()
// fmt.Println(ts)
// // Output:
// // 1673193599
// }
func ExampleFormatTimeToStr() {
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
result1 := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss")
result2 := FormatTimeToStr(datetime, "yyyy-mm-dd")
result3 := FormatTimeToStr(datetime, "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
}
func ExampleFormatStrToTime() {
result1, _ := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
result2, _ := FormatStrToTime("2021-01-02", "yyyy-mm-dd")
result3, _ := FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08 +0000 UTC
// 2021-01-02 00:00:00 +0000 UTC
// 2021-01-02 16:04:08 +0000 UTC
}
func ExampleBeginOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:00 +0000 UTC
}
func ExampleEndOfMinute() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMinute(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:50:59.999999999 +0000 UTC
}
func ExampleBeginOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:00:00 +0000 UTC
}
func ExampleEndOfHour() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfHour(input)
fmt.Println(result)
// Output:
// 2023-01-08 18:59:59.999999999 +0000 UTC
}
func ExampleBeginOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfDay() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfDay(input)
fmt.Println(result)
// Output:
// 2023-01-08 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
}
func ExampleEndOfWeek() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfWeek(input)
fmt.Println(result)
// Output:
// 2023-01-14 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfMonth() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfMonth(input)
fmt.Println(result)
// Output:
// 2023-01-31 23:59:59.999999999 +0000 UTC
}
func ExampleBeginOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := BeginOfYear(input)
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
}
func ExampleEndOfYear() {
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
result := EndOfYear(input)
fmt.Println(result)
// Output:
// 2023-12-31 23:59:59.999999999 +0000 UTC
}
func ExampleNewUnix() {
result := NewUnix(1647597438)
fmt.Println(result)
// Output:
// &{1647597438}
}
func ExampleNewUnixNow() {
tm1 := NewUnixNow()
unixTimestamp := tm1.ToUnix()
tm2 := NewUnix(unixTimestamp)
fmt.Println(reflect.DeepEqual(tm1, tm2))
// Output:
// true
}
// func ExampleNewFormat() {
// tm, err := NewFormat("2022-03-18 17:04:05")
// if err != nil {
// return
// }
// result := tm.ToFormat()
// fmt.Println(result)
// // Output:
// // 2022-03-18 17:04:05
// }
// func ExampleNewISO8601() {
// tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
// if err != nil {
// return
// }
// result := tm.ToIso8601()
// fmt.Println(result)
// // Output:
// // 2006-01-02T23:04:05+08:00
// }

View File

@@ -52,8 +52,8 @@ func TestGetNowDate(t *testing.T) {
assert.Equal(expected, GetNowDate()) assert.Equal(expected, GetNowDate())
} }
func TestGetNotTime(t *testing.T) { func TestGetNowTime(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNotTime") assert := internal.NewAssert(t, "TestGetNowTime")
expected := time.Now().Format("15:04:05") expected := time.Now().Format("15:04:05")
assert.Equal(expected, GetNowTime()) assert.Equal(expected, GetNowTime())
} }
@@ -81,7 +81,6 @@ func TestFormatTimeToStr(t *testing.T) {
for i := 0; i < len(cases); i++ { for i := 0; i < len(cases); i++ {
actual := FormatTimeToStr(datetime, cases[i]) actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual) assert.Equal(expected[i], actual)
} }
} }

View File

@@ -1,4 +1,5 @@
# Algorithm # Algorithm
Package algorithm implements some basic algorithm. eg. sort, search. Package algorithm implements some basic algorithm. eg. sort, search.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -12,6 +13,7 @@ Package algorithm implements some basic algorithm. eg. sort, search.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage ## Usage
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
@@ -35,14 +37,12 @@ import (
- [LinearSearch](#LinearSearch) - [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache) - [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="BubbleSort">BubbleSort</span> ### <span id="BubbleSort">BubbleSort</span>
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -50,6 +50,7 @@ import (
```go ```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -60,10 +61,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -74,20 +74,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="InsertionSort">InsertionSort</span> ### <span id="InsertionSort">InsertionSort</span>
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -95,6 +98,7 @@ func main() {
```go ```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -105,17 +109,16 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type people struct {
type people struct {
Name string Name string
Age int Age int
} }
// PeopleAageComparator sort people slice by age field // PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{} type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator // Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int { func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people) p1, _ := v1.(people)
p2, _ := v2.(people) p2, _ := v2.(people)
@@ -125,34 +128,32 @@ func main() {
} else if p1.Age > p2.Age { } else if p1.Age > p2.Age {
return 1 return 1
} }
return 0 return 0
}
//decending order func main() {
// if p1.Age > p2.Age { peoples := []people{
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20}, {Name: "a", Age: 20},
{Name: "b", Age: 10}, {Name: "b", Age: 10},
{Name: "c", Age: 17}, {Name: "c", Age: 17},
{Name: "d", Age: 8}, {Name: "d", Age: 8},
{Name: "e", Age: 28}, {Name: "e", Age: 28},
} }
comparator := &peopleAgeComparator{} comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator) algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}] fmt.Println(peoples)
// Output:
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
} }
``` ```
### <span id="SelectionSort">SelectionSort</span> ### <span id="SelectionSort">SelectionSort</span>
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -160,6 +161,7 @@ func main() {
```go ```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -170,10 +172,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -184,20 +185,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="ShellSort">ShellSort</span> ### <span id="ShellSort">ShellSort</span>
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -205,6 +209,7 @@ func main() {
```go ```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -215,10 +220,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -229,20 +233,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="QuickSort">QuickSort</span> ### <span id="QuickSort">QuickSort</span>
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -250,6 +257,7 @@ func main() {
```go ```go
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator) func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -260,10 +268,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -274,20 +281,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="HeapSort">HeapSort</span> ### <span id="HeapSort">HeapSort</span>
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -295,6 +305,7 @@ func main() {
```go ```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -305,10 +316,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -319,20 +329,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="MergeSort">MergeSort</span> ### <span id="MergeSort">MergeSort</span>
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -340,6 +353,7 @@ func main() {
```go ```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -350,10 +364,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -364,19 +377,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="CountSort">CountSort</span> ### <span id="CountSort">CountSort</span>
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -384,6 +401,7 @@ func main() {
```go ```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -394,10 +412,10 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -408,20 +426,23 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6} sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="BinarySearch">BinarySearch</span> ### <span id="BinarySearch">BinarySearch</span>
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p> <p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -429,6 +450,7 @@ func main() {
```go ```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -439,10 +461,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -453,21 +474,26 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span> ### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p> <p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -475,6 +501,7 @@ func main() {
```go ```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -485,10 +512,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -499,29 +525,34 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="LinearSearch">LinearSearch</span> ### <span id="LinearSearch">LinearSearch</span>
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p>
<p>return the index of target in slice base on equal function.If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b> <b>Signature:</b>
```go ```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -533,35 +564,26 @@ import (
) )
func main() { func main() {
type intComparator struct{} numbers := []int{3, 4, 5, 3, 2, 1}
func (c *intComparator) Compare(v1 any, v2 any) int { equalFunc := func(a, b int) bool {
val1, _ := v1.(int) return a == b
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
comparator := &intComparator{} result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator) fmt.Println(result1)
fmt.Println(notFoundIndex) //-1 fmt.Println(result2)
// Output:
// 0
// -1
} }
``` ```
### <span id="LRUCache">LRUCache</span> ### <span id="LRUCache">LRUCache</span>
<p>LRUCache implements mem cache with lru.</p> <p>LRUCache implements mem cache with lru.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -573,6 +595,7 @@ func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int func (l *LRUCache[K, V]) Len() int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -588,14 +611,26 @@ func main() {
cache.Put(1, 1) cache.Put(1, 1)
cache.Put(2, 2) cache.Put(2, 2)
cache.Put(3, 3)
fmt.Println(cache.Len()) // 3 result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
v, ok := cache.Get(1) fmt.Println(result1, ok1)
fmt.Println(v, ok) // 1 true fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
ok = cache.Delete(1) fmt.Println(cache.Len())
fmt.Println(ok) // true
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Algorithm # Algorithm
algorithm算法包实现一些基本算法sortsearchlrucache。
algorithm 算法包实现一些基本算法sortsearchlrucache。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -12,6 +13,7 @@ algorithm算法包实现一些基本算法sortsearchlrucache。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法 ## 用法
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
@@ -35,22 +37,21 @@ import (
- [LinearSearch](#LinearSearch) - [LinearSearch](#LinearSearch)
- [LRUCache](#LRUCache) - [LRUCache](#LRUCache)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 文档 ## 文档
### <span id="BubbleSort">BubbleSort</span> ### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -60,10 +61,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -74,28 +74,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="InsertionSort">InsertionSort</span> ### <span id="InsertionSort">InsertionSort</span>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -105,17 +109,16 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type people struct {
type people struct {
Name string Name string
Age int Age int
} }
// PeopleAageComparator sort people slice by age field // PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{} type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator // Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int { func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people) p1, _ := v1.(people)
p2, _ := v2.(people) p2, _ := v2.(people)
@@ -125,42 +128,41 @@ func main() {
} else if p1.Age > p2.Age { } else if p1.Age > p2.Age {
return 1 return 1
} }
return 0 return 0
}
//decending order func main() {
// if p1.Age > p2.Age { peoples := []people{
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20}, {Name: "a", Age: 20},
{Name: "b", Age: 10}, {Name: "b", Age: 10},
{Name: "c", Age: 17}, {Name: "c", Age: 17},
{Name: "d", Age: 8}, {Name: "d", Age: 8},
{Name: "e", Age: 28}, {Name: "e", Age: 28},
} }
comparator := &peopleAgeComparator{} comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator) algorithm.InsertionSort(peoples, comparator)
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}] fmt.Println(peoples)
// Output:
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
} }
``` ```
### <span id="SelectionSort">SelectionSort</span> ### <span id="SelectionSort">SelectionSort</span>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -170,10 +172,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -184,28 +185,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="ShellSort">ShellSort</span> ### <span id="ShellSort">ShellSort</span>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -215,10 +220,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -229,28 +233,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="QuickSort">QuickSort</span> ### <span id="QuickSort">QuickSort</span>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -260,10 +268,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -274,28 +281,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="HeapSort">HeapSort</span> ### <span id="HeapSort">HeapSort</span>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -305,10 +316,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -319,28 +329,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="MergeSort">MergeSort</span> ### <span id="MergeSort">MergeSort</span>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -350,10 +364,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -364,27 +377,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="CountSort">CountSort</span> ### <span id="CountSort">CountSort</span>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator</p>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -394,10 +412,10 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -408,28 +426,32 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6} sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="BinarySearch">BinarySearch</span> ### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -439,10 +461,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -453,29 +474,35 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span> ### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -485,10 +512,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -499,30 +525,35 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="LinearSearch">LinearSearch</span> ### <span id="LinearSearch">LinearSearch</span>
<p>线性查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<p>基于传入的相等函数线性查找元素,返回元素索引,未找到元素返回-1。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -533,36 +564,27 @@ import (
) )
func main() { func main() {
type intComparator struct{} numbers := []int{3, 4, 5, 3, 2, 1}
func (c *intComparator) Compare(v1 any, v2 any) int { equalFunc := func(a, b int) bool {
val1, _ := v1.(int) return a == b
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
comparator := &intComparator{} result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator) fmt.Println(result1)
fmt.Println(notFoundIndex) //-1 fmt.Println(result2)
// Output:
// 0
// -1
} }
``` ```
### <span id="LRUCache">LRUCache</span> ### <span id="LRUCache">LRUCache</span>
<p>lru实现缓存</p>
<p>lru算法实现缓存。</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -573,7 +595,8 @@ func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int func (l *LRUCache[K, V]) Len() int
``` ```
<b>Example:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -588,14 +611,26 @@ func main() {
cache.Put(1, 1) cache.Put(1, 1)
cache.Put(2, 2) cache.Put(2, 2)
cache.Put(3, 3)
fmt.Println(cache.Len()) // 3 result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
v, ok := cache.Get(1) fmt.Println(result1, ok1)
fmt.Println(v, ok) // 1 true fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
ok = cache.Delete(1) fmt.Println(cache.Len())
fmt.Println(ok) // true
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
} }
``` ```

View File

@@ -61,8 +61,6 @@ func main() {
} }
``` ```
### <span id="Bridge">Bridge</span> ### <span id="Bridge">Bridge</span>
<p>Link multiple channels into one channel until cancel the context.</p> <p>Link multiple channels into one channel until cancel the context.</p>
@@ -105,6 +103,7 @@ func main() {
for v := range c.Bridge(ctx, genVals()) { for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -114,9 +113,6 @@ func main() {
} }
``` ```
### <span id="FanIn">FanIn</span> ### <span id="FanIn">FanIn</span>
<p>Merge multiple channels into one channel until cancel the context.</p> <p>Merge multiple channels into one channel until cancel the context.</p>
@@ -156,7 +152,6 @@ func main() {
} }
``` ```
### <span id="Repeat">Repeat</span> ### <span id="Repeat">Repeat</span>
<p>Create channel, put values into the channel repeatly until cancel the context.</p> <p>Create channel, put values into the channel repeatly until cancel the context.</p>
@@ -187,6 +182,7 @@ func main() {
for v := range intStream { for v := range intStream {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -195,8 +191,6 @@ func main() {
} }
``` ```
### <span id="Generate">Generate</span> ### <span id="Generate">Generate</span>
<p>Creates a channel, then put values into the channel.</p> <p>Creates a channel, then put values into the channel.</p>
@@ -269,6 +263,7 @@ func main() {
for v := range intStream { for v := range intStream {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// hello // hello
// hello // hello
@@ -276,8 +271,6 @@ func main() {
} }
``` ```
### <span id="Or">Or</span> ### <span id="Or">Or</span>
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p> <p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
@@ -321,9 +314,6 @@ func main() {
} }
``` ```
### <span id="OrDone">OrDone</span> ### <span id="OrDone">OrDone</span>
<p>Read a channel into another channel, will close until cancel context.</p> <p>Read a channel into another channel, will close until cancel context.</p>
@@ -354,6 +344,7 @@ func main() {
for v := range c.OrDone(ctx, intStream) { for v := range c.OrDone(ctx, intStream) {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 1 // 1
@@ -361,9 +352,6 @@ func main() {
} }
``` ```
### <span id="Take">Take</span> ### <span id="Take">Take</span>
<p>Create a channel whose values are taken from another channel with limit number.</p> <p>Create a channel whose values are taken from another channel with limit number.</p>
@@ -402,6 +390,7 @@ func main() {
for v := range intStream { for v := range intStream {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -409,8 +398,6 @@ func main() {
} }
``` ```
### <span id="Tee">Tee</span> ### <span id="Tee">Tee</span>
<p>Split one chanel into two channels, until cancel the context.</p> <p>Split one chanel into two channels, until cancel the context.</p>
@@ -444,6 +431,7 @@ func main() {
fmt.Println(v) fmt.Println(v)
fmt.Println(<-ch2) fmt.Println(<-ch2)
} }
// Output: // Output:
// 1 // 1
// 1 // 1

View File

@@ -46,7 +46,7 @@ import (
type Channel[T any] struct type Channel[T any] struct
func NewChannel[T any]() *Channel[T] func NewChannel[T any]() *Channel[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -61,8 +61,6 @@ func main() {
} }
``` ```
### <span id="Bridge">Bridge</span> ### <span id="Bridge">Bridge</span>
<p>将多个channel链接到一个channel直到取消上下文。</p> <p>将多个channel链接到一个channel直到取消上下文。</p>
@@ -72,7 +70,7 @@ func main() {
```go ```go
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -105,6 +103,7 @@ func main() {
for v := range c.Bridge(ctx, genVals()) { for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -114,9 +113,6 @@ func main() {
} }
``` ```
### <span id="FanIn">FanIn</span> ### <span id="FanIn">FanIn</span>
<p>将多个channel合并为一个channel直到取消上下文。</p> <p>将多个channel合并为一个channel直到取消上下文。</p>
@@ -126,7 +122,7 @@ func main() {
```go ```go
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -156,7 +152,6 @@ func main() {
} }
``` ```
### <span id="Generate">Generate</span> ### <span id="Generate">Generate</span>
<p>根据传入的值生成channel.</p> <p>根据传入的值生成channel.</p>
@@ -166,7 +161,7 @@ func main() {
```go ```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -204,7 +199,7 @@ func main() {
```go ```go
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -225,6 +220,7 @@ func main() {
for v := range intStream { for v := range intStream {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -233,9 +229,6 @@ func main() {
} }
``` ```
### <span id="RepeatFn">RepeatFn</span> ### <span id="RepeatFn">RepeatFn</span>
<p>返回一个channel重复执行函数fn并将结果放入返回的channel直到取消上下文。</p> <p>返回一个channel重复执行函数fn并将结果放入返回的channel直到取消上下文。</p>
@@ -245,7 +238,7 @@ func main() {
```go ```go
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -277,8 +270,6 @@ func main() {
} }
``` ```
### <span id="Or">Or</span> ### <span id="Or">Or</span>
<p>将一个或多个channel读取到一个channel中当任何读取channel关闭时将结束读取。</p> <p>将一个或多个channel读取到一个channel中当任何读取channel关闭时将结束读取。</p>
@@ -288,7 +279,7 @@ func main() {
```go ```go
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -322,9 +313,6 @@ func main() {
} }
``` ```
### <span id="OrDone">OrDone</span> ### <span id="OrDone">OrDone</span>
<p>将一个channel读入另一个channel直到取消上下文。</p> <p>将一个channel读入另一个channel直到取消上下文。</p>
@@ -334,7 +322,7 @@ func main() {
```go ```go
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -355,6 +343,7 @@ func main() {
for v := range c.OrDone(ctx, intStream) { for v := range c.OrDone(ctx, intStream) {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 1 // 1
@@ -362,9 +351,6 @@ func main() {
} }
``` ```
### <span id="Take">Take</span> ### <span id="Take">Take</span>
<p>返回一个channel其值从另一个channel获取直到取消上下文。</p> <p>返回一个channel其值从另一个channel获取直到取消上下文。</p>
@@ -374,7 +360,7 @@ func main() {
```go ```go
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -403,6 +389,7 @@ func main() {
for v := range intStream { for v := range intStream {
fmt.Println(v) fmt.Println(v)
} }
// Output: // Output:
// 1 // 1
// 2 // 2
@@ -410,8 +397,6 @@ func main() {
} }
``` ```
### <span id="Tee">Tee</span> ### <span id="Tee">Tee</span>
<p>将一个channel分成两个channel直到取消上下文。</p> <p>将一个channel分成两个channel直到取消上下文。</p>
@@ -421,7 +406,7 @@ func main() {
```go ```go
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -58,40 +58,51 @@ import (
func main() { func main() {
// bool // bool
fmt.Println(condition.Bool(false)) // false result1 := condition.Bool(false)
fmt.Println(condition.Bool(true)) // true result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer // integer
fmt.Println(condition.Bool(0)) // false result3 := condition.Bool(0)
fmt.Println(condition.Bool(1)) // true result4 := condition.Bool(1)
fmt.Println(result3) // false
// float fmt.Println(result4) // true
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string // string
fmt.Println(condition.Bool("")) // false result5 := condition.Bool("")
fmt.Println(condition.Bool(" ")) // true result6 := condition.Bool(" ")
fmt.Println(condition.Bool("0")) // true fmt.Println(result5) // false
fmt.Println(result6) // true
// slice // slice
var nums [2]int nums := []int{}
fmt.Println(condition.Bool(nums)) // false result7 := condition.Bool(nums)
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map nums = append(nums, 1, 2)
fmt.Println(condition.Bool(map[string]string{})) // false result8 := condition.Bool(nums)
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true fmt.Println(result7) // false
fmt.Println(result8) // true
// struct // struct
fmt.Println(condition.Bool(struct{}{})) // false result9 = condition.Bool(struct{}{})
fmt.Println(condition.Bool(time.Now())) // true fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
} }
``` ```
### <span id="And">And</span> ### <span id="And">And</span>
<p>Returns true if both a and b are truthy.</p> <p>Returns true if both a and b are truthy.</p>
@@ -277,10 +288,18 @@ import (
) )
func main() { func main() {
trueValue := "1" conditionTrue := 2 > 1
falseValue := "0" result1 := condition.TernaryOperator(conditionTrue, 0, 1)
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1" conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
} }
``` ```

View File

@@ -45,7 +45,7 @@ slices和map的length大于0时返回true否则返回false<br/>
```go ```go
func Bool[T any](value T) bool func Bool[T any](value T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -57,40 +57,50 @@ import (
func main() { func main() {
// bool // bool
fmt.Println(condition.Bool(false)) // false result1 := condition.Bool(false)
fmt.Println(condition.Bool(true)) // true result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer // integer
fmt.Println(condition.Bool(0)) // false result3 := condition.Bool(0)
fmt.Println(condition.Bool(1)) // true result4 := condition.Bool(1)
fmt.Println(result3) // false
// float fmt.Println(result4) // true
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string // string
fmt.Println(condition.Bool("")) // false result5 := condition.Bool("")
fmt.Println(condition.Bool(" ")) // true result6 := condition.Bool(" ")
fmt.Println(condition.Bool("0")) // true fmt.Println(result5) // false
fmt.Println(result6) // true
// slice // slice
var nums [2]int nums := []int{}
fmt.Println(condition.Bool(nums)) // false result7 := condition.Bool(nums)
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map nums = append(nums, 1, 2)
fmt.Println(condition.Bool(map[string]string{})) // false result8 := condition.Bool(nums)
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true fmt.Println(result7) // false
fmt.Println(result8) // true
// struct // struct
fmt.Println(condition.Bool(struct{}{})) // false result9 = condition.Bool(struct{}{})
fmt.Println(condition.Bool(time.Now())) // true fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
} }
``` ```
### <span id="And">And</span> ### <span id="And">And</span>
<p>逻辑且操作当切仅当a和b都为true时返回true</p> <p>逻辑且操作当切仅当a和b都为true时返回true</p>
@@ -99,7 +109,7 @@ func main() {
```go ```go
func And[T, U any](a T, b U) bool func And[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -117,8 +127,6 @@ func main() {
} }
``` ```
### <span id="Or">Or</span> ### <span id="Or">Or</span>
<p>逻辑或操作当切仅当a和b都为false时返回false</p> <p>逻辑或操作当切仅当a和b都为false时返回false</p>
@@ -127,7 +135,7 @@ func main() {
```go ```go
func Or[T, U any](a T, b U) bool func Or[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -145,8 +153,6 @@ func main() {
} }
``` ```
### <span id="Xor">Xor</span> ### <span id="Xor">Xor</span>
<p>逻辑异或操作a和b相同返回falsea和b不相同返回true</p> <p>逻辑异或操作a和b相同返回falsea和b不相同返回true</p>
@@ -155,7 +161,7 @@ func main() {
```go ```go
func Xor[T, U any](a T, b U) bool func Xor[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -173,8 +179,6 @@ func main() {
} }
``` ```
### <span id="Nor">Nor</span> ### <span id="Nor">Nor</span>
<p>异或的取反操作</p> <p>异或的取反操作</p>
@@ -183,7 +187,7 @@ func main() {
```go ```go
func Nor[T, U any](a T, b U) bool func Nor[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -201,8 +205,6 @@ func main() {
} }
``` ```
### <span id="Xnor">Xnor</span> ### <span id="Xnor">Xnor</span>
<p>如果a和b都是真的或a和b均是假的则返回true。</p> <p>如果a和b都是真的或a和b均是假的则返回true。</p>
@@ -211,7 +213,7 @@ func main() {
```go ```go
func Xnor[T, U any](a T, b U) bool func Xnor[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -237,7 +239,7 @@ func main() {
```go ```go
func Nand[T, U any](a T, b U) bool func Nand[T, U any](a T, b U) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -255,8 +257,6 @@ func main() {
} }
``` ```
### <span id="TernaryOperator">TernaryOperator</span> ### <span id="TernaryOperator">TernaryOperator</span>
<p>三元运算符</p> <p>三元运算符</p>
@@ -265,7 +265,7 @@ func main() {
```go ```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -276,10 +276,18 @@ import (
) )
func main() { func main() {
trueValue := "1" conditionTrue := 2 > 1
falseValue := "0" result1 := condition.TernaryOperator(conditionTrue, 0, 1)
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1" conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Convertor # Convertor
Package convertor contains some functions for data type convertion. Package convertor contains some functions for data type convertion.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ Package convertor contains some functions for data type convertion.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/convertor"
@@ -19,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [ColorHexToRGB](#ColorHexToRGB) - [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex) - [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool) - [ToBool](#ToBool)
@@ -35,14 +38,15 @@ import (
- [MapToSlice](#MapToSlice) - [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte) - [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte) - [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="ColorHexToRGB">ColorHexToRGB</span> ### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>Convert color hex to color rgb.</p> <p>Convert color hex to color rgb.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -50,6 +54,7 @@ import (
```go ```go
func ColorHexToRGB(colorHex string) (red, green, blue int) func ColorHexToRGB(colorHex string) (red, green, blue int)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -63,12 +68,14 @@ import (
func main() { func main() {
colorHex := "#003366" colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex) r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
fmt.Println(r, g, b)
// Output:
// 0 51 102
} }
``` ```
### <span id="ColorRGBToHex">ColorRGBToHex</span> ### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>Convert color rgb to color hex.</p> <p>Convert color rgb to color hex.</p>
@@ -78,6 +85,7 @@ func main() {
```go ```go
func ColorRGBToHex(red, green, blue int) string func ColorRGBToHex(red, green, blue int) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -92,14 +100,15 @@ func main() {
r := 0 r := 0
g := 51 g := 51
b := 102 b := 102
colorHex := convertor.ColorRGBToHex(r, g, b) colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366 fmt.Println(colorHex)
// Output:
// #003366
} }
``` ```
### <span id="ToBool">ToBool</span> ### <span id="ToBool">ToBool</span>
<p>Convert string to bool. Use strconv.ParseBool.</p> <p>Convert string to bool. Use strconv.ParseBool.</p>
@@ -109,6 +118,7 @@ func main() {
```go ```go
func ToBool(s string) (bool, error) func ToBool(s string) (bool, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -120,22 +130,26 @@ import (
) )
func main() { func main() {
v1, _ := convertor.ToBool("1") cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true") for i := 0; i < len(cases); i++ {
fmt.Println(v2) //true result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
v3, _ := convertor.ToBool("True") // Output:
fmt.Println(v3) //true // true
// true
v4, _ := convertor.ToBool("123") // true
fmt.Println(v4) //false // false
// false
// false
// false
// false
// false
} }
``` ```
### <span id="ToBytes">ToBytes</span> ### <span id="ToBytes">ToBytes</span>
<p>Convert value to byte slice.</p> <p>Convert value to byte slice.</p>
@@ -145,6 +159,7 @@ func main() {
```go ```go
func ToBytes(data any) ([]byte, error) func ToBytes(data any) ([]byte, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -156,16 +171,18 @@ import (
) )
func main() { func main() {
bytesData, err := convertor.ToBytes("0") bytesData, err := convertor.ToBytes("abc")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
fmt.Println(bytesData)
// Output:
// [97 98 99]
} }
``` ```
### <span id="ToChar">ToChar</span> ### <span id="ToChar">ToChar</span>
<p>Convert string to char slice.</p> <p>Convert string to char slice.</p>
@@ -175,6 +192,7 @@ func main() {
```go ```go
func ToChar(s string) []string func ToChar(s string) []string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -186,18 +204,21 @@ import (
) )
func main() { func main() {
chars := convertor.ToChar("") result1 := convertor.ToChar("")
fmt.Println(chars) //[]string{""} result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
chars = convertor.ToChar("abc") fmt.Println(result1)
fmt.Println(chars) //[]string{"a", "b", "c"} fmt.Println(result2)
fmt.Println(result3)
chars = convertor.ToChar("1 2#3") // Output:
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"} // []
// [a b c]
// [1 2 # 3]
} }
``` ```
### <span id="ToChannel">ToChannel</span> ### <span id="ToChannel">ToChannel</span>
<p>Convert a collection of elements to a read-only channel.</p> <p>Convert a collection of elements to a read-only channel.</p>
@@ -207,6 +228,7 @@ func main() {
```go ```go
func ToChannel[T any](array []T) <-chan T func ToChannel[T any](array []T) <-chan T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -219,23 +241,21 @@ import (
func main() { func main() {
ch := convertor.ToChannel([]int{1, 2, 3}) ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
val1, _ := <-ch fmt.Println(result1)
fmt.Println(val1) //1 fmt.Println(result2)
fmt.Println(result3)
val2, _ := <-ch // Output:
fmt.Println(val2) //2 // 1
// 2
val3, _ := <-ch // 3
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
} }
``` ```
### <span id="ToFloat">ToFloat</span> ### <span id="ToFloat">ToFloat</span>
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p> <p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
@@ -245,6 +265,7 @@ func main() {
```go ```go
func ToFloat(value any) (float64, error) func ToFloat(value any) (float64, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -256,19 +277,30 @@ import (
) )
func main() { func main() {
v, err := convertor.ToFloat("") result1, _ := convertor.ToFloat("")
if err != nil { result2, err := convertor.ToFloat("abc")
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax result3, _ := convertor.ToFloat("-1")
} result4, _ := convertor.ToFloat("-.11")
fmt.Println(v) //0 result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
v, _ = convertor.ToFloat("-.11") fmt.Println(result1)
fmt.Println(v) //-0.11 fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
} }
``` ```
### <span id="ToInt">ToInt</span> ### <span id="ToInt">ToInt</span>
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p> <p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
@@ -278,6 +310,7 @@ func main() {
```go ```go
func ToInt(value any) (int64, error) func ToInt(value any) (int64, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -289,19 +322,27 @@ import (
) )
func main() { func main() {
v, err := convertor.ToInt("") result1, _ := convertor.ToInt("123")
if err != nil { result2, _ := convertor.ToInt("-123")
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax result3, _ := convertor.ToInt(float64(12.3))
} result4, err := convertor.ToInt("abc")
fmt.Println(v) //0 result5, _ := convertor.ToInt(true)
v, _ = convertor.ToFloat(1.12) fmt.Println(result1)
fmt.Println(v) //1 fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
} }
``` ```
### <span id="ToJson">ToJson</span> ### <span id="ToJson">ToJson</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p> <p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
@@ -311,6 +352,7 @@ func main() {
```go ```go
func ToJson(value any) (string, error) func ToJson(value any) (string, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -322,14 +364,20 @@ import (
) )
func main() { func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3} aMap := map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap) result, err := ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
} }
``` ```
### <span id="ToMap">ToMap</span> ### <span id="ToMap">ToMap</span>
<p>Convert a slice of structs to a map based on iteratee function. </p> <p>Convert a slice of structs to a map based on iteratee function. </p>
@@ -339,6 +387,7 @@ func main() {
```go ```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -358,16 +407,18 @@ func main() {
{name: "Hello", code: 100}, {name: "Hello", code: 100},
{name: "Hi", code: 101}, {name: "Hi", code: 101},
} }
result := convertor.ToMap(messages, func(msg Message) (int, string) { result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name return msg.code, msg.name
}) })
fmt.Println(result) //{100: "Hello", 101: "Hi"} fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
} }
``` ```
### <span id="ToPointer">ToPointer</span> ### <span id="ToPointer">ToPointer</span>
<p>Returns a pointer to passed value. </p> <p>Returns a pointer to passed value. </p>
@@ -377,6 +428,7 @@ func main() {
```go ```go
func ToPointer[T any](value T) *T func ToPointer[T any](value T) *T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -389,11 +441,13 @@ import (
func main() { func main() {
result := convertor.ToPointer(123) result := convertor.ToPointer(123)
fmt.Println(*result) //123 fmt.Println(*result)
// Output:
// 123
} }
``` ```
### <span id="ToString">ToString</span> ### <span id="ToString">ToString</span>
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p> <p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
@@ -403,6 +457,7 @@ func main() {
```go ```go
func ToString(value any) string func ToString(value any) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -414,13 +469,33 @@ import (
) )
func main() { func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1" result1 := convertor.ToString("")
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1" result2 := convertor.ToString(nil)
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]" result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
} }
``` ```
### <span id="StructToMap">StructToMap</span> ### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p> <p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
@@ -430,6 +505,7 @@ func main() {
```go ```go
func StructToMap(value any) (map[string]any, error) func StructToMap(value any) (map[string]any, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -451,12 +527,13 @@ func main() {
} }
pm, _ := convertor.StructToMap(p) pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test] fmt.Println(pm)
// Output:
// map[name:test]
} }
``` ```
### <span id="MapToSlice">MapToSlice</span> ### <span id="MapToSlice">MapToSlice</span>
<p>Convert a map to a slice based on iteratee function.</p> <p>Convert a map to a slice based on iteratee function.</p>
@@ -466,6 +543,7 @@ func main() {
```go ```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -486,7 +564,6 @@ func main() {
} }
``` ```
### <span id="EncodeByte">EncodeByte</span> ### <span id="EncodeByte">EncodeByte</span>
<p>Encode data to byte slice.</p> <p>Encode data to byte slice.</p>
@@ -496,6 +573,7 @@ func main() {
```go ```go
func EncodeByte(data any) ([]byte, error) func EncodeByte(data any) ([]byte, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -508,12 +586,13 @@ import (
func main() { func main() {
byteData, _ := convertor.EncodeByte("abc") byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99} fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
} }
``` ```
### <span id="DecodeByte">DecodeByte</span> ### <span id="DecodeByte">DecodeByte</span>
<p>Decode byte data to target object. target should be a pointer instance.</p> <p>Decode byte data to target object. target should be a pointer instance.</p>
@@ -523,6 +602,7 @@ func main() {
```go ```go
func DecodeByte(data []byte, target any) error func DecodeByte(data []byte, target any) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -536,7 +616,144 @@ import (
func main() { func main() {
var result string var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99} byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc" err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
}
```
### <span id="DeepClone">DeepClone</span>
<p>Creates a deep copy of passed item, can't clone unexported field of struct.</p>
<b>Signature:</b>
```go
func DeepClone[T any](src T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>Copies each field from the source struct into the destination struct.</p>
<b>Signature:</b>
```go
func CopyProperties[T, U any](dst T, src U) (err error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Address struct {
Country string
ZipCode string
}
type User struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
type Employee struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
employee1 := Employee{}
CopyProperties(&employee1, &user)
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
CopyProperties(&employee2, &user)
fmt.Println(employee1)
fmt.Println(employee2)
// Output:
// {user001 10 Admin {CN 001} [a b] 0}
// {user001 10 Admin {CN 001} [a b] 500}
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Convertor # Convertor
convertor转换器包支持一些常见的数据类型转换
convertor 转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -37,22 +38,25 @@ import (
- [MapToSlice](#MapToSlice) - [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte) - [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte) - [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 文档 ## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span> ### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb</p>
<p>颜色值十六进制转rgb。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ColorHexToRGB(colorHex string) (red, green, blue int) func ColorHexToRGB(colorHex string) (red, green, blue int)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -65,22 +69,25 @@ import (
func main() { func main() {
colorHex := "#003366" colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex) r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
fmt.Println(r, g, b)
// Output:
// 0 51 102
} }
``` ```
### <span id="ColorRGBToHex">ColorRGBToHex</span> ### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制</p> <p>颜色值rgb转十六进制</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ColorRGBToHex(red, green, blue int) string func ColorRGBToHex(red, green, blue int) string
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -94,24 +101,26 @@ func main() {
r := 0 r := 0
g := 51 g := 51
b := 102 b := 102
colorHex := convertor.ColorRGBToHex(r, g, b) colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366 fmt.Println(colorHex)
// Output:
// #003366
} }
``` ```
### <span id="ToBool">ToBool</span> ### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型使用strconv.ParseBool</p> <p>字符串转布尔类型使用strconv.ParseBool</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToBool(s string) (bool, error) func ToBool(s string) (bool, error)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -122,32 +131,37 @@ import (
) )
func main() { func main() {
v1, _ := convertor.ToBool("1") cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true") for i := 0; i < len(cases); i++ {
fmt.Println(v2) //true result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
v3, _ := convertor.ToBool("True") // Output:
fmt.Println(v3) //true // true
// true
v4, _ := convertor.ToBool("123") // true
fmt.Println(v4) //false // false
// false
// false
// false
// false
// false
} }
``` ```
### <span id="ToBytes">ToBytes</span> ### <span id="ToBytes">ToBytes</span>
<p>interface转字节切片.</p> <p>Interface转字节切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToBytes(data any) ([]byte, error) func ToBytes(data any) ([]byte, error)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -158,26 +172,29 @@ import (
) )
func main() { func main() {
bytesData, err := convertor.ToBytes("0") bytesData, err := convertor.ToBytes("abc")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
fmt.Println(bytesData)
// Output:
// [97 98 99]
} }
``` ```
### <span id="ToChar">ToChar</span> ### <span id="ToChar">ToChar</span>
<p>字符串转字符切片</p> <p>字符串转字符切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToChar(s string) []string func ToChar(s string) []string
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -188,29 +205,32 @@ import (
) )
func main() { func main() {
chars := convertor.ToChar("") result1 := convertor.ToChar("")
fmt.Println(chars) //[]string{""} result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
chars = convertor.ToChar("abc") fmt.Println(result1)
fmt.Println(chars) //[]string{"a", "b", "c"} fmt.Println(result2)
fmt.Println(result3)
chars = convertor.ToChar("1 2#3") // Output:
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"} // []
// [a b c]
// [1 2 # 3]
} }
``` ```
### <span id="ToChannel">ToChannel</span> ### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel</p> <p>将切片转为只读channel</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToChannel[T any](array []T) <-chan T func ToChannel[T any](array []T) <-chan T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -222,33 +242,32 @@ import (
func main() { func main() {
ch := convertor.ToChannel([]int{1, 2, 3}) ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
val1, _ := <-ch fmt.Println(result1)
fmt.Println(val1) //1 fmt.Println(result2)
fmt.Println(result3)
val2, _ := <-ch // Output:
fmt.Println(val2) //2 // 1
// 2
val3, _ := <-ch // 3
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
} }
``` ```
### <span id="ToFloat">ToFloat</span> ### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error</p> <p>将interface转成float64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToFloat(value any) (float64, error) func ToFloat(value any) (float64, error)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -259,29 +278,41 @@ import (
) )
func main() { func main() {
v, err := convertor.ToFloat("") result1, _ := convertor.ToFloat("")
if err != nil { result2, err := convertor.ToFloat("abc")
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax result3, _ := convertor.ToFloat("-1")
} result4, _ := convertor.ToFloat("-.11")
fmt.Println(v) //0 result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
v, _ = convertor.ToFloat("-.11") fmt.Println(result1)
fmt.Println(v) //-0.11 fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
} }
``` ```
### <span id="ToInt">ToInt</span> ### <span id="ToInt">ToInt</span>
<p>将interface转成int64类型如果参数无法转换会返回0和error</p> <p>将interface转成int64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToInt(value any) (int64, error) func ToInt(value any) (int64, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -292,29 +323,38 @@ import (
) )
func main() { func main() {
v, err := convertor.ToInt("") result1, _ := convertor.ToInt("123")
if err != nil { result2, _ := convertor.ToInt("-123")
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax result3, _ := convertor.ToInt(float64(12.3))
} result4, err := convertor.ToInt("abc")
fmt.Println(v) //0 result5, _ := convertor.ToInt(true)
v, _ = convertor.ToFloat(1.12) fmt.Println(result1)
fmt.Println(v) //1 fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
} }
``` ```
### <span id="ToJson">ToJson</span> ### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串如果参数无法转换会返回""和error</p> <p>将interface转成json字符串如果参数无法转换会返回""和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToJson(value any) (string, error) func ToJson(value any) (string, error)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -325,24 +365,31 @@ import (
) )
func main() { func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3} aMap := map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap) result, err := ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
} }
``` ```
### <span id="ToMap">ToMap</span> ### <span id="ToMap">ToMap</span>
<p>将切片转为map</p> <p>将切片转为map</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -361,26 +408,29 @@ func main() {
{name: "Hello", code: 100}, {name: "Hello", code: 100},
{name: "Hi", code: 101}, {name: "Hi", code: 101},
} }
result := convertor.ToMap(messages, func(msg Message) (int, string) { result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name return msg.code, msg.name
}) })
fmt.Println(result) //{100: "Hello", 101: "Hi"} fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
} }
``` ```
### <span id="ToPointer">ToPointer</span> ### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针</p> <p>返回传入值的指针</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToPointer[T any](value T) *T func ToPointer[T any](value T) *T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -392,22 +442,24 @@ import (
func main() { func main() {
result := convertor.ToPointer(123) result := convertor.ToPointer(123)
fmt.Println(*result) //123 fmt.Println(*result)
// Output:
// 123
} }
``` ```
### <span id="ToString">ToString</span> ### <span id="ToString">ToString</span>
<p>将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p> <p>将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToString(value any) string func ToString(value any) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -418,24 +470,44 @@ import (
) )
func main() { func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1" result1 := convertor.ToString("")
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1" result2 := convertor.ToString(nil)
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]" result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
} }
``` ```
### <span id="StructToMap">StructToMap</span> ### <span id="StructToMap">StructToMap</span>
<p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p> <p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func StructToMap(value any) (map[string]any, error) func StructToMap(value any) (map[string]any, error)
``` ```
<b>列子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -456,22 +528,24 @@ func main() {
} }
pm, _ := convertor.StructToMap(p) pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test] fmt.Println(pm)
// Output:
// map[name:test]
} }
``` ```
### <span id="MapToSlice">MapToSlice</span> ### <span id="MapToSlice">MapToSlice</span>
<p>map中key和value执行函数iteratee后转为切片</p> <p>map中key和value执行函数iteratee后转为切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -491,18 +565,17 @@ func main() {
} }
``` ```
### <span id="EncodeByte">EncodeByte</span> ### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片</p> <p>将data编码成字节切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func EncodeByte(data any) ([]byte, error) func EncodeByte(data any) ([]byte, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -514,22 +587,24 @@ import (
func main() { func main() {
byteData, _ := convertor.EncodeByte("abc") byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99} fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
} }
``` ```
### <span id="DecodeByte">DecodeByte</span> ### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p> <p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func DecodeByte(data []byte, target any) error func DecodeByte(data []byte, target any) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -542,7 +617,142 @@ import (
func main() { func main() {
var result string var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99} byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc" err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
}
```
### <span id="DeepClone">DeepClone</span>
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
<b>函数签名:</b>
```go
func DeepClone[T any](src T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>拷贝不同结构体之间的同名字段。</p>
<b>函数签名:</b>
```go
func CopyProperties[T, U any](dst T, src U) (err error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Address struct {
Country string
ZipCode string
}
type User struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
type Employee struct {
Name string
Age int
Role string
Addr Address
Hobbys []string
salary int
}
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
employee1 := Employee{}
CopyProperties(&employee1, &user)
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
CopyProperties(&employee2, &user)
fmt.Println(employee1)
fmt.Println(employee2)
// Output:
// {user001 10 Admin {CN 001} [a b] 0}
// {user001 10 Admin {CN 001} [a b] 500}
} }
``` ```

View File

@@ -61,8 +61,6 @@ import (
## Documentation ## Documentation
### <span id="AesEcbEncrypt">AesEcbEncrypt</span> ### <span id="AesEcbEncrypt">AesEcbEncrypt</span>
<p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -83,16 +81,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesEcbDecrypt">AesEcbDecrypt</span> ### <span id="AesEcbDecrypt">AesEcbDecrypt</span>
<p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -113,16 +114,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCbcEncrypt">AesCbcEncrypt</span> ### <span id="AesCbcEncrypt">AesCbcEncrypt</span>
<p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -143,16 +147,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCbcDecrypt">AesCbcDecrypt</span> ### <span id="AesCbcDecrypt">AesCbcDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -174,16 +181,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCtrCrypt">AesCtrCrypt</span> ### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -205,17 +215,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key)) decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span> ### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -237,15 +249,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbDecrypt">AesCfbDecrypt</span> ### <span id="AesCfbDecrypt">AesCfbDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -267,16 +283,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesOfbEncrypt">AesOfbEncrypt</span> ### <span id="AesOfbEncrypt">AesOfbEncrypt</span>
<p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -298,15 +317,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbDecrypt">AesOfbDecrypt</span> ### <span id="AesCfbDecrypt">AesOfbDecrypt</span>
<p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -328,17 +350,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="Base64StdEncode">Base64StdEncode</span> ### <span id="Base64StdEncode">Base64StdEncode</span>
<p>Encode string with base64 encoding.</p> <p>Encode string with base64 encoding.</p>
@@ -359,13 +383,13 @@ import (
) )
func main() { func main() {
base64Str := cryptor.Base64StdEncode("hello world") base64Str := cryptor.Base64StdEncode("hello")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ= fmt.Println(base64Str)
// Output:
// aGVsbG8=
} }
``` ```
### <span id="Base64StdDecode">Base64StdDecode</span> ### <span id="Base64StdDecode">Base64StdDecode</span>
<p>Decode a base64 encoded string.</p> <p>Decode a base64 encoded string.</p>
@@ -387,13 +411,14 @@ import (
) )
func main() { func main() {
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=") str := cryptor.Base64StdDecode("aGVsbG8=")
fmt.Println(str) //hello world fmt.Println(str)
// Output:
// hello
} }
``` ```
### <span id="DesEcbEncrypt">DesEcbEncrypt</span> ### <span id="DesEcbEncrypt">DesEcbEncrypt</span>
<p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -415,16 +440,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesEcbDecrypt">DesEcbDecrypt</span> ### <span id="DesEcbDecrypt">DesEcbDecrypt</span>
<p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -446,17 +474,20 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCbcEncrypt">DesCbcEncrypt</span> ### <span id="DesCbcEncrypt">DesCbcEncrypt</span>
<p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -478,16 +509,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted)) encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCbcDecrypt">DesCbcDecrypt</span> ### <span id="DesCbcDecrypt">DesCbcDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -509,17 +543,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCtrCrypt">DesCtrCrypt</span> ### <span id="DesCtrCrypt">DesCtrCrypt</span>
<p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p> <p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
@@ -541,17 +576,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key)) encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key)) decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCfbEncrypt">DesCfbEncrypt</span> ### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
<p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p>
@@ -573,15 +610,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted)) encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCfbDecrypt">DesCfbDecrypt</span> ### <span id="DesCfbDecrypt">DesCfbDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -603,16 +643,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesOfbEncrypt">DesOfbEncrypt</span> ### <span id="DesOfbEncrypt">DesOfbEncrypt</span>
<p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p> <p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -634,15 +676,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesOfbDecrypt">DesOfbDecrypt</span> ### <span id="DesOfbDecrypt">DesOfbDecrypt</span>
<p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -664,17 +709,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="HmacMd5">HmacMd5</span> ### <span id="HmacMd5">HmacMd5</span>
<p>Get the md5 hmac hash of string.</p> <p>Get the md5 hmac hash of string.</p>
@@ -696,13 +743,16 @@ import (
) )
func main() { func main() {
s := cryptor.HmacMd5("hello world", "12345")) str := "hello"
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d key := "12345"
hms := cryptor.HmacMd5(str, key)
fmt.Println(hms)
// Output:
// e834306eab892d872525d4918a7a639a
} }
``` ```
### <span id="HmacSha1">HmacSha1</span> ### <span id="HmacSha1">HmacSha1</span>
<p>Get the sha1 hmac hash of string.</p> <p>Get the sha1 hmac hash of string.</p>
@@ -724,13 +774,16 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha1("hello world", "12345")) str := "hello"
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd key := "12345"
hms := cryptor.HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
} }
``` ```
### <span id="HmacSha256">HmacSha256</span> ### <span id="HmacSha256">HmacSha256</span>
<p>Get the sha256 hmac hash of string</p> <p>Get the sha256 hmac hash of string</p>
@@ -752,13 +805,17 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha256("hello world", "12345")) str := "hello"
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8 key := "12345"
hms := cryptor.HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
} }
``` ```
### <span id="HmacSha512">HmacSha512</span> ### <span id="HmacSha512">HmacSha512</span>
<p>Get the sha512 hmac hash of string.</p> <p>Get the sha512 hmac hash of string.</p>
@@ -780,14 +837,18 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha512("hello world", "12345")) str := "hello"
fmt.Println(s) key := "12345"
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
hms := cryptor.HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
} }
``` ```
### <span id="Md5String">Md5String</span> ### <span id="Md5String">Md5String</span>
<p>Get the md5 value of string.</p> <p>Get the md5 value of string.</p>
@@ -809,13 +870,16 @@ import (
) )
func main() { func main() {
s := cryptor.Md5String("hello")) str := "hello"
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
md5Str := cryptor.Md5String(str)
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
} }
``` ```
### <span id="Md5File">Md5File</span> ### <span id="Md5File">Md5File</span>
<p>Get the md5 value of file.</p> <p>Get the md5 value of file.</p>
@@ -842,8 +906,6 @@ func main() {
} }
``` ```
### <span id="Sha1">Sha1</span> ### <span id="Sha1">Sha1</span>
<p>Get the sha1 value of string.</p> <p>Get the sha1 value of string.</p>
@@ -865,13 +927,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha1("hello world")) str := "hello"
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
result := cryptor.Sha1(str)
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
} }
``` ```
### <span id="Sha256">Sha256</span> ### <span id="Sha256">Sha256</span>
<p>Get the sha256 value of string.</p> <p>Get the sha256 value of string.</p>
@@ -893,13 +958,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha256("hello world")) str := "hello"
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
result := cryptor.Sha256(str)
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
} }
``` ```
### <span id="Sha512">Sha512</span> ### <span id="Sha512">Sha512</span>
<p>Get the sha512 value of string.</p> <p>Get the sha512 value of string.</p>
@@ -921,13 +989,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha512("hello world")) str := "hello"
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
result := cryptor.Sha512(str)
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
} }
``` ```
### <span id="GenerateRsaKey">GenerateRsaKey</span> ### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>Create the rsa public and private key file in current directory.</p> <p>Create the rsa public and private key file in current directory.</p>
@@ -956,8 +1027,6 @@ func main() {
} }
``` ```
### <span id="RsaEncrypt">RsaEncrypt</span> ### <span id="RsaEncrypt">RsaEncrypt</span>
<p>Encrypt data with public key file useing ras algorithm.</p> <p>Encrypt data with public key file useing ras algorithm.</p>
@@ -981,19 +1050,21 @@ import (
func main() { func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem") err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil { if err != nil {
fmt.Println(err) return
} }
data := []byte("hello world") data := []byte("hello")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem") encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem") decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="RsaDecrypt">RsaDecrypt</span> ### <span id="RsaDecrypt">RsaDecrypt</span>
<p>Decrypt data with private key file useing ras algorithm.</p> <p>Decrypt data with private key file useing ras algorithm.</p>
@@ -1017,14 +1088,17 @@ import (
func main() { func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem") err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil { if err != nil {
fmt.Println(err) return
} }
data := []byte("hello world") data := []byte("hello")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem") encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem") decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ import (
func NewHashMap() *HashMap func NewHashMap() *HashMap
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -72,7 +72,7 @@ func main() {
func NewHashMapWithCapacity(size, capacity uint64) *HashMap func NewHashMapWithCapacity(size, capacity uint64) *HashMap
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -98,7 +98,7 @@ func main() {
func (hm *HashMap) Get(key any) any func (hm *HashMap) Get(key any) any
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -126,7 +126,7 @@ func main() {
func (hm *HashMap) Put(key any, value any) any func (hm *HashMap) Put(key any, value any) any
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -155,7 +155,7 @@ func main() {
func (hm *HashMap) Delete(key any) func (hm *HashMap) Delete(key any)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -187,7 +187,7 @@ func main() {
func (hm *HashMap) Contains(key any) bool func (hm *HashMap) Contains(key any) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -217,7 +217,7 @@ func main() {
func (hm *HashMap) Iterate(iteratee func(key, value any)) func (hm *HashMap) Iterate(iteratee func(key, value any))
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -252,7 +252,7 @@ func main() {
func (hm *HashMap) Keys() []any func (hm *HashMap) Keys() []any
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -284,7 +284,7 @@ func main() {
func (hm *HashMap) Values() []any func (hm *HashMap) Values() []any
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -48,7 +48,7 @@ type MaxHeap[T any] struct {
} }
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -89,7 +89,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) Push(value T) func (h *MaxHeap[T]) Push(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -136,7 +136,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) Pop() (T, bool) func (h *MaxHeap[T]) Pop() (T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -184,7 +184,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) Peek() (T, bool) func (h *MaxHeap[T]) Peek() (T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -232,7 +232,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) Data() []T func (h *MaxHeap[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -277,7 +277,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) Size() int func (h *MaxHeap[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -323,7 +323,7 @@ func main() {
```go ```go
func (h *MaxHeap[T]) PrintStructure() func (h *MaxHeap[T]) PrintStructure()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -81,7 +81,7 @@ type SinglyLink[T any] struct {
} }
func NewSinglyLink[T any]() *SinglyLink[T] func NewSinglyLink[T any]() *SinglyLink[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -107,7 +107,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) Values() []T func (link *SinglyLink[T]) Values() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -139,7 +139,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) InsertAt(index int, value T) func (link *SinglyLink[T]) InsertAt(index int, value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -174,7 +174,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) InsertAtHead(value T) func (link *SinglyLink[T]) InsertAtHead(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -206,7 +206,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) InsertAtTail(value T) func (link *SinglyLink[T]) InsertAtTail(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -237,7 +237,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) DeleteAt(index int) func (link *SinglyLink[T]) DeleteAt(index int)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -271,7 +271,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) DeleteAtHead() func (link *SinglyLink[T]) DeleteAtHead()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -306,7 +306,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) DeleteAtTail() func (link *SinglyLink[T]) DeleteAtTail()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -339,7 +339,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) DeleteValue(value T) func (link *SinglyLink[T]) DeleteValue(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -373,7 +373,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) Reverse() func (link *SinglyLink[T]) Reverse()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -405,7 +405,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -437,7 +437,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) Size() int func (link *SinglyLink[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -468,7 +468,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) IsEmpty() bool func (link *SinglyLink[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -500,7 +500,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) Clear() func (link *SinglyLink[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -533,7 +533,7 @@ func main() {
```go ```go
func (link *SinglyLink[T]) Clear() func (link *SinglyLink[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -576,7 +576,7 @@ type DoublyLink[T any] struct {
} }
func NewDoublyLink[T any]() *DoublyLink[T] func NewDoublyLink[T any]() *DoublyLink[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -602,7 +602,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) Values() []T func (link *DoublyLink[T]) Values() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -634,7 +634,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) InsertAt(index int, value T) func (link *DoublyLink[T]) InsertAt(index int, value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -669,7 +669,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) InsertAtHead(value T) func (link *DoublyLink[T]) InsertAtHead(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -701,7 +701,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) InsertAtTail(value T) func (link *DoublyLink[T]) InsertAtTail(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -732,7 +732,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) DeleteAt(index int) func (link *DoublyLink[T]) DeleteAt(index int)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -766,7 +766,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) DeleteAtHead() func (link *DoublyLink[T]) DeleteAtHead()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -801,7 +801,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) DeleteAtTail() func (link *DoublyLink[T]) DeleteAtTail()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -835,7 +835,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) Reverse() func (link *DoublyLink[T]) Reverse()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -867,7 +867,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -899,7 +899,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) Size() int func (link *DoublyLink[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -930,7 +930,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) IsEmpty() bool func (link *DoublyLink[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -962,7 +962,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) Clear() func (link *DoublyLink[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -995,7 +995,7 @@ func main() {
```go ```go
func (link *DoublyLink[T]) Clear() func (link *DoublyLink[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -47,6 +47,13 @@ import (
- [Unique](#Unique) - [Unique](#Unique)
- [Union](#Union) - [Union](#Union)
- [Intersection](#Intersection) - [Intersection](#Intersection)
- [Difference](#Difference)
- [SymmetricDifference](#SymmetricDifference)
- [RetainAll](#RetainAll)
- [DeleteAll](#DeleteAll)
- [ForEach](#ForEach)
- [Iterator](#Iterator)
- [ListToMap](#ListToMap)
- [SubList](#SubList) - [SubList](#SubList)
- [DeleteIf](#DeleteIf) - [DeleteIf](#DeleteIf)
@@ -828,6 +835,233 @@ func main() {
### <span id="Difference">Difference</span>
<p>Return a list whose element in the original list, not in the given list.</p>
<b>Signature:</b>
```go
func (l *List[T]) Difference(other *List[T]) *List[T]
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>Oppoiste operation of intersection function.</p>
<b>Signature:</b>
```go
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T]
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3, 4
}
```
### <span id="RetainAll">RetainAll</span>
<p>Retains only the elements in this list that are contained in the given list.</p>
<b>Signature:</b>
```go
func (l *List[T]) RetainAll(list *List[T]) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
fmt.Println(list.Data()) //1, 2
fmt.Println(list1.Data()) //2, 3
fmt.Println(list2.Data()) //1, 2
}
```
### <span id="DeleteAll">DeleteAll</span>
<p>Removes from this list all of its elements that are contained in the given list.</p>
<b>Signature:</b>
```go
func (l *List[T]) DeleteAll(list *List[T]) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
fmt.Println(list.Data()) //2,3,4
fmt.Println(list1.Data()) //1,4
fmt.Println(list2.Data()) //3,4
}
```
### <span id="ForEach">ForEach</span>
<p>Performs the given action for each element of the list.</p>
<b>Signature:</b>
```go
func (l *List[T]) ForEach(consumer func(T))
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := make([]int, 0)
list.ForEach(func(i int) {
result = append(result, i)
})
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="Iterator">Iterator</span>
<p>Returns an iterator over the elements in this list in proper sequence.</p>
<b>Signature:</b>
```go
func (l *List[T]) Iterator() iterator.Iterator[T]
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
result := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
result = append(result, item)
}
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="ListToMap">ListToMap</span>
<p>Converts a list to a map based on iteratee function.</p>
<b>Signature:</b>
```go
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
fmt.Println(result) //map[int]bool{1: false, 2: true, 3: true, 4: true}
}
```
### <span id="SubList">SubList</span> ### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p> <p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>

View File

@@ -34,7 +34,6 @@ import (
- [PopLast](#PopLast) - [PopLast](#PopLast)
- [DeleteAt](#DeleteAt) - [DeleteAt](#DeleteAt)
- [InsertAt](#InsertAt) - [InsertAt](#InsertAt)
- [UpdateAt](#UpdateAt) - [UpdateAt](#UpdateAt)
- [Equal](#Equal) - [Equal](#Equal)
- [IsEmpty](#IsEmpty) - [IsEmpty](#IsEmpty)
@@ -48,6 +47,13 @@ import (
- [Unique](#Unique) - [Unique](#Unique)
- [Union](#Union) - [Union](#Union)
- [Intersection](#Intersection) - [Intersection](#Intersection)
- [Difference](#Difference)
- [SymmetricDifference](#SymmetricDifference)
- [RetainAll](#RetainAll)
- [DeleteAll](#DeleteAll)
- [ForEach](#ForEach)
- [Iterator](#Iterator)
- [ListToMap](#ListToMap)
- [SubList](#SubList) - [SubList](#SubList)
- [DeleteIf](#DeleteIf) - [DeleteIf](#DeleteIf)
@@ -66,7 +72,7 @@ type List[T any] struct {
} }
func NewList[T any](data []T) *List[T] func NewList[T any](data []T) *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -92,7 +98,7 @@ func main() {
```go ```go
func (l *List[T]) Contain(value T) bool func (l *List[T]) Contain(value T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -121,7 +127,7 @@ func main() {
```go ```go
func (l *List[T]) Data() []T func (l *List[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -150,7 +156,7 @@ func main() {
```go ```go
func (l *List[T]) ValueOf(index int) (*T, bool) func (l *List[T]) ValueOf(index int) (*T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -180,7 +186,7 @@ func main() {
```go ```go
func (l *List[T]) IndexOf(value T) int func (l *List[T]) IndexOf(value T) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -207,7 +213,7 @@ func main() {
```go ```go
func (l *List[T]) LastIndexOf(value T) int func (l *List[T]) LastIndexOf(value T) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -233,7 +239,7 @@ func main() {
```go ```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int func (l *List[T]) IndexOfFunc(f func(T) bool) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -259,7 +265,7 @@ func main() {
```go ```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -287,7 +293,7 @@ func main() {
```go ```go
func (l *List[T]) Push(value T) func (l *List[T]) Push(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -316,7 +322,7 @@ func main() {
```go ```go
func (l *List[T]) PopFirst() (*T, bool) func (l *List[T]) PopFirst() (*T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -348,7 +354,7 @@ func main() {
```go ```go
func (l *List[T]) PopLast() (*T, bool) func (l *List[T]) PopLast() (*T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -379,7 +385,7 @@ func main() {
```go ```go
func (l *List[T]) DeleteAt(index int) func (l *List[T]) DeleteAt(index int)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -417,7 +423,7 @@ func main() {
```go ```go
func (l *List[T]) InsertAt(index int, value T) func (l *List[T]) InsertAt(index int, value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -454,7 +460,7 @@ func main() {
```go ```go
func (l *List[T]) UpdateAt(index int, value T) func (l *List[T]) UpdateAt(index int, value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -487,7 +493,7 @@ func main() {
```go ```go
func (l *List[T]) Equal(other *List[T]) bool func (l *List[T]) Equal(other *List[T]) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -517,7 +523,7 @@ func main() {
```go ```go
func (l *List[T]) IsEmpty() bool func (l *List[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -547,7 +553,7 @@ func main() {
```go ```go
func (l *List[T]) Clear() func (l *List[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -575,7 +581,7 @@ func main() {
```go ```go
func (l *List[T]) Clone() *List[T] func (l *List[T]) Clone() *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -604,7 +610,7 @@ func main() {
```go ```go
func (l *List[T]) Merge(other *List[T]) *List[T] func (l *List[T]) Merge(other *List[T]) *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -633,7 +639,7 @@ func main() {
```go ```go
func (l *List[T]) Size() int func (l *List[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -660,7 +666,7 @@ func main() {
```go ```go
func (l *List[T]) Cap() int func (l *List[T]) Cap() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -689,7 +695,7 @@ func main() {
```go ```go
func (l *List[T]) Swap(i, j int) func (l *List[T]) Swap(i, j int)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -718,7 +724,7 @@ func main() {
```go ```go
func (l *List[T]) Reverse() func (l *List[T]) Reverse()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -747,7 +753,7 @@ func main() {
```go ```go
func (l *List[T]) Unique() func (l *List[T]) Unique()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -776,7 +782,7 @@ func main() {
```go ```go
func (l *List[T]) Union(other *List[T]) *List[T] func (l *List[T]) Union(other *List[T]) *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -806,7 +812,7 @@ func main() {
```go ```go
func (l *List[T]) Intersection(other *List[T]) *List[T] func (l *List[T]) Intersection(other *List[T]) *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -826,16 +832,244 @@ func main() {
``` ```
### <span id="Difference">Difference</span>
<p>差集运算。</p>
<b>函数签名:</b>
```go
func (l *List[T]) Difference(other *List[T]) *List[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>对称差集运算。</p>
<b>函数签名:</b>
```go
func (l *List[T]) SymmetricDifference(other *List[T]) *List[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list1 := NewList([]int{1, 2, 3})
list2 := NewList([]int{1, 2, 4})
list3 := list1.Intersection(list2)
fmt.Println(list3.Data()) //3, 4
}
```
### <span id="RetainAll">RetainAll</span>
<p>仅保留列表中包含在给定列表中的元素。</p>
<b>函数签名:</b>
```go
func (l *List[T]) RetainAll(list *List[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
retain := NewList([]int{1, 2})
retain1 := NewList([]int{2, 3})
retain2 := NewList([]int{1, 2, 5})
list.RetainAll(retain)
list1.RetainAll(retain1)
list2.RetainAll(retain2)
fmt.Println(list.Data()) //1, 2
fmt.Println(list1.Data()) //2, 3
fmt.Println(list2.Data()) //1, 2
}
```
### <span id="DeleteAll">DeleteAll</span>
<p>从列表中删除给定列表中包含的所有元素。</p>
<b>函数签名:</b>
```go
func (l *List[T]) DeleteAll(list *List[T]) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
del := NewList([]int{1})
del1 := NewList([]int{2, 3})
del2 := NewList([]int{1, 2, 5})
list.DeleteAll(del)
list1.DeleteAll(del1)
list2.DeleteAll(del2)
fmt.Println(list.Data()) //2,3,4
fmt.Println(list1.Data()) //1,4
fmt.Println(list2.Data()) //3,4
}
```
### <span id="ForEach">ForEach</span>
<p>对列表的每个元素执行给定的操作。</p>
<b>函数签名:</b>
```go
func (l *List[T]) ForEach(consumer func(T))
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := make([]int, 0)
list.ForEach(func(i int) {
result = append(result, i)
})
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="Iterator">Iterator</span>
<p>按顺序返回列表中元素的迭代器。</p>
<b>函数签名:</b>
```go
func (l *List[T]) Iterator() iterator.Iterator[T]
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
result := make([]int, 0)
for iterator.HasNext() {
item, _ := iterator.Next()
result = append(result, item)
}
fmt.Println(result.Data()) //1,2,3,4
}
```
### <span id="ListToMap">ListToMap</span>
<p>基于iteratee函数将列表转换为映射map。</p>
<b>函数签名:</b>
```go
func ListToMap[T any, K comparable, V any](list *List[T], iteratee func(T) (K, V)) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
fmt.Println(result) //map[int]bool{1: false, 2: true, 3: true, 4: true}
}
```
### <span id="SubList">SubList</span> ### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p> <p>返回指定的fromIndex包含和toIndex不包含之间的原始列表的子列表。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -863,7 +1097,7 @@ func main() {
```go ```go
func (l *List[T]) DeleteIf(f func(T) bool) int func (l *List[T]) DeleteIf(f func(T) bool) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -99,7 +99,7 @@ type ArrayQueue[T any] struct {
size int size int
} }
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -125,7 +125,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Data() []T func (q *ArrayQueue[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -152,7 +152,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Enqueue(item T) bool func (q *ArrayQueue[T]) Enqueue(item T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -183,7 +183,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Dequeue() (T, bool) func (q *ArrayQueue[T]) Dequeue() (T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -215,7 +215,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Front() T func (q *ArrayQueue[T]) Front() T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -247,7 +247,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Back() T func (q *ArrayQueue[T]) Back() T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -278,7 +278,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Size() int func (q *ArrayQueue[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -308,7 +308,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) IsEmpty() bool func (q *ArrayQueue[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -341,7 +341,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) IsFull() bool func (q *ArrayQueue[T]) IsFull() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -373,7 +373,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Clear() func (q *ArrayQueue[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -404,7 +404,7 @@ func main() {
```go ```go
func (q *ArrayQueue[T]) Contain(value T) bool func (q *ArrayQueue[T]) Contain(value T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -448,7 +448,7 @@ type QueueNode[T any] struct {
Next *QueueNode[T] Next *QueueNode[T]
} }
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -474,7 +474,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Data() []T func (q *LinkedQueue[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -501,7 +501,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Enqueue(value T) func (q *LinkedQueue[T]) Enqueue(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -532,7 +532,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Dequeue() (T, error) func (q *LinkedQueue[T]) Dequeue() (T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -564,7 +564,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Front() (*T, error) func (q *LinkedQueue[T]) Front() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -596,7 +596,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Back() (*T, error) func (q *LinkedQueue[T]) Back() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -627,7 +627,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Size() int func (q *LinkedQueue[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -657,7 +657,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) IsEmpty() bool func (q *LinkedQueue[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -690,7 +690,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Clear() func (q *LinkedQueue[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -721,7 +721,7 @@ func main() {
```go ```go
func (q *LinkedQueue[T]) Contain(value T) bool func (q *LinkedQueue[T]) Contain(value T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -763,7 +763,7 @@ type CircularQueue[T any] struct {
capacity int capacity int
} }
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -789,7 +789,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Data() []T func (q *CircularQueue[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -816,7 +816,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Enqueue(value T) error func (q *CircularQueue[T]) Enqueue(value T) error
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -847,7 +847,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Dequeue() (*T, bool) func (q *CircularQueue[T]) Dequeue() (*T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -880,7 +880,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Front() T func (q *CircularQueue[T]) Front() T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -912,7 +912,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Back() T func (q *CircularQueue[T]) Back() T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -943,7 +943,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Size() int func (q *CircularQueue[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -973,7 +973,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) IsEmpty() bool func (q *CircularQueue[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1006,7 +1006,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) IsFull() bool func (q *CircularQueue[T]) IsFull() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1038,7 +1038,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Clear() func (q *CircularQueue[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1069,7 +1069,7 @@ func main() {
```go ```go
func (q *CircularQueue[T]) Contain(value T) bool func (q *CircularQueue[T]) Contain(value T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1108,7 +1108,7 @@ type PriorityQueue[T any] struct {
comparator lancetconstraints.Comparator comparator lancetconstraints.Comparator
} }
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1134,7 +1134,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) Data() []T func (q *PriorityQueue[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1161,7 +1161,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) Enqueue(item T) bool func (q *PriorityQueue[T]) Enqueue(item T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1207,7 +1207,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) Dequeue() (T, bool) func (q *PriorityQueue[T]) Dequeue() (T, bool)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1254,7 +1254,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) IsEmpty() bool func (q *PriorityQueue[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1301,7 +1301,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) IsFull() bool func (q *PriorityQueue[T]) IsFull() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -1348,7 +1348,7 @@ func main() {
```go ```go
func (q *PriorityQueue[T]) Size() int func (q *PriorityQueue[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -55,7 +55,7 @@ import (
type Set[T comparable] map[T]bool type Set[T comparable] map[T]bool
func NewSet[T comparable](items ...T) Set[T] func NewSet[T comparable](items ...T) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -81,7 +81,7 @@ func main() {
```go ```go
func NewSetFromSlice[T comparable](items []T) Set[T] func NewSetFromSlice[T comparable](items []T) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -107,7 +107,7 @@ func main() {
```go ```go
func (s Set[T]) Values() []T func (s Set[T]) Values() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -134,7 +134,7 @@ func main() {
```go ```go
func (s Set[T]) Add(items ...T) func (s Set[T]) Add(items ...T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -161,7 +161,7 @@ func main() {
```go ```go
func (s Set[T]) AddIfNotExist(item T) bool func (s Set[T]) AddIfNotExist(item T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -193,7 +193,7 @@ func main() {
```go ```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -232,7 +232,7 @@ func main() {
```go ```go
func (s Set[T]) Delete(items ...T) func (s Set[T]) Delete(items ...T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -261,7 +261,7 @@ func main() {
```go ```go
func (s Set[T]) Contain(item T) bool func (s Set[T]) Contain(item T) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -291,7 +291,7 @@ func main() {
```go ```go
func (s Set[T]) ContainAll(other Set[T]) bool func (s Set[T]) ContainAll(other Set[T]) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -321,7 +321,7 @@ func main() {
```go ```go
func (s Set[T]) Size() int func (s Set[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -348,7 +348,7 @@ func main() {
```go ```go
func (s Set[T]) Clone() Set[T] func (s Set[T]) Clone() Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -378,7 +378,7 @@ func main() {
```go ```go
func (s Set[T]) Equal(other Set[T]) bool func (s Set[T]) Equal(other Set[T]) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -408,7 +408,7 @@ func main() {
```go ```go
func (s Set[T]) Iterate(fn func(item T)) func (s Set[T]) Iterate(fn func(item T))
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -439,7 +439,7 @@ func main() {
```go ```go
func (s Set[T]) IsEmpty() bool func (s Set[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -468,7 +468,7 @@ func main() {
```go ```go
func (s Set[T]) Union(other Set[T]) Set[T] func (s Set[T]) Union(other Set[T]) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -497,7 +497,7 @@ func main() {
```go ```go
func (s Set[T]) Intersection(other Set[T]) Set[T] func (s Set[T]) Intersection(other Set[T]) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -525,7 +525,7 @@ func main() {
```go ```go
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T] func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -556,7 +556,7 @@ func main() {
```go ```go
func (s Set[T]) Minus(comparedSet Set[T]) Set[T] func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -64,7 +64,7 @@ type ArrayStack[T any] struct {
} }
func NewArrayStack[T any]() *ArrayStack[T] func NewArrayStack[T any]() *ArrayStack[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -91,7 +91,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Push(value T) func (s *ArrayStack[T]) Push(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -122,7 +122,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Pop() (*T, error) func (s *ArrayStack[T]) Pop() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -157,7 +157,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Peak() (*T, error) func (s *ArrayStack[T]) Peak() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -192,7 +192,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Data() []T func (s *ArrayStack[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -223,7 +223,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Size() int func (s *ArrayStack[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -254,7 +254,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) IsEmpty() bool func (s *ArrayStack[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -287,7 +287,7 @@ func main() {
```go ```go
func (s *ArrayStack[T]) Clear() func (s *ArrayStack[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -331,7 +331,7 @@ type LinkedStack[T any] struct {
} }
func NewLinkedStack[T any]() *LinkedStack[T] func NewLinkedStack[T any]() *LinkedStack[T]
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -358,7 +358,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Push(value T) func (s *LinkedStack[T]) Push(value T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -389,7 +389,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Pop() (*T, error) func (s *LinkedStack[T]) Pop() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -424,7 +424,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Peak() (*T, error) func (s *LinkedStack[T]) Peak() (*T, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -459,7 +459,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Data() []T func (s *LinkedStack[T]) Data() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -490,7 +490,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Size() int func (s *LinkedStack[T]) Size() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -521,7 +521,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) IsEmpty() bool func (s *LinkedStack[T]) IsEmpty() bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -554,7 +554,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Clear() func (s *LinkedStack[T]) Clear()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -588,7 +588,7 @@ func main() {
```go ```go
func (s *LinkedStack[T]) Print() func (s *LinkedStack[T]) Print()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -62,7 +62,7 @@ type TreeNode[T any] struct {
Right *TreeNode[T] Right *TreeNode[T]
} }
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -103,7 +103,7 @@ func main() {
```go ```go
func (t *BSTree[T]) Insert(data T) func (t *BSTree[T]) Insert(data T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -149,7 +149,7 @@ func main() {
```go ```go
func (t *BSTree[T]) Delete(data T) func (t *BSTree[T]) Delete(data T)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -197,7 +197,7 @@ func main() {
```go ```go
func (t *BSTree[T]) PreOrderTraverse() []T func (t *BSTree[T]) PreOrderTraverse() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -243,7 +243,7 @@ func main() {
```go ```go
func (t *BSTree[T]) InOrderTraverse() []T func (t *BSTree[T]) InOrderTraverse() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -289,7 +289,7 @@ func main() {
```go ```go
func (t *BSTree[T]) PostOrderTraverse() []T func (t *BSTree[T]) PostOrderTraverse() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -335,7 +335,7 @@ func main() {
```go ```go
func (t *BSTree[T]) LevelOrderTraverse() []T func (t *BSTree[T]) LevelOrderTraverse() []T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -381,7 +381,7 @@ func main() {
```go ```go
func (t *BSTree[T]) Depth() int func (t *BSTree[T]) Depth() int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -427,7 +427,7 @@ func main() {
```go ```go
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -479,7 +479,7 @@ func main() {
```go ```go
func (t *BSTree[T]) Print() func (t *BSTree[T]) Print()
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -1,4 +1,5 @@
# Datetime # Datetime
Package datetime supports date and time format and compare. Package datetime supports date and time format and compare.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -11,6 +12,7 @@ Package datetime supports date and time format and compare.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/datetime" "github.com/duke-git/lancet/v2/datetime"
@@ -20,6 +22,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [AddDay](#AddDay) - [AddDay](#AddDay)
- [AddHour](#AddHour) - [AddHour](#AddHour)
- [AddMinute](#AddMinute) - [AddMinute](#AddMinute)
@@ -51,14 +54,14 @@ import (
- [ToFormatForTpl](#ToFormatForTpl) - [ToFormatForTpl](#ToFormatForTpl)
- [ToIso8601](#ToIso8601) - [ToIso8601](#ToIso8601)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
## Note: ## Note:
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows: 1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
- yyyy-mm-dd hh:mm:ss - yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm - yyyy-mm-dd hh:mm
- yyyy-mm-dd hh - yyyy-mm-dd hh
@@ -78,8 +81,8 @@ import (
- hh:mm:ss - hh:mm:ss
- mm:ss - mm:ss
### <span id="AddDay">AddDay</span> ### <span id="AddDay">AddDay</span>
<p>Add or sub days to time.</p> <p>Add or sub days to time.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -87,6 +90,7 @@ import (
```go ```go
func AddDay(t time.Time, day int64) time.Time func AddDay(t time.Time, day int64) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -100,15 +104,24 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Days := datetime.AddDay(now, 2)
before2Days := datetime.AddDay(now, -2)
fmt.Println(after2Days, before2Days) tomorrow := datetime.AddDay(now, 1)
diff1 := tomorrow.Sub(now)
yesterday := datetime.AddDay(now, -1)
diff2 := yesterday.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 24h0m0s
// -24h0m0s
} }
``` ```
### <span id="AddHour">AddHour</span> ### <span id="AddHour">AddHour</span>
<p>Add or sub hours to time.</p> <p>Add or sub hours to time.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -116,6 +129,7 @@ func main() {
```go ```go
func AddHour(t time.Time, hour int64) time.Time func AddHour(t time.Time, hour int64) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -129,14 +143,24 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Hours := datetime.AddHour(now, 2)
before2Hours := datetime.AddHour(now, -2)
fmt.Println(after2Hours, after2Hours) after2Hours := datetime.AddHour(now, 2)
diff1 := after2Hours.Sub(now)
before2Hours := datetime.AddHour(now, -2)
diff2 := before2Hours.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2h0m0s
// -2h0m0s
} }
``` ```
### <span id="AddMinute">AddMinute</span> ### <span id="AddMinute">AddMinute</span>
<p>Add or sub minutes to time.</p> <p>Add or sub minutes to time.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -144,6 +168,7 @@ func main() {
```go ```go
func AddMinute(t time.Time, minute int64) time.Time func AddMinute(t time.Time, minute int64) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -157,14 +182,24 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Minute := datetime.AddMinute(now, 2)
before2Minute := datetime.AddMinute(now, -2)
fmt.Println(after2Minute, before2Minute) after2Minutes := datetime.AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
before2Minutes := datetime.AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2m0s
// -2m0s
} }
``` ```
### <span id="BeginOfMinute">BeginOfMinute</span> ### <span id="BeginOfMinute">BeginOfMinute</span>
<p>Return beginning minute time of day.</p> <p>Return beginning minute time of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -172,6 +207,7 @@ func main() {
```go ```go
func BeginOfMinute(t time.Time) time.Time func BeginOfMinute(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -184,13 +220,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfMinute(td) result := datetime.BeginOfMinute(input)
fmt.Println(bm) //2022-02-15 15:48:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:50:00 +0000 UTC
} }
``` ```
### <span id="BeginOfHour">BeginOfHour</span> ### <span id="BeginOfHour">BeginOfHour</span>
<p>Return zero time of day.</p> <p>Return zero time of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -198,6 +239,7 @@ func main() {
```go ```go
func BeginOfHour(t time.Time) time.Time func BeginOfHour(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -210,13 +252,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfHour(td) result := datetime.BeginOfHour(input)
fmt.Println(bm) //2022-02-15 15:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfDay">BeginOfDay</span> ### <span id="BeginOfDay">BeginOfDay</span>
<p>Return begin time of day.</p> <p>Return begin time of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -224,6 +271,7 @@ func main() {
```go ```go
func BeginOfDay(t time.Time) time.Time func BeginOfDay(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -236,15 +284,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfDay(td) result := datetime.BeginOfDay(input)
fmt.Println(bm) //2022-02-15 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfWeek">BeginOfWeek</span> ### <span id="BeginOfWeek">BeginOfWeek</span>
<p>Return beginning time of week, week begin from Sunday.</p> <p>Return beginning time of week, week begin from Sunday.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -252,6 +303,7 @@ func main() {
```go ```go
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -264,15 +316,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfWeek(td) result := datetime.BeginOfWeek(input)
fmt.Println(bm) //2022-02-13 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfMonth">BeginOfMonth</span> ### <span id="BeginOfMonth">BeginOfMonth</span>
<p>Return beginning time of month</p> <p>Return beginning time of month</p>
<b>Signature:</b> <b>Signature:</b>
@@ -280,6 +335,7 @@ func main() {
```go ```go
func BeginOfMonth(t time.Time) time.Time func BeginOfMonth(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -292,14 +348,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfMonth(td) result := datetime.BeginOfMonth(input)
fmt.Println(bm) //2022-02-01 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfYear">BeginOfYear</span> ### <span id="BeginOfYear">BeginOfYear</span>
<p>Return beginning time of year.</p> <p>Return beginning time of year.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -307,6 +367,7 @@ func main() {
```go ```go
func BeginOfYear(t time.Time) time.Time func BeginOfYear(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -319,15 +380,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfYear(td) result := datetime.BeginOfYear(input)
fmt.Println(bm) //2022-01-01 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
} }
``` ```
### <span id="EndOfMinute">EndOfMinute</span> ### <span id="EndOfMinute">EndOfMinute</span>
<p>Return end time minute of day.</p> <p>Return end time minute of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -335,6 +399,7 @@ func main() {
```go ```go
func EndOfMinute(t time.Time) time.Time func EndOfMinute(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -347,13 +412,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfMinute(td) result := datetime.EndOfMinute(input)
fmt.Println(bm) //2022-02-15 15:48:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:50:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfHour">EndOfHour</span> ### <span id="EndOfHour">EndOfHour</span>
<p>Return end time hour of day.</p> <p>Return end time hour of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -361,6 +431,7 @@ func main() {
```go ```go
func EndOfHour(t time.Time) time.Time func EndOfHour(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -373,13 +444,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfHour(td) result := datetime.EndOfHour(input)
fmt.Println(bm) //2022-02-15 15:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfDay">EndOfDay</span> ### <span id="EndOfDay">EndOfDay</span>
<p>Return end time hour of day.</p> <p>Return end time hour of day.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -387,6 +463,7 @@ func main() {
```go ```go
func EndOfDay(t time.Time) time.Time func EndOfDay(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -399,15 +476,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfDay(td) result := datetime.EndOfDay(input)
fmt.Println(bm) //2022-02-15 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfWeek">EndOfWeek</span> ### <span id="EndOfWeek">EndOfWeek</span>
<p>Return end time of week, week end with Saturday.</p> <p>Return end time of week, week end with Saturday.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -415,6 +495,7 @@ func main() {
```go ```go
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -427,15 +508,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfWeek(td) result := datetime.EndOfWeek(input)
fmt.Println(bm) //2022-02-19 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-14 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfMonth">EndOfMonth</span> ### <span id="EndOfMonth">EndOfMonth</span>
<p>Return end time of month</p> <p>Return end time of month</p>
<b>Signature:</b> <b>Signature:</b>
@@ -443,6 +527,7 @@ func main() {
```go ```go
func EndOfMonth(t time.Time) time.Time func EndOfMonth(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -455,14 +540,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfMonth(td) result := datetime.EndOfMonth(input)
fmt.Println(bm) //2022-02-28 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-31 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfYear">EndOfYear</span> ### <span id="EndOfYear">EndOfYear</span>
<p>Return beginning time of year.</p> <p>Return beginning time of year.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -470,6 +559,7 @@ func main() {
```go ```go
func EndOfYear(t time.Time) time.Time func EndOfYear(t time.Time) time.Time
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -482,14 +572,18 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfYear(td) result := datetime.EndOfYear(input)
fmt.Println(bm) //2022-12-31 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-12-31 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="GetNowDate">GetNowDate</span> ### <span id="GetNowDate">GetNowDate</span>
<p>Get current date string, format is yyyy-mm-dd.</p> <p>Get current date string, format is yyyy-mm-dd.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -497,6 +591,7 @@ func main() {
```go ```go
func GetNowDate() string func GetNowDate() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -511,12 +606,16 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
currentDate := datetime.GetNowDate() currentDate := datetime.GetNowDate()
fmt.Println(currentDate) // 2022-01-28
fmt.Println(currentDate)
// Output:
// 2022-01-28
} }
``` ```
### <span id="GetNowTime">GetNowTime</span> ### <span id="GetNowTime">GetNowTime</span>
<p>Get current time string, format is hh:mm:ss.</p> <p>Get current time string, format is hh:mm:ss.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -524,6 +623,7 @@ func main() {
```go ```go
func GetNowTime() string func GetNowTime() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -538,12 +638,16 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
currentTime := datetime.GetNowTime() currentTime := datetime.GetNowTime()
fmt.Println(currentDate) // 15:57:33
fmt.Println(currentTime) // 15:57:33
// Output:
// 15:57:33
} }
``` ```
### <span id="GetNowDateTime">GetNowDateTime</span> ### <span id="GetNowDateTime">GetNowDateTime</span>
<p>Get current date time string, format is yyyy-mm-dd hh:mm:ss.</p> <p>Get current date time string, format is yyyy-mm-dd hh:mm:ss.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -551,6 +655,7 @@ func main() {
```go ```go
func GetNowDateTime() string func GetNowDateTime() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -565,12 +670,16 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
current := datetime.GetNowDateTime() current := datetime.GetNowDateTime()
fmt.Println(current) // 2022-01-28 15:59:33
fmt.Println(current)
// Output:
// 2022-01-28 15:59:33
} }
``` ```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span> ### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>Return timestamp of zero hour (timestamp of 00:00).</p> <p>Return timestamp of zero hour (timestamp of 00:00).</p>
<b>Signature:</b> <b>Signature:</b>
@@ -578,6 +687,7 @@ func main() {
```go ```go
func GetZeroHourTimestamp() int64 func GetZeroHourTimestamp() int64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -592,12 +702,16 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp() zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime) // 1643299200
fmt.Println(zeroTime)
// Output:
// 1643299200
} }
``` ```
### <span id="GetNightTimestamp">GetNightTimestamp</span> ### <span id="GetNightTimestamp">GetNightTimestamp</span>
<p>Return timestamp of zero hour (timestamp of 23:59).</p> <p>Return timestamp of zero hour (timestamp of 23:59).</p>
<b>Signature:</b> <b>Signature:</b>
@@ -605,6 +719,7 @@ func main() {
```go ```go
func GetNightTimestamp() int64 func GetNightTimestamp() int64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -619,11 +734,16 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
nightTime := datetime.GetNightTimestamp() nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime) // 1643385599
fmt.Println(nightTime)
// Output:
// 1643385599
} }
``` ```
### <span id="FormatTimeToStr">FormatTimeToStr</span> ### <span id="FormatTimeToStr">FormatTimeToStr</span>
<p>Format time to string, `format` param specification see note 1.</p> <p>Format time to string, `format` param specification see note 1.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -631,6 +751,7 @@ func main() {
```go ```go
func FormatTimeToStr(t time.Time, format string) string func FormatTimeToStr(t time.Time, format string) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -643,14 +764,25 @@ import (
) )
func main() { func main() {
now := time.Now() t, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
timeStr := datetime.FormatTimeToStr(now, "yyyy/mm/dd hh:mm:ss")
fmt.Println(timeStr) //2022/01/28 16:07:44 result1 := datetime.FormatTimeToStr(t, "yyyy-mm-dd hh:mm:ss")
result2 := datetime.FormatTimeToStr(t, "yyyy-mm-dd")
result3 := datetime.FormatTimeToStr(t, "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
} }
``` ```
### <span id="FormatStrToTime">FormatStrToTime</span> ### <span id="FormatStrToTime">FormatStrToTime</span>
<p>Format string to time, `format` param specification see note 1.</p> <p>Format string to time, `format` param specification see note 1.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -658,6 +790,7 @@ func main() {
```go ```go
func FormatStrToTime(str, format string) (time.Time, error) func FormatStrToTime(str, format string) (time.Time, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -669,14 +802,23 @@ import (
) )
func main() { func main() {
time := datetime.FormatStrToTime("2006-01-02 15:04:05", "yyyy/mm/dd hh:mm:ss") result1, _ := datetime.FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
fmt.Println(time) result2, _ := datetime.FormatStrToTime("2021-01-02", "yyyy-mm-dd")
result3, _ := datetime.FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08 +0000 UTC
// 2021-01-02 00:00:00 +0000 UTC
// 2021-01-02 16:04:08 +0000 UTC
} }
``` ```
### <span id="NewUnixNow">NewUnixNow</span> ### <span id="NewUnixNow">NewUnixNow</span>
<p>Return unix timestamp of current time</p> <p>Return unix timestamp of current time</p>
<b>Signature:</b> <b>Signature:</b>
@@ -687,6 +829,7 @@ type theTime struct {
} }
func NewUnixNow() *theTime func NewUnixNow() *theTime
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -699,12 +842,15 @@ import (
func main() { func main() {
tm := datetime.NewUnixNow() tm := datetime.NewUnixNow()
fmt.Println(tm) //&{1647597438} fmt.Println(tm)
// Output:
// &{1647597438}
} }
``` ```
### <span id="NewUnix">NewUnix</span> ### <span id="NewUnix">NewUnix</span>
<p>Return unix timestamp of specified int64 value.</p> <p>Return unix timestamp of specified int64 value.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -715,6 +861,7 @@ type theTime struct {
} }
func NewUnix(unix int64) *theTime func NewUnix(unix int64) *theTime
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -727,13 +874,15 @@ import (
func main() { func main() {
tm := datetime.NewUnix(1647597438) tm := datetime.NewUnix(1647597438)
fmt.Println(tm) //&{1647597438} fmt.Println(tm)
// Output:
// &{1647597438}
} }
``` ```
### <span id="NewFormat">NewFormat</span> ### <span id="NewFormat">NewFormat</span>
<p>Return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".</p> <p>Return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".</p>
<b>Signature:</b> <b>Signature:</b>
@@ -744,6 +893,7 @@ type theTime struct {
} }
func NewFormat(t string) (*theTime, error) func NewFormat(t string) (*theTime, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -756,14 +906,15 @@ import (
func main() { func main() {
tm, err := datetime.NewFormat("2022-03-18 17:04:05") tm, err := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm) //&{1647594245} fmt.Println(tm)
// Output:
// &{1647594245}
} }
``` ```
### <span id="NewISO8601">NewISO8601</span> ### <span id="NewISO8601">NewISO8601</span>
<p>Return unix timestamp of specified iso8601 time string.</p> <p>Return unix timestamp of specified iso8601 time string.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -774,6 +925,7 @@ type theTime struct {
} }
func NewISO8601(iso8601 string) (*theTime, error) func NewISO8601(iso8601 string) (*theTime, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -786,13 +938,15 @@ import (
func main() { func main() {
tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z") tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
fmt.Println(tm) //&{1136214245} fmt.Println(tm)
// Output:
// &{1136214245}
} }
``` ```
### <span id="ToUnix">ToUnix</span> ### <span id="ToUnix">ToUnix</span>
<p>Return unix timestamp.</p> <p>Return unix timestamp.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -800,6 +954,7 @@ func main() {
```go ```go
func (t *theTime) ToUnix() int64 func (t *theTime) ToUnix() int64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -812,13 +967,15 @@ import (
func main() { func main() {
tm := datetime.NewUnixNow() tm := datetime.NewUnixNow()
fmt.Println(tm.ToUnix()) //1647597438 fmt.Println(tm.ToUnix())
// Output:
// 1647597438
} }
``` ```
### <span id="ToFormat">ToFormat</span> ### <span id="ToFormat">ToFormat</span>
<p>Return time string 'yyyy-mm-dd hh:mm:ss'.</p> <p>Return time string 'yyyy-mm-dd hh:mm:ss'.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -826,6 +983,7 @@ func main() {
```go ```go
func (t *theTime) ToFormat() string func (t *theTime) ToFormat() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -838,13 +996,15 @@ import (
func main() { func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05") tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm.ToFormat()) //"2022-03-18 17:04:05" fmt.Println(tm.ToFormat())
// Output:
// 2022-03-18 17:04:05
} }
``` ```
### <span id="ToFormatForTpl">ToFormatForTpl</span> ### <span id="ToFormatForTpl">ToFormatForTpl</span>
<p>Return the time string which format is specified tpl.</p> <p>Return the time string which format is specified tpl.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -852,6 +1012,7 @@ func main() {
```go ```go
func (t *theTime) ToFormatForTpl(tpl string) string func (t *theTime) ToFormatForTpl(tpl string) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -865,12 +1026,15 @@ import (
func main() { func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05") tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
ts := tm.ToFormatForTpl("2006/01/02 15:04:05") ts := tm.ToFormatForTpl("2006/01/02 15:04:05")
fmt.Println(ts) //"2022/03/18 17:04:05" fmt.Println(ts)
// Output:
// 2022/03/18 17:04:05
} }
``` ```
### <span id="ToIso8601">ToIso8601</span> ### <span id="ToIso8601">ToIso8601</span>
<p>Return iso8601 time string.</p> <p>Return iso8601 time string.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -878,6 +1042,7 @@ func main() {
```go ```go
func (t *theTime) ToIso8601() string func (t *theTime) ToIso8601() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -891,6 +1056,9 @@ import (
func main() { func main() {
tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z") tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
ts := tm.ToIso8601() ts := tm.ToIso8601()
fmt.Println(ts) //"2006-01-02T23:04:05+08:00" fmt.Println(ts)
// Output:
// 2006-01-02T23:04:05+08:00
} }
``` ```

View File

@@ -77,14 +77,16 @@ import (
### <span id="AddDay">AddDay</span> ### <span id="AddDay">AddDay</span>
<p>将日期加/减天数</p>
<b>函数签名:</b> <p>将日期加/减天数。</p>
<b>Signature:</b>
```go ```go
func AddDay(t time.Time, day int64) time.Time func AddDay(t time.Time, day int64) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -97,23 +99,33 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Days := datetime.AddDay(now, 2)
before2Days := datetime.AddDay(now, -2)
fmt.Println(after2Days, before2Days) tomorrow := datetime.AddDay(now, 1)
diff1 := tomorrow.Sub(now)
yesterday := datetime.AddDay(now, -1)
diff2 := yesterday.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 24h0m0s
// -24h0m0s
} }
``` ```
### <span id="AddHour">AddHour</span> ### <span id="AddHour">AddHour</span>
<p>将日期加/减小时数</p>
<b>函数签名:</b> <p>将日期加/减小时数。</p>
<b>Signature:</b>
```go ```go
func AddHour(t time.Time, hour int64) time.Time func AddHour(t time.Time, hour int64) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -126,22 +138,33 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Hours := datetime.AddHour(now, 2)
before2Hours := datetime.AddHour(now, -2)
fmt.Println(after2Hours, after2Hours) after2Hours := datetime.AddHour(now, 2)
diff1 := after2Hours.Sub(now)
before2Hours := datetime.AddHour(now, -2)
diff2 := before2Hours.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2h0m0s
// -2h0m0s
} }
``` ```
### <span id="AddMinute">AddMinute</span> ### <span id="AddMinute">AddMinute</span>
<p>将日期加/减分钟数</p>
<b>函数签名:</b> <p>将日期加/减分钟数。</p>
<b>Signature:</b>
```go ```go
func AddMinute(t time.Time, minute int64) time.Time func AddMinute(t time.Time, minute int64) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -154,22 +177,33 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
after2Minute := datetime.AddMinute(now, 2)
before2Minute := datetime.AddMinute(now, -2)
fmt.Println(after2Minute, before2Minute) after2Minutes := datetime.AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
before2Minutes := datetime.AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
fmt.Println(diff1)
fmt.Println(diff2)
// Output:
// 2m0s
// -2m0s
} }
``` ```
### <span id="BeginOfMinute">BeginOfMinute</span> ### <span id="BeginOfMinute">BeginOfMinute</span>
<p>返回指定时间的分钟开始时间</p>
<b>函数签名:</b> <p>返回指定时间的分钟开始时间。</p>
<b>Signature:</b>
```go ```go
func BeginOfMinute(t time.Time) time.Time func BeginOfMinute(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -181,21 +215,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfMinute(td) result := datetime.BeginOfMinute(input)
fmt.Println(bm) //2022-02-15 15:48:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:50:00 +0000 UTC
} }
``` ```
### <span id="BeginOfHour">BeginOfHour</span> ### <span id="BeginOfHour">BeginOfHour</span>
<p>返回指定时间的小时开始时间</p>
<b>函数签名:</b> <p>返回指定时间的小时开始时间。</p>
<b>Signature:</b>
```go ```go
func BeginOfHour(t time.Time) time.Time func BeginOfHour(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -207,21 +247,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfHour(td) result := datetime.BeginOfHour(input)
fmt.Println(bm) //2022-02-15 15:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfDay">BeginOfDay</span> ### <span id="BeginOfDay">BeginOfDay</span>
<p>返回指定时间的当天开始时间</p>
<b>函数签名:</b> <p>返回指定时间的当天开始时间。</p>
<b>Signature:</b>
```go ```go
func BeginOfDay(t time.Time) time.Time func BeginOfDay(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -233,23 +279,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfDay(td) result := datetime.BeginOfDay(input)
fmt.Println(bm) //2022-02-15 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfWeek">BeginOfWeek</span> ### <span id="BeginOfWeek">BeginOfWeek</span>
<p>返回指定时间的每周开始时间,默认开始时间星期日</p>
<b>函数签名:</b> <p>返回指定时间的每周开始时间,默认开始时间星期日。</p>
<b>Signature:</b>
```go ```go
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -261,23 +311,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfWeek(td) result := datetime.BeginOfWeek(input)
fmt.Println(bm) //2022-02-13 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfMonth">BeginOfMonth</span> ### <span id="BeginOfMonth">BeginOfMonth</span>
<p>返回指定时间的当月开始时间</p>
<b>函数签名:</b> <p>返回指定时间的当月开始时间。</p>
<b>Signature:</b>
```go ```go
func BeginOfMonth(t time.Time) time.Time func BeginOfMonth(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -289,22 +343,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfMonth(td) result := datetime.BeginOfMonth(input)
fmt.Println(bm) //2022-02-01 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
} }
``` ```
### <span id="BeginOfYear">BeginOfYear</span> ### <span id="BeginOfYear">BeginOfYear</span>
<p>返回指定时间的当年开始时间</p> <p>返回指定时间的当年开始时间</p>
<b>函数签名:</b> <b>Signature:</b>
```go ```go
func BeginOfYear(t time.Time) time.Time func BeginOfYear(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -316,23 +375,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.BeginOfYear(td) result := datetime.BeginOfYear(input)
fmt.Println(bm) //2022-01-01 00:00:00 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-01 00:00:00 +0000 UTC
} }
``` ```
### <span id="EndOfMinute">EndOfMinute</span> ### <span id="EndOfMinute">EndOfMinute</span>
<p>返回指定时间的分钟结束时间</p>
<b>函数签名:</b> <p>返回指定时间的分钟结束时间。</p>
<b>Signature:</b>
```go ```go
func EndOfMinute(t time.Time) time.Time func EndOfMinute(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -344,21 +407,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfMinute(td) result := datetime.EndOfMinute(input)
fmt.Println(bm) //2022-02-15 15:48:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:50:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfHour">EndOfHour</span> ### <span id="EndOfHour">EndOfHour</span>
<p>返回指定时间的小时结束时间</p>
<b>函数签名:</b> <p>返回指定时间的小时结束时间。</p>
<b>Signature:</b>
```go ```go
func EndOfHour(t time.Time) time.Time func EndOfHour(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -370,21 +439,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfHour(td) result := datetime.EndOfHour(input)
fmt.Println(bm) //2022-02-15 15:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 18:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfDay">EndOfDay</span> ### <span id="EndOfDay">EndOfDay</span>
<p>返回指定时间的当天结束时间.</p>
<b>函数签名:</b> <p>返回指定时间的当天结束时间。</p>
<b>Signature:</b>
```go ```go
func EndOfDay(t time.Time) time.Time func EndOfDay(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -396,23 +471,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfDay(td) result := datetime.EndOfDay(input)
fmt.Println(bm) //2022-02-15 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-08 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfWeek">EndOfWeek</span> ### <span id="EndOfWeek">EndOfWeek</span>
<p>返回指定时间的星期结束时间,默认结束时间星期六</p>
<b>函数签名:</b> <p>返回指定时间的星期结束时间,默认结束时间星期六。</p>
<b>Signature:</b>
```go ```go
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -424,23 +503,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfWeek(td) result := datetime.EndOfWeek(input)
fmt.Println(bm) //2022-02-19 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-14 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfMonth">EndOfMonth</span> ### <span id="EndOfMonth">EndOfMonth</span>
<p>返回指定时间的月份结束时间</p>
<b>函数签名:</b> <p>返回指定时间的当月结束时间。</p>
<b>Signature:</b>
```go ```go
func EndOfMonth(t time.Time) time.Time func EndOfMonth(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -452,22 +535,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfMonth(td) result := datetime.EndOfMonth(input)
fmt.Println(bm) //2022-02-28 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-01-31 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="EndOfYear">EndOfYear</span> ### <span id="EndOfYear">EndOfYear</span>
<p>返回指定时间的年份结束时间</p>
<b>函数签名:</b> <p>返回指定时间的当年结束时间。</p>
<b>Signature:</b>
```go ```go
func EndOfYear(t time.Time) time.Time func EndOfYear(t time.Time) time.Time
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -479,22 +567,27 @@ import (
) )
func main() { func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local) input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
bm := datetime.EndOfYear(td) result := datetime.EndOfYear(input)
fmt.Println(bm) //2022-12-31 23:59:59.999999999 +0800 CST
fmt.Println(result)
// Output:
// 2023-12-31 23:59:59.999999999 +0000 UTC
} }
``` ```
### <span id="GetNowDate">GetNowDate</span> ### <span id="GetNowDate">GetNowDate</span>
<p>获取当天日期返回格式yyyy-mm-dd</p>
<b>函数签名:</b> <p>获取当天日期返回格式yyyy-mm-dd。</p>
<b>Signature:</b>
```go ```go
func GetNowDate() string func GetNowDate() string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -508,20 +601,25 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
currentDate := datetime.GetNowDate() currentDate := datetime.GetNowDate()
fmt.Println(currentDate) // 2022-01-28
fmt.Println(currentDate)
// Output:
// 2022-01-28
} }
``` ```
### <span id="GetNowTime">GetNowTime</span> ### <span id="GetNowTime">GetNowTime</span>
<p>获取当时时间返回格式hh:mm:ss</p> <p>获取当时时间返回格式hh:mm:ss</p>
<b>函数签名:</b> <b>Signature:</b>
```go ```go
func GetNowTime() string func GetNowTime() string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -535,20 +633,25 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
currentTime := datetime.GetNowTime() currentTime := datetime.GetNowTime()
fmt.Println(currentDate) // 15:57:33
fmt.Println(currentTime) // 15:57:33
// Output:
// 15:57:33
} }
``` ```
### <span id="GetNowDateTime">GetNowDateTime</span> ### <span id="GetNowDateTime">GetNowDateTime</span>
<p>获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss.</p>
<b>函数签名:</b> <p>获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss。</p>
<b>Signature:</b>
```go ```go
func GetNowDateTime() string func GetNowDateTime() string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -562,20 +665,25 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
current := datetime.GetNowDateTime() current := datetime.GetNowDateTime()
fmt.Println(current) // 2022-01-28 15:59:33
fmt.Println(current)
// Output:
// 2022-01-28 15:59:33
} }
``` ```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span> ### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>获取零时时间戳(timestamp of 00:00).</p>
<b>函数签名:</b> <p>获取零点时间戳(timestamp of 00:00)</p>
<b>Signature:</b>
```go ```go
func GetZeroHourTimestamp() int64 func GetZeroHourTimestamp() int64
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -589,20 +697,25 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp() zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime) // 1643299200
fmt.Println(zeroTime)
// Output:
// 1643299200
} }
``` ```
### <span id="GetNightTimestamp">GetNightTimestamp</span> ### <span id="GetNightTimestamp">GetNightTimestamp</span>
<p>获取午夜时间戳(timestamp of 23:59).</p>
<b>函数签名:</b> <p>获取午夜时间戳(timestamp of 23:59)。</p>
<b>Signature:</b>
```go ```go
func GetNightTimestamp() int64 func GetNightTimestamp() int64
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -616,19 +729,25 @@ import (
func main() { func main() {
now := time.Now() now := time.Now()
nightTime := datetime.GetNightTimestamp() nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime) // 1643385599
fmt.Println(nightTime)
// Output:
// 1643385599
} }
``` ```
### <span id="FormatTimeToStr">FormatTimeToStr</span> ### <span id="FormatTimeToStr">FormatTimeToStr</span>
<p>将日期格式化成字符串,`format` 参数格式参考注<sup>1</sup></p>
<b>函数签名:</b> <p>将日期格式化成字符串,`format` 参数格式参考注1。</p>
<b>Signature:</b>
```go ```go
func FormatTimeToStr(t time.Time, format string) string func FormatTimeToStr(t time.Time, format string) string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -640,22 +759,34 @@ import (
) )
func main() { func main() {
now := time.Now() t, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
timeStr := datetime.FormatTimeToStr(now, "yyyy/mm/dd hh:mm:ss")
fmt.Println(timeStr) //2022/01/28 16:07:44 result1 := datetime.FormatTimeToStr(t, "yyyy-mm-dd hh:mm:ss")
result2 := datetime.FormatTimeToStr(t, "yyyy-mm-dd")
result3 := datetime.FormatTimeToStr(t, "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08
// 2021-01-02
// 02-01-21 16:04:08
} }
``` ```
### <span id="FormatStrToTime">FormatStrToTime</span> ### <span id="FormatStrToTime">FormatStrToTime</span>
<p>将字符串格式化成时间,`format` 参数格式参考注<sup>1</sup></p>
<b>函数签名:</b> <p>将字符串格式化成时间,`format` 参数格式参考注1。</p>
<b>Signature:</b>
```go ```go
func FormatStrToTime(str, format string) (time.Time, error) func FormatStrToTime(str, format string) (time.Time, error)
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -666,16 +797,26 @@ import (
) )
func main() { func main() {
time := datetime.FormatStrToTime("2006-01-02 15:04:05", "yyyy/mm/dd hh:mm:ss") result1, _ := datetime.FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
fmt.Println(time) result2, _ := datetime.FormatStrToTime("2021-01-02", "yyyy-mm-dd")
result3, _ := datetime.FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 2021-01-02 16:04:08 +0000 UTC
// 2021-01-02 00:00:00 +0000 UTC
// 2021-01-02 16:04:08 +0000 UTC
} }
``` ```
### <span id="NewUnixNow">NewUnixNow</span> ### <span id="NewUnixNow">NewUnixNow</span>
<p>创建一个当前时间的unix时间戳</p>
<b>函数签名:</b> <p>创建一个当前时间的unix时间戳。</p>
<b>Signature:</b>
```go ```go
type theTime struct { type theTime struct {
@@ -683,7 +824,8 @@ type theTime struct {
} }
func NewUnixNow() *theTime func NewUnixNow() *theTime
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -695,15 +837,18 @@ import (
func main() { func main() {
tm := datetime.NewUnixNow() tm := datetime.NewUnixNow()
fmt.Println(tm) //&{1647597438} fmt.Println(tm)
// Output:
// &{1647597438}
} }
``` ```
### <span id="NewUnix">NewUnix</span> ### <span id="NewUnix">NewUnix</span>
<p>创建一个unix时间戳</p>
<b>函数签名:</b> <p>创建一个unix时间戳。</p>
<b>Signature:</b>
```go ```go
type theTime struct { type theTime struct {
@@ -711,7 +856,8 @@ type theTime struct {
} }
func NewUnix(unix int64) *theTime func NewUnix(unix int64) *theTime
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -723,16 +869,18 @@ import (
func main() { func main() {
tm := datetime.NewUnix(1647597438) tm := datetime.NewUnix(1647597438)
fmt.Println(tm) //&{1647597438} fmt.Println(tm)
// Output:
// &{1647597438}
} }
``` ```
### <span id="NewFormat">NewFormat</span> ### <span id="NewFormat">NewFormat</span>
<p>创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳</p>
<b>函数签名:</b> <p>创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳。</p>
<b>Signature:</b>
```go ```go
type theTime struct { type theTime struct {
@@ -740,7 +888,8 @@ type theTime struct {
} }
func NewFormat(t string) (*theTime, error) func NewFormat(t string) (*theTime, error)
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -752,17 +901,18 @@ import (
func main() { func main() {
tm, err := datetime.NewFormat("2022-03-18 17:04:05") tm, err := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm) //&{1647594245} fmt.Println(tm)
// Output:
// &{1647594245}
} }
``` ```
### <span id="NewISO8601">NewISO8601</span> ### <span id="NewISO8601">NewISO8601</span>
<p>创建一个iso8601格式时间字符串的unix时间戳</p>
<b>函数签名:</b> <p>创建一个iso8601格式时间字符串的unix时间戳。</p>
<b>Signature:</b>
```go ```go
type theTime struct { type theTime struct {
@@ -770,7 +920,8 @@ type theTime struct {
} }
func NewISO8601(iso8601 string) (*theTime, error) func NewISO8601(iso8601 string) (*theTime, error)
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -782,21 +933,24 @@ import (
func main() { func main() {
tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z") tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
fmt.Println(tm) //&{1136214245} fmt.Println(tm)
// Output:
// &{1136214245}
} }
``` ```
### <span id="ToUnix">ToUnix</span> ### <span id="ToUnix">ToUnix</span>
<p>返回unix时间戳</p>
<b>函数签名:</b> <p>返回unix时间戳。</p>
<b>Signature:</b>
```go ```go
func (t *theTime) ToUnix() int64 func (t *theTime) ToUnix() int64
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -808,21 +962,24 @@ import (
func main() { func main() {
tm := datetime.NewUnixNow() tm := datetime.NewUnixNow()
fmt.Println(tm.ToUnix()) //1647597438 fmt.Println(tm.ToUnix())
// Output:
// 1647597438
} }
``` ```
### <span id="ToFormat">ToFormat</span> ### <span id="ToFormat">ToFormat</span>
<p>返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串</p>
<b>函数签名:</b> <p>返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串。</p>
<b>Signature:</b>
```go ```go
func (t *theTime) ToFormat() string func (t *theTime) ToFormat() string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -834,21 +991,24 @@ import (
func main() { func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05") tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm.ToFormat()) //"2022-03-18 17:04:05" fmt.Println(tm.ToFormat())
// Output:
// 2022-03-18 17:04:05
} }
``` ```
### <span id="ToFormatForTpl">ToFormatForTpl</span> ### <span id="ToFormatForTpl">ToFormatForTpl</span>
<p>返回tpl格式指定的日期字符串</p>
<b>函数签名:</b> <p>返回tpl格式指定的日期字符串。</p>
<b>Signature:</b>
```go ```go
func (t *theTime) ToFormatForTpl(tpl string) string func (t *theTime) ToFormatForTpl(tpl string) string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -861,20 +1021,24 @@ import (
func main() { func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05") tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
ts := tm.ToFormatForTpl("2006/01/02 15:04:05") ts := tm.ToFormatForTpl("2006/01/02 15:04:05")
fmt.Println(ts) //"2022/03/18 17:04:05" fmt.Println(ts)
// Output:
// 2022/03/18 17:04:05
} }
``` ```
### <span id="ToIso8601">ToIso8601</span> ### <span id="ToIso8601">ToIso8601</span>
<p>返回iso8601日期字符串</p>
<b>函数签名:</b> <p>返回iso8601日期字符串。</p>
<b>Signature:</b>
```go ```go
func (t *theTime) ToIso8601() string func (t *theTime) ToIso8601() string
``` ```
<b>例子:</b>
<b>Example:</b>
```go ```go
package main package main
@@ -887,6 +1051,9 @@ import (
func main() { func main() {
tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z") tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
ts := tm.ToIso8601() ts := tm.ToIso8601()
fmt.Println(ts) //"2006-01-02T23:04:05+08:00" fmt.Println(ts)
// Output:
// 2006-01-02T23:04:05+08:00
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Fileutil # Fileutil
Package fileutil implements some basic functions for file operations. Package fileutil implements some basic functions for file operations.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ Package fileutil implements some basic functions for file operations.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/fileutil" "github.com/duke-git/lancet/v2/fileutil"
@@ -19,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [ClearFile](#ClearFile) - [ClearFile](#ClearFile)
- [CreateFile](#CreateFile) - [CreateFile](#CreateFile)
- [CreateDir](#CreateDir) - [CreateDir](#CreateDir)
@@ -40,9 +43,8 @@ import (
## Documentation ## Documentation
### <span id="ClearFile">ClearFile</span> ### <span id="ClearFile">ClearFile</span>
<p>Clear the file content, write empty string to the file.</p> <p>Clear the file content, write empty string to the file.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -50,6 +52,7 @@ import (
```go ```go
func ClearFile(path string) error func ClearFile(path string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -69,6 +72,7 @@ func main() {
``` ```
### <span id="CreateFile">CreateFile</span> ### <span id="CreateFile">CreateFile</span>
<p>Create file in path. return true if create succeed.</p> <p>Create file in path. return true if create succeed.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -76,6 +80,7 @@ func main() {
```go ```go
func CreateFile(path string) bool func CreateFile(path string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -92,9 +97,8 @@ func main() {
} }
``` ```
### <span id="CreateDir">CreateDir</span> ### <span id="CreateDir">CreateDir</span>
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p> <p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -102,6 +106,7 @@ func main() {
```go ```go
func CreateDir(absPath string) error func CreateDir(absPath string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -118,8 +123,8 @@ func main() {
} }
``` ```
### <span id="CopyFile">CopyFile</span> ### <span id="CopyFile">CopyFile</span>
<p>Copy src file to dest file. If dest file exist will overwrite it.</p> <p>Copy src file to dest file. If dest file exist will overwrite it.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -127,6 +132,7 @@ func main() {
```go ```go
func CopyFile(srcFilePath string, dstFilePath string) error func CopyFile(srcFilePath string, dstFilePath string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -145,9 +151,8 @@ func main() {
} }
``` ```
### <span id="FileMode">FileMode</span> ### <span id="FileMode">FileMode</span>
<p>Return file mode infomation.</p> <p>Return file mode infomation.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -155,6 +160,7 @@ func main() {
```go ```go
func FileMode(path string) (fs.FileMode, error) func FileMode(path string) (fs.FileMode, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -174,9 +180,8 @@ func main() {
} }
``` ```
### <span id="MiMeType">MiMeType</span> ### <span id="MiMeType">MiMeType</span>
<p>Get file mime type, 'file' param's type should be string or *os.File.</p> <p>Get file mime type, 'file' param's type should be string or *os.File.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -184,6 +189,7 @@ func main() {
```go ```go
func MiMeType(file any) string func MiMeType(file any) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -205,10 +211,8 @@ func main() {
} }
``` ```
### <span id="IsExist">IsExist</span> ### <span id="IsExist">IsExist</span>
<p>Checks if a file or directory exists.</p> <p>Checks if a file or directory exists.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -216,6 +220,7 @@ func main() {
```go ```go
func IsExist(path string) bool func IsExist(path string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -233,9 +238,8 @@ func main() {
} }
``` ```
### <span id="IsLink">IsLink</span> ### <span id="IsLink">IsLink</span>
<p>Checks if a file is symbol link or not.</p> <p>Checks if a file is symbol link or not.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -243,6 +247,7 @@ func main() {
```go ```go
func IsLink(path string) bool func IsLink(path string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -259,9 +264,8 @@ func main() {
} }
``` ```
### <span id="IsDir">IsDir</span> ### <span id="IsDir">IsDir</span>
<p>Checks if the path is directy or not.</p> <p>Checks if the path is directy or not.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -269,6 +273,7 @@ func main() {
```go ```go
func IsDir(path string) bool func IsDir(path string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -288,9 +293,8 @@ func main() {
} }
``` ```
### <span id="ListFileNames">ListFileNames</span> ### <span id="ListFileNames">ListFileNames</span>
<p>List all file names in given path.</p> <p>List all file names in given path.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -298,6 +302,7 @@ func main() {
```go ```go
func ListFileNames(path string) ([]string, error) func ListFileNames(path string) ([]string, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -314,9 +319,8 @@ func main() {
} }
``` ```
### <span id="RemoveFile">RemoveFile</span> ### <span id="RemoveFile">RemoveFile</span>
<p>Remove the file of path.</p> <p>Remove the file of path.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -324,6 +328,7 @@ func main() {
```go ```go
func RemoveFile(path string) error func RemoveFile(path string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -342,8 +347,8 @@ func main() {
} }
``` ```
### <span id="ReadFileToString">ReadFileToString</span> ### <span id="ReadFileToString">ReadFileToString</span>
<p>Return string of file content.</p> <p>Return string of file content.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -351,6 +356,7 @@ func main() {
```go ```go
func ReadFileToString(path string) (string, error) func ReadFileToString(path string) (string, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -374,9 +380,8 @@ func main() {
} }
``` ```
### <span id="ReadFileByLine">ReadFileByLine</span> ### <span id="ReadFileByLine">ReadFileByLine</span>
<p>Read file line by line, and return slice of lines</p> <p>Read file line by line, and return slice of lines</p>
<b>Signature:</b> <b>Signature:</b>
@@ -384,6 +389,7 @@ func main() {
```go ```go
func ReadFileByLine(path string)([]string, error) func ReadFileByLine(path string)([]string, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -408,9 +414,8 @@ func main() {
} }
``` ```
### <span id="Zip">Zip</span> ### <span id="Zip">Zip</span>
<p>Create a zip file of fpath, fpath could be a file or a directory.</p> <p>Create a zip file of fpath, fpath could be a file or a directory.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -418,6 +423,7 @@ func main() {
```go ```go
func Zip(fpath string, destPath string) error func Zip(fpath string, destPath string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -436,10 +442,8 @@ func main() {
} }
``` ```
### <span id="UnZip">UnZip</span> ### <span id="UnZip">UnZip</span>
<p>Unzip the file and save it to dest path.</p> <p>Unzip the file and save it to dest path.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -447,6 +451,7 @@ func main() {
```go ```go
func UnZip(zipFile string, destPath string) error func UnZip(zipFile string, destPath string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -464,8 +469,3 @@ func main() {
} }
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Fileutil # Fileutil
fileutil包支持文件基本操作。
fileutil 包支持文件基本操作。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ fileutil包支持文件基本操作。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/fileutil" "github.com/duke-git/lancet/v2/fileutil"
@@ -19,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [ClearFile](#ClearFile) - [ClearFile](#ClearFile)
- [CreateFile](#CreateFile) - [CreateFile](#CreateFile)
- [CreateDir](#CreateDir) - [CreateDir](#CreateDir)
@@ -39,9 +42,8 @@ import (
## 文档 ## 文档
### <span id="ClearFile">ClearFile</span> ### <span id="ClearFile">ClearFile</span>
<p>清空文件内容</p> <p>清空文件内容</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -49,7 +51,8 @@ import (
```go ```go
func ClearFile(path string) error func ClearFile(path string) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -68,6 +71,7 @@ func main() {
``` ```
### <span id="CreateFile">CreateFile</span> ### <span id="CreateFile">CreateFile</span>
<p>创建文件创建成功返回true, 否则返回false</p> <p>创建文件创建成功返回true, 否则返回false</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -75,7 +79,8 @@ func main() {
```go ```go
func CreateFile(path string) bool func CreateFile(path string) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -91,8 +96,8 @@ func main() {
} }
``` ```
### <span id="CreateDir">CreateDir</span> ### <span id="CreateDir">CreateDir</span>
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p> <p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -100,6 +105,7 @@ func main() {
```go ```go
func CreateDir(absPath string) error func CreateDir(absPath string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -116,9 +122,8 @@ func main() {
} }
``` ```
### <span id="CopyFile">CopyFile</span> ### <span id="CopyFile">CopyFile</span>
<p>拷贝文件,会覆盖原有的文件</p> <p>拷贝文件,会覆盖原有的文件</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -126,7 +131,8 @@ func main() {
```go ```go
func CopyFile(srcFilePath string, dstFilePath string) error func CopyFile(srcFilePath string, dstFilePath string) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -144,9 +150,8 @@ func main() {
} }
``` ```
### <span id="FileMode">FileMode</span> ### <span id="FileMode">FileMode</span>
<p>获取文件mode信息</p> <p>获取文件mode信息</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -154,7 +159,8 @@ func main() {
```go ```go
func FileMode(path string) (fs.FileMode, error) func FileMode(path string) (fs.FileMode, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -173,9 +179,8 @@ func main() {
} }
``` ```
### <span id="MiMeType">MiMeType</span> ### <span id="MiMeType">MiMeType</span>
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p> <p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -183,7 +188,8 @@ func main() {
```go ```go
func MiMeType(file any) string func MiMeType(file any) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -204,10 +210,8 @@ func main() {
} }
``` ```
### <span id="IsExist">IsExist</span> ### <span id="IsExist">IsExist</span>
<p>判断文件或目录是否存在</p> <p>判断文件或目录是否存在</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -215,7 +219,8 @@ func main() {
```go ```go
func IsExist(path string) bool func IsExist(path string) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -232,9 +237,8 @@ func main() {
} }
``` ```
### <span id="IsLink">IsLink</span> ### <span id="IsLink">IsLink</span>
<p>判断文件是否是符号链接</p> <p>判断文件是否是符号链接</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -242,7 +246,8 @@ func main() {
```go ```go
func IsLink(path string) bool func IsLink(path string) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -258,9 +263,8 @@ func main() {
} }
``` ```
### <span id="IsDir">IsDir</span> ### <span id="IsDir">IsDir</span>
<p>判断参数是否是目录</p> <p>判断参数是否是目录</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -268,7 +272,8 @@ func main() {
```go ```go
func IsDir(path string) bool func IsDir(path string) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -287,9 +292,8 @@ func main() {
} }
``` ```
### <span id="ListFileNames">ListFileNames</span> ### <span id="ListFileNames">ListFileNames</span>
<p>返回目录下所有文件名</p> <p>返回目录下所有文件名</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -297,7 +301,8 @@ func main() {
```go ```go
func ListFileNames(path string) ([]string, error) func ListFileNames(path string) ([]string, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -313,9 +318,8 @@ func main() {
} }
``` ```
### <span id="RemoveFile">RemoveFile</span> ### <span id="RemoveFile">RemoveFile</span>
<p>删除文件</p> <p>删除文件</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -323,7 +327,8 @@ func main() {
```go ```go
func RemoveFile(path string) error func RemoveFile(path string) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -341,8 +346,8 @@ func main() {
} }
``` ```
### <span id="ReadFileToString">ReadFileToString</span> ### <span id="ReadFileToString">ReadFileToString</span>
<p>读取文件内容并返回字符串</p> <p>读取文件内容并返回字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -350,7 +355,8 @@ func main() {
```go ```go
func ReadFileToString(path string) (string, error) func ReadFileToString(path string) (string, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -373,9 +379,8 @@ func main() {
} }
``` ```
### <span id="ReadFileByLine">ReadFileByLine</span> ### <span id="ReadFileByLine">ReadFileByLine</span>
<p>按行读取文件内容,返回字符串切片包含每一行</p> <p>按行读取文件内容,返回字符串切片包含每一行</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -383,7 +388,8 @@ func main() {
```go ```go
func ReadFileByLine(path string)([]string, error) func ReadFileByLine(path string)([]string, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -407,9 +413,8 @@ func main() {
} }
``` ```
### <span id="Zip">Zip</span> ### <span id="Zip">Zip</span>
<p>zip压缩文件, fpath参数可以是文件或目录</p> <p>zip压缩文件, fpath参数可以是文件或目录</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -417,7 +422,8 @@ func main() {
```go ```go
func Zip(fpath string, destPath string) error func Zip(fpath string, destPath string) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -435,10 +441,8 @@ func main() {
} }
``` ```
### <span id="UnZip">UnZip</span> ### <span id="UnZip">UnZip</span>
<p>zip解压缩文件并保存在目录中</p> <p>zip解压缩文件并保存在目录中</p>
<b>Signature:</b> <b>Signature:</b>
@@ -446,7 +450,8 @@ func main() {
```go ```go
func UnZip(zipFile string, destPath string) error func UnZip(zipFile string, destPath string) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -463,8 +468,3 @@ func main() {
} }
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Formatter # Formatter
formatter contains some functions for data formatting. formatter contains some functions for data formatting.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ formatter contains some functions for data formatting.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/formatter" "github.com/duke-git/lancet/v2/formatter"
@@ -19,15 +21,15 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [Comma](#Comma) - [Comma](#Comma)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="Comma">Comma</span> ### <span id="Comma">Comma</span>
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p> <p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -35,6 +37,7 @@ import (
```go ```go
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -46,7 +49,17 @@ import (
) )
func main() { func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345" result1 := formatter.Comma("123", "")
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67" result2 := formatter.Comma("12345", "$")
result3 := formatter.Comma(1234567, "¥")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 123
// $12,345
// ¥1,234,567
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Formatter # Formatter
formatter格式化器包含一些数据格式化处理方法。
formatter 格式化器包含一些数据格式化处理方法。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ formatter格式化器包含一些数据格式化处理方法。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/formatter" "github.com/duke-git/lancet/v2/formatter"
@@ -19,15 +21,15 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [Comma](#Comma) - [Comma](#Comma)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 文档 ## 文档
### <span id="Comma">Comma</span> ### <span id="Comma">Comma</span>
<p>用逗号每隔3位分割数字/字符串支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p> <p>用逗号每隔3位分割数字/字符串支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -35,7 +37,8 @@ import (
```go ```go
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -46,7 +49,17 @@ import (
) )
func main() { func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345" result1 := formatter.Comma("123", "")
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67" result2 := formatter.Comma("12345", "$")
result3 := formatter.Comma(1234567, "¥")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 123
// $12,345
// ¥1,234,567
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Function # Function
Package function can control the flow of function execution and support part of functional programming. Package function can control the flow of function execution and support part of functional programming.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -11,6 +12,7 @@ Package function can control the flow of function execution and support part of
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/function" "github.com/duke-git/lancet/v2/function"
@@ -20,12 +22,14 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [After](#After) - [After](#After)
- [Before](#Before) - [Before](#Before)
- [CurryFn](#CurryFn) - [CurryFn](#CurryFn)
- [Compose](#Compose) - [Compose](#Compose)
- [Debounced](#Debounced) - [Debounced](#Debounced)
- [Delay](#Delay) - [Delay](#Delay)
- [Schedule](#Schedule)
- [Pipeline](#Pipeline) - [Pipeline](#Pipeline)
- [Watcher](#Watcher) - [Watcher](#Watcher)
@@ -33,9 +37,8 @@ import (
## Documentation ## Documentation
### <span id="After">After</span> ### <span id="After">After</span>
<p>Creates a function that invokes given func once it's called n or more times.</p> <p>Creates a function that invokes given func once it's called n or more times.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -43,6 +46,7 @@ import (
```go ```go
func After(n int, fn any) func(args ...any) []reflect.Value func After(n int, fn any) func(args ...any) []reflect.Value
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -54,33 +58,18 @@ import (
) )
func main() { func main() {
arr := []string{"a", "b"} fn := function.After(2, func() {
f := function.After(len(arr), func(i int) int { fmt.Println("hello")
fmt.Println("last print")
return i
}) })
type cb func(args ...any) []reflect.Value fn()
print := func(i int, s string, fn cb) { fn()
fmt.Printf("arr[%d] is %s \n", i, s)
fn(i)
}
fmt.Println("arr is", arr) // Output:
for i := 0; i < len(arr); i++ { // hello
print(i, arr[i], f)
}
//output:
// arr is [a b]
// arr[0] is a
// arr[1] is b
// last print
} }
``` ```
### <span id="Before">Before</span> ### <span id="Before">Before</span>
<p>creates a function that invokes func once it's called less than n times.</p> <p>creates a function that invokes func once it's called less than n times.</p>
@@ -90,6 +79,7 @@ func main() {
```go ```go
func Before(n int, fn any) func(args ...any) []reflect.Value func Before(n int, fn any) func(args ...any) []reflect.Value
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -102,29 +92,21 @@ import (
) )
func main() { func main() {
arr := []string{"a", "b", "c", "d", "e"} fn := function.Before(2, func() {
f := function.Before(3, func(i int) int { fmt.Println("hello")
return i
}) })
var res []int64 fn()
type cb func(args ...any) []reflect.Value fn()
appendStr := func(i int, s string, fn cb) { fn()
v := fn(i) fn()
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ { // Output:
appendStr(i, arr[i], f) // hello
} // hello
expected := []int64{0, 1, 2, 2, 2}
fmt.Println(res) // 0, 1, 2, 2, 2
} }
``` ```
### <span id="CurryFn">CurryFn</span> ### <span id="CurryFn">CurryFn</span>
<p>Make curry function.</p> <p>Make curry function.</p>
@@ -135,6 +117,7 @@ func main() {
type CurryFn[T any] func(...T) T type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T func (cf CurryFn[T]) New(val T) func(...T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -150,19 +133,20 @@ func main() {
return a + b return a + b
} }
var addCurry CurryFn[int] = func(values ...int) int { var addCurry function.CurryFn[int] = func(values ...int) int {
return add(values[0], values[1]) return add(values[0], values[1])
} }
add1 := addCurry.New(1) add1 := addCurry.New(1)
result := add1(2) result := add1(2)
fmt.Println(result) //3 fmt.Println(result)
// Output:
// 3
} }
``` ```
### <span id="Compose">Compose</span> ### <span id="Compose">Compose</span>
<p>Compose the function list from right to left, then return the composed function.</p> <p>Compose the function list from right to left, then return the composed function.</p>
@@ -172,6 +156,7 @@ func main() {
```go ```go
func Compose[T any](fnList ...func(...T) T) func(...T) T func Compose[T any](fnList ...func(...T) T) func(...T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -189,16 +174,17 @@ func main() {
toLower := func(strs ...string) string { toLower := func(strs ...string) string {
return strings.ToLower(strs[0]) return strings.ToLower(strs[0])
} }
transform := Compose(toUpper, toLower) transform := function.Compose(toUpper, toLower)
result := transform("aBCde") result := transform("aBCde")
fmt.Println(result) //ABCDE fmt.Println(result)
// Output:
// ABCDE
} }
``` ```
### <span id="Debounced">Debounced</span> ### <span id="Debounced">Debounced</span>
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p> <p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
@@ -208,6 +194,7 @@ func main() {
```go ```go
func Debounced(fn func(), duration time.Duration) func() func Debounced(fn func(), duration time.Duration) func()
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -220,27 +207,34 @@ import (
func main() { func main() {
count := 0 count := 0
add := func() { add := func() {
count++ count++
} }
debouncedAdd := function.Debounced(add, 50*time.Microsecond) debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd() debouncedAdd()
function.debouncedAdd() debouncedAdd()
function.debouncedAdd() debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd() fmt.Println(count)
debouncedAdd()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
fmt.Println(count)
// Output:
// 1
// 2
} }
``` ```
### <span id="Delay">Delay</span> ### <span id="Delay">Delay</span>
<p>Invoke function after delayed time.</p> <p>Invoke function after delayed time.</p>
@@ -250,6 +244,7 @@ func main() {
```go ```go
func Delay(delay time.Duration, fn any, args ...any) func Delay(delay time.Duration, fn any, args ...any)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -262,14 +257,16 @@ import (
func main() { func main() {
var print = func(s string) { var print = func(s string) {
fmt.Println(count) //delay 2 seconds fmt.Println(s)
} }
function.Delay(2*time.Second, print, "delay 2 seconds")
function.Delay(2*time.Second, print, "hello")
// Output:
// hello
} }
``` ```
### <span id="Schedule">Schedule</span> ### <span id="Schedule">Schedule</span>
<p>Invoke function every duration time, until close the returned bool chan.</p> <p>Invoke function every duration time, until close the returned bool chan.</p>
@@ -279,6 +276,7 @@ func main() {
```go ```go
func Schedule(d time.Duration, fn any, args ...any) chan bool func Schedule(d time.Duration, fn any, args ...any) chan bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -290,20 +288,24 @@ import (
) )
func main() { func main() {
var res []string count := 0
appendStr := func(s string) {
res = append(res, s) increase := func() {
count++
} }
stop := function.Schedule(1*time.Second, appendStr, "*") stop := function.Schedule(2*time.Second, increase)
time.Sleep(5 * time.Second)
time.Sleep(2 * time.Second)
close(stop) close(stop)
fmt.Println(res) //[* * * * *] fmt.Println(count)
// Output:
// 2
} }
``` ```
### <span id="Pipeline">Pipeline</span> ### <span id="Pipeline">Pipeline</span>
<p>Pipeline takes a list of functions and returns a function whose param will be passed into <p>Pipeline takes a list of functions and returns a function whose param will be passed into
@@ -314,6 +316,7 @@ the functions one by one.</p>
```go ```go
func Pipeline[T any](funcs ...func(T) T) func(T) T func Pipeline[T any](funcs ...func(T) T) func(T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -335,13 +338,17 @@ func main() {
return x * x return x * x
} }
fn := Pipeline(addOne, double, square) fn := function.Pipeline(addOne, double, square)
fmt.Println(fn(2)) //36 result := fn(2)
fmt.Println(result)
// Output:
// 36
} }
``` ```
### <span id="Watcher">Watcher</span> ### <span id="Watcher">Watcher</span>
<p>Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.</p> <p>Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.</p>
@@ -360,6 +367,7 @@ func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher func (w *Watcher) Reset() //reset the watcher
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -396,6 +404,3 @@ func longRunningTask() {
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Function # Function
function函数包控制函数执行流程包含部分函数式编程。
function 函数包控制函数执行流程,包含部分函数式编程。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -11,6 +12,7 @@ function函数包控制函数执行流程包含部分函数式编程。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/function" "github.com/duke-git/lancet/v2/function"
@@ -20,12 +22,14 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [After](#After) - [After](#After)
- [Before](#Before) - [Before](#Before)
- [CurryFn](#CurryFn) - [CurryFn](#CurryFn)
- [Compose](#Compose) - [Compose](#Compose)
- [Debounced](#Debounced) - [Debounced](#Debounced)
- [Delay](#Delay) - [Delay](#Delay)
- [Schedule](#Schedule)
- [Pipeline](#Pipeline) - [Pipeline](#Pipeline)
- [Watcher](#Watcher) - [Watcher](#Watcher)
@@ -33,9 +37,8 @@ import (
## 文档 ## 文档
### <span id="After">After</span> ### <span id="After">After</span>
<p>创建一个函数当他被调用n或更多次之后将马上触发fn</p> <p>创建一个函数当他被调用n或更多次之后将马上触发fn</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -43,7 +46,8 @@ import (
```go ```go
func After(n int, fn any) func(args ...any) []reflect.Value func After(n int, fn any) func(args ...any) []reflect.Value
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -54,33 +58,18 @@ import (
) )
func main() { func main() {
arr := []string{"a", "b"} fn := function.After(2, func() {
f := function.After(len(arr), func(i int) int { fmt.Println("hello")
fmt.Println("last print")
return i
}) })
type cb func(args ...any) []reflect.Value fn()
print := func(i int, s string, fn cb) { fn()
fmt.Printf("arr[%d] is %s \n", i, s)
fn(i)
}
fmt.Println("arr is", arr) // Output:
for i := 0; i < len(arr); i++ { // hello
print(i, arr[i], f)
}
//output:
// arr is [a b]
// arr[0] is a
// arr[1] is b
// last print
} }
``` ```
### <span id="Before">Before</span> ### <span id="Before">Before</span>
<p>创建一个函数调用次数不超过n次之后再调用这个函数将返回一次最后调用fn的结果</p> <p>创建一个函数调用次数不超过n次之后再调用这个函数将返回一次最后调用fn的结果</p>
@@ -90,7 +79,8 @@ func main() {
```go ```go
func Before(n int, fn any) func(args ...any) []reflect.Value func Before(n int, fn any) func(args ...any) []reflect.Value
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -102,28 +92,21 @@ import (
) )
func main() { func main() {
arr := []string{"a", "b", "c", "d", "e"} fn := function.Before(2, func() {
f := function.Before(3, func(i int) int { fmt.Println("hello")
return i
}) })
var res []int64 fn()
type cb func(args ...any) []reflect.Value fn()
appendStr := func(i int, s string, fn cb) { fn()
v := fn(i) fn()
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ { // Output:
appendStr(i, arr[i], f) // hello
} // hello
fmt.Println(res) // 0, 1, 2, 2, 2
} }
``` ```
### <span id="CurryFn">CurryFn</span> ### <span id="CurryFn">CurryFn</span>
<p>创建柯里化函数</p> <p>创建柯里化函数</p>
@@ -134,7 +117,8 @@ func main() {
type CurryFn[T any] func(...T) T type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T func (cf CurryFn[T]) New(val T) func(...T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -149,19 +133,20 @@ func main() {
return a + b return a + b
} }
var addCurry CurryFn[int] = func(values ...int) int { var addCurry function.CurryFn[int] = func(values ...int) int {
return add(values[0], values[1]) return add(values[0], values[1])
} }
add1 := addCurry.New(1) add1 := addCurry.New(1)
result := add1(2) result := add1(2)
fmt.Println(result) //3 fmt.Println(result)
// Output:
// 3
} }
``` ```
### <span id="Compose">Compose</span> ### <span id="Compose">Compose</span>
<p>从右至左组合函数列表fnList返回组合后的函数</p> <p>从右至左组合函数列表fnList返回组合后的函数</p>
@@ -171,7 +156,8 @@ func main() {
```go ```go
func Compose[T any](fnList ...func(...T) T) func(...T) T func Compose[T any](fnList ...func(...T) T) func(...T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -188,16 +174,17 @@ func main() {
toLower := func(strs ...string) string { toLower := func(strs ...string) string {
return strings.ToLower(strs[0]) return strings.ToLower(strs[0])
} }
transform := Compose(toUpper, toLower) transform := function.Compose(toUpper, toLower)
result := transform("aBCde") result := transform("aBCde")
fmt.Println(result) //ABCDE fmt.Println(result)
// Output:
// ABCDE
} }
``` ```
### <span id="Debounced">Debounced</span> ### <span id="Debounced">Debounced</span>
<p>创建一个debounced函数该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p> <p>创建一个debounced函数该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
@@ -207,7 +194,8 @@ func main() {
```go ```go
func Debounced(fn func(), duration time.Duration) func() func Debounced(fn func(), duration time.Duration) func()
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -219,27 +207,34 @@ import (
func main() { func main() {
count := 0 count := 0
add := func() { add := func() {
count++ count++
} }
debouncedAdd := function.Debounced(add, 50*time.Microsecond) debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd() debouncedAdd()
function.debouncedAdd() debouncedAdd()
function.debouncedAdd() debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd() fmt.Println(count)
debouncedAdd()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
fmt.Println(count)
// Output:
// 1
// 2
} }
``` ```
### <span id="Delay">Delay</span> ### <span id="Delay">Delay</span>
<p>延迟delay时间后调用函数</p> <p>延迟delay时间后调用函数</p>
@@ -249,7 +244,8 @@ func main() {
```go ```go
func Delay(delay time.Duration, fn any, args ...any) func Delay(delay time.Duration, fn any, args ...any)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -261,14 +257,16 @@ import (
func main() { func main() {
var print = func(s string) { var print = func(s string) {
fmt.Println(count) //test delay fmt.Println(s)
} }
function.Delay(2*time.Second, print, "test delay")
function.Delay(2*time.Second, print, "hello")
// Output:
// hello
} }
``` ```
### <span id="Schedule">Schedule</span> ### <span id="Schedule">Schedule</span>
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p> <p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
@@ -278,7 +276,8 @@ func main() {
```go ```go
func Schedule(d time.Duration, fn any, args ...any) chan bool func Schedule(d time.Duration, fn any, args ...any) chan bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -289,21 +288,24 @@ import (
) )
func main() { func main() {
var res []string count := 0
appendStr := func(s string) {
res = append(res, s) increase := func() {
count++
} }
stop := function.Schedule(1*time.Second, appendStr, "*") stop := function.Schedule(2*time.Second, increase)
time.Sleep(5 * time.Second)
time.Sleep(2 * time.Second)
close(stop) close(stop)
fmt.Println(res) //[* * * * *] fmt.Println(count)
// Output:
// 2
} }
``` ```
### <span id="Pipeline">Pipeline</span> ### <span id="Pipeline">Pipeline</span>
<p>执行函数pipeline.</p> <p>执行函数pipeline.</p>
@@ -313,7 +315,8 @@ func main() {
```go ```go
func Pipeline[T any](funcs ...func(T) T) func(T) T func Pipeline[T any](funcs ...func(T) T) func(T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -334,14 +337,17 @@ func main() {
return x * x return x * x
} }
f := Pipeline(addOne, double, square) fn := function.Pipeline(addOne, double, square)
fmt.Println(fn(2)) //36 result := fn(2)
fmt.Println(result)
// Output:
// 36
} }
``` ```
### <span id="Watcher">Watcher</span> ### <span id="Watcher">Watcher</span>
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p> <p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
@@ -360,7 +366,8 @@ func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher func (w *Watcher) Reset() //reset the watcher
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -397,6 +404,3 @@ func longRunningTask() {
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Maputil # Maputil
Package maputil includes some functions to manipulate map. Package maputil includes some functions to manipulate map.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ Package maputil includes some functions to manipulate map.
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go) - [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Example: ## Example:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/maputil" "github.com/duke-git/lancet/v2/maputil"
@@ -20,22 +21,34 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [ForEach](#ForEach) - [ForEach](#ForEach)
- [Filter](#Filter) - [Filter](#Filter)
- [FilterByKeys](#FilterByKeys)
- [FilterByValues](#FilterByValues)
- [OmitBy](#OmitBy)
- [OmitByKeys](#OmitByKeys)
- [OmitByValues](#OmitByValues)
- [Intersect](#Intersect) - [Intersect](#Intersect)
- [Keys](#Keys) - [Keys](#Keys)
- [Values](#Values)
- [KeysBy](#KeysBy)
- [ValuesBy](#ValuesBy)
- [MapKeys](#MapKeys)
- [MapValues](#MapValues)
- [Entries](#Entries)
- [FromEntries](#FromEntries)
- [Transform](#Transform)
- [Merge](#Merge) - [Merge](#Merge)
- [Minus](#Minus) - [Minus](#Minus)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint) - [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="ForEach">ForEach</span> ### <span id="ForEach">ForEach</span>
<p>Executes iteratee funcation for every key and value pair in map.</p> <p>Executes iteratee funcation for every key and value pair in map.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -43,6 +56,7 @@ import (
```go ```go
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -66,14 +80,16 @@ func main() {
maputil.ForEach(m, func(_ string, value int) { maputil.ForEach(m, func(_ string, value int) {
sum += value sum += value
}) })
fmt.Println(sum) // 10
fmt.Println(sum)
// Output:
// 10
} }
``` ```
### <span id="Filter">Filter</span> ### <span id="Filter">Filter</span>
<p>Iterates over map, return a new map contains all key and value pairs pass the predicate function.</p> <p>Iterates over map, return a new map contains all key and value pairs pass the predicate function.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -81,6 +97,7 @@ func main() {
```go ```go
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -106,15 +123,217 @@ func main() {
maputil.Filter(m, func(_ string, value int) { maputil.Filter(m, func(_ string, value int) {
sum += value sum += value
}) })
res := maputil.Filter(m, isEven)
fmt.Println(res) // map[string]int{"b": 2, "d": 4,} result := maputil.Filter(m, isEven)
fmt.Println(result)
// Output:
// map[b:2 d:4]
} }
``` ```
### <span id="FilterByKeys">FilterByKeys</span>
<p>Iterates over map, return a new map whose keys are all given keys.</p>
<b>Signature:</b>
```go
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.FilterByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[a:1 b:2]
}
```
### <span id="FilterByValues">FilterByValues</span>
<p>Iterates over map, return a new map whose values are all given values.</p>
<b>Signature:</b>
```go
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.FilterByValues(m, []int{3, 4})
fmt.Println(result)
// Output:
// map[c:3 d:4]
}
```
### <span id="OmitBy">OmitBy</span>
<p>OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.</p>
<b>Signature:</b>
```go
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
result := maputil.OmitBy(m, isEven)
fmt.Println(result)
// Output:
// map[a:1 c:3 e:5]
}
```
### <span id="OmitByKeys">OmitByKeys</span>
<p>The opposite of FilterByKeys, extracts all the map elements which keys are not omitted.</p>
<b>Signature:</b>
```go
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.OmitByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[c:3 d:4 e:5]
}
```
### <span id="OmitByValues">OmitByValues</span>
<p>The opposite of FilterByValues. remov all elements whose value are in the give slice.</p>
<b>Signature:</b>
```go
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.OmitByValues(m, []int{4, 5})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
```
### <span id="Intersect">Intersect</span> ### <span id="Intersect">Intersect</span>
<p>Iterates over maps, return a new map of key and value pairs in all given maps.</p> <p>Iterates over maps, return a new map of key and value pairs in all given maps.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -122,6 +341,7 @@ func main() {
```go ```go
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -152,18 +372,23 @@ func main() {
"e": 9, "e": 9,
} }
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3} result1 := maputil.Intersect(m1)
result2 := maputil.Intersect(m1, m2)
result3 := maputil.Intersect(m1, m2, m3)
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2} fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1} // Output:
// map[a:1 b:2 c:3]
// map[a:1 b:2]
// map[a:1]
} }
``` ```
### <span id="Keys">Keys</span> ### <span id="Keys">Keys</span>
<p>Returns a slice of the map's keys.</p> <p>Returns a slice of the map's keys.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -171,6 +396,7 @@ func main() {
```go ```go
func Keys[K comparable, V any](m map[K]V) []K func Keys[K comparable, V any](m map[K]V) []K
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -178,6 +404,7 @@ package main
import ( import (
"fmt" "fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil" "github.com/duke-git/lancet/v2/maputil"
) )
@@ -192,14 +419,16 @@ func main() {
keys := maputil.Keys(m) keys := maputil.Keys(m)
sort.Ints(keys) sort.Ints(keys)
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
fmt.Println(keys)
// Output:
// [1 2 3 4 5]
} }
``` ```
### <span id="Merge">Merge</span> ### <span id="Merge">Merge</span>
<p>Merge maps, next key will overwrite previous key.</p> <p>Merge maps, next key will overwrite previous key.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -207,6 +436,7 @@ func main() {
```go ```go
func Merge[K comparable, V any](maps ...map[K]V) map[K]V func Merge[K comparable, V any](maps ...map[K]V) map[K]V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -226,14 +456,18 @@ func main() {
1: "1", 1: "1",
3: "2", 3: "2",
} }
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
result := maputil.Merge(m1, m2)
fmt.Println(result)
// Output:
// map[1:c 2:b 3:d]
} }
``` ```
### <span id="Minus">Minus</span> ### <span id="Minus">Minus</span>
<p>Creates an map of whose key in mapA but not in mapB.</p> <p>Creates an map of whose key in mapA but not in mapB.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -241,6 +475,7 @@ func main() {
```go ```go
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -264,13 +499,17 @@ func main() {
"d": 33, "d": 33,
} }
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3} result := maputil.Minus(m1, m2)
fmt.Println(result)
// Output:
// map[c:3]
} }
``` ```
### <span id="Values">Values</span> ### <span id="Values">Values</span>
<p>Returns a slice of the map's values.</p> <p>Returns a slice of the map's values.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -278,6 +517,7 @@ func main() {
```go ```go
func Values[K comparable, V any](m map[K]V) []V func Values[K comparable, V any](m map[K]V) []V
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -285,6 +525,7 @@ package main
import ( import (
"fmt" "fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil" "github.com/duke-git/lancet/v2/maputil"
) )
@@ -300,18 +541,243 @@ func main() {
values := maputil.Values(m) values := maputil.Values(m)
sort.Strings(values) sort.Strings(values)
fmt.Println(values) // []string{"a", "a", "b", "c", "d"} fmt.Println(values)
// Output:
// [a a b c d]
} }
``` ```
### <span id="IsDisjoint">IsDisjoint</span> ### <span id="KeysBy">KeysBy</span>
<p>Checks two maps are disjoint if they have no keys in common</p>
<p>Creates a slice whose element is the result of function mapper invoked by every map's key.</p>
<b>Signature:</b> <b>Signature:</b>
```go ```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T
``` ```
<b>Example:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
}
keys := maputil.KeysBy(m, func(n int) int {
return n + 1
})
sort.Ints(keys)
fmt.Println(keys)
// Output:
// [2 3 4]
}
```
### <span id="ValuesBy">ValuesBy</span>
<p>Creates a slice whose element is the result of function mapper invoked by every map's value.</p>
<b>Signature:</b>
```go
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
values := maputil.ValuesBy(m, func(v string) string {
switch v {
case "a":
return "a-1"
case "b":
return "b-2"
case "c":
return "c-3"
default:
return ""
}
})
sort.Strings(values)
fmt.Println(values)
// Output:
// [a-1 b-2 c-3]
}
```
### <span id="MapKeys">MapKeys</span>
<p>Transforms a map to other type map by manipulating it's keys.</p>
<b>Signature:</b>
```go
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := maputil.MapKeys(m, func(k int, _ string) string {
return strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c]
}
```
### <span id="MapValues">MapValues</span>
<p>Transforms a map to other type map by manipulating it's values.</p>
<b>Signature:</b>
```go
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := maputil.MapValues(m, func(k int, v string) string {
return v + strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a1 2:b2 3:c3]
}
```
### <span id="Entry">Entry</span>
<p>Transforms a map into array of key/value pairs.</p>
<b>Signature:</b>
```go
type Entry[K comparable, V any] struct {
Key K
Value V
}
func Entries[K comparable, V any](m map[K]V) []Entry[K, V]
```
<b>Example:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := maputil.Entries(m)
sort.Slice(result, func(i, j int) bool {
return result[i].Value < result[j].Value
})
fmt.Println(result)
// Output:
// [{a 1} {b 2} {c 3}]
}
```
### <span id="FromEntries">FromEntries</span>
<p>Creates a map based on a slice of key/value pairs.</p>
<b>Signature:</b>
```go
type Entry[K comparable, V any] struct {
Key K
Value V
}
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V
```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -323,30 +789,102 @@ import (
) )
func main() { func main() {
m1 := map[int]string{ result := maputil.FromEntries([]Entry[string, int]{
1: "a", {Key: "a", Value: 1},
2: "a", {Key: "b", Value: 2},
3: "b", {Key: "c", Value: 3},
4: "c", })
5: "d",
}
m2 := map[int]string{ fmt.Println(result)
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m3 := map[int]string{ // Output:
6: "a", // map[a:1 b:2 c:3]
} }
```
ok := maputil.IsDisjoint(m2, m1)
fmt.Println(ok) // false ### <span id="Transform">Transform</span>
ok = maputil.IsDisjoint(m2, m3) <p>Transform a map to another type map.</p>
fmt.Println(ok) // true
<b>Signature:</b>
```go
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2
```
<b>Example:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Transform(m, func(k string, v int) (string, string) {
return k, strconv.Itoa(v)
})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>Checks two maps are disjoint if they have no keys in common</p>
<b>Signature:</b>
```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"d": 22,
}
m3 := map[string]int{
"a": 22,
}
result1 := maputil.IsDisjoint(m1, m2)
result2 := maputil.IsDisjoint(m1, m3)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Maputil # Maputil
maputil包包括一些操作map的函数。
maputil 包包括一些操作 map 的函数。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ maputil包包括一些操作map的函数。
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go) - [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/maputil" "github.com/duke-git/lancet/v2/maputil"
@@ -20,22 +21,34 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录: ## 目录:
- [ForEach](#ForEach) - [ForEach](#ForEach)
- [Filter](#Filter) - [Filter](#Filter)
- [FilterByKeys](#FilterByKeys)
- [FilterByValues](#FilterByValues)
- [OmitBy](#OmitBy)
- [OmitByKeys](#OmitByKeys)
- [OmitByValues](#OmitByValues)
- [Intersect](#Intersect) - [Intersect](#Intersect)
- [Keys](#Keys) - [Keys](#Keys)
- [Values](#Values)
- [KeysBy](#KeysBy)
- [ValuesBy](#ValuesBy)
- [MapKeys](#MapKeys)
- [MapValues](#MapValues)
- [Entries](#Entries)
- [FromEntries](#FromEntries)
- [Transform](#Transform)
- [Merge](#Merge) - [Merge](#Merge)
- [Minus](#Minus) - [Minus](#Minus)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint) - [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## API文档: ## API 文档:
### <span id="ForEach">ForEach</span> ### <span id="ForEach">ForEach</span>
<p>对map中的每对key和value执行iteratee函数</p> <p>对map中的每对key和value执行iteratee函数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -43,7 +56,8 @@ import (
```go ```go
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -66,22 +80,25 @@ func main() {
maputil.ForEach(m, func(_ string, value int) { maputil.ForEach(m, func(_ string, value int) {
sum += value sum += value
}) })
fmt.Println(sum) // 10
fmt.Println(sum)
// Output:
// 10
} }
``` ```
### <span id="Filter">Filter</span> ### <span id="Filter">Filter</span>
<p>迭代map中的每对key和value, 返回符合predicate函数的key, value</p>
<p>迭代map中的每对key和value, 返回符合predicate函数的key, value。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -106,15 +123,215 @@ func main() {
maputil.Filter(m, func(_ string, value int) { maputil.Filter(m, func(_ string, value int) {
sum += value sum += value
}) })
res := maputil.Filter(m, isEven)
fmt.Println(res) // map[string]int{"b": 2, "d": 4,} result := Filter(m, isEven)
fmt.Println(result)
// Output:
// map[b:2 d:4]
}
```
### <span id="FilterByKeys">FilterByKeys</span>
<p>迭代map, 返回一个新map其key都是给定的key值。</p>
<b>函数签名:</b>
```go
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.FilterByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[a:1 b:2]
} }
``` ```
### <span id="FilterByValues">FilterByValues</span>
<p>迭代map, 返回一个新map其value都是给定的value值。</p>
<b>函数签名:</b>
```go
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.FilterByValues(m, []int{3, 4})
fmt.Println(result)
// Output:
// map[c:3 d:4]
}
```
### <span id="OmitBy">OmitBy</span>
<p>Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。</p>
<b>函数签名:</b>
```go
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
result := maputil.OmitBy(m, isEven)
fmt.Println(result)
// Output:
// map[a:1 c:3 e:5]
}
```
### <span id="OmitByKeys">OmitByKeys</span>
<p>FilterByKeys的反向操作, 迭代map, 返回一个新map其key不包括给定的key值。</p>
<b>函数签名:</b>
```go
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.OmitByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[c:3 d:4 e:5]
}
```
### <span id="OmitByValues">OmitByValues</span>
<p>FilterByValues的反向操作, 迭代map, 返回一个新map其value不包括给定的value值。</p>
<b>函数签名:</b>
```go
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := maputil.OmitByValues(m, []int{4, 5})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
```
### <span id="Intersect">Intersect</span> ### <span id="Intersect">Intersect</span>
<p>多个map的交集操作</p> <p>多个map的交集操作</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -122,7 +339,8 @@ func main() {
```go ```go
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -152,18 +370,23 @@ func main() {
"e": 9, "e": 9,
} }
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3} result1 := maputil.Intersect(m1)
result2 := maputil.Intersect(m1, m2)
result3 := maputil.Intersect(m1, m2, m3)
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2} fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1} // Output:
// map[a:1 b:2 c:3]
// map[a:1 b:2]
// map[a:1]
} }
``` ```
### <span id="Keys">Keys</span> ### <span id="Keys">Keys</span>
<p>返回map中所有key的切片</p> <p>返回map中所有key的切片</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -171,7 +394,8 @@ func main() {
```go ```go
func Keys[K comparable, V any](m map[K]V) []K func Keys[K comparable, V any](m map[K]V) []K
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -192,14 +416,16 @@ func main() {
keys := maputil.Keys(m) keys := maputil.Keys(m)
sort.Ints(keys) sort.Ints(keys)
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
fmt.Println(keys)
// Output:
// [1 2 3 4 5]
} }
``` ```
### <span id="Merge">Merge</span> ### <span id="Merge">Merge</span>
<p>合并多个maps, 相同的key会被后来的key覆盖</p> <p>合并多个maps, 相同的key会被后来的key覆盖</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -207,7 +433,8 @@ func main() {
```go ```go
func Merge[K comparable, V any](maps ...map[K]V) map[K]V func Merge[K comparable, V any](maps ...map[K]V) map[K]V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -226,13 +453,18 @@ func main() {
1: "1", 1: "1",
3: "2", 3: "2",
} }
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
result := maputil.Merge(m1, m2)
fmt.Println(result)
// Output:
// map[1:c 2:b 3:d]
} }
``` ```
### <span id="Minus">Minus</span> ### <span id="Minus">Minus</span>
<p>返回一个map其中的key存在于mapA不存在于mapB.</p> <p>返回一个map其中的key存在于mapA不存在于mapB.</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -240,7 +472,8 @@ func main() {
```go ```go
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -263,13 +496,17 @@ func main() {
"d": 33, "d": 33,
} }
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3} result := maputil.Minus(m1, m2)
fmt.Println(result)
// Output:
// map[c:3]
} }
``` ```
### <span id="Values">Values</span> ### <span id="Values">Values</span>
<p>返回map中所有value的切片</p> <p>返回map中所有value的切片</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -277,7 +514,8 @@ func main() {
```go ```go
func Values[K comparable, V any](m map[K]V) []V func Values[K comparable, V any](m map[K]V) []V
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -299,20 +537,242 @@ func main() {
values := maputil.Values(m) values := maputil.Values(m)
sort.Strings(values) sort.Strings(values)
fmt.Println(values) // []string{"a", "a", "b", "c", "d"} // Output:
// [a a b c d]
} }
``` ```
### <span id="KeysBy">KeysBy</span>
### <span id="IsDisjoint">IsDisjoint</span> <p>创建一个切片其元素是每个map的key调用mapper函数的结果。</p>
<p>验证两个map是否具有不同的key</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T
``` ```
<b>例子:</b>
<b>示例:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
}
keys := maputil.KeysBy(m, func(n int) int {
return n + 1
})
sort.Ints(keys)
fmt.Println(keys)
// Output:
// [2 3 4]
}
```
### <span id="ValuesBy">ValuesBy</span>
<p>创建一个切片其元素是每个map的value调用mapper函数的结果。</p>
<b>函数签名:</b>
```go
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
values := maputil.ValuesBy(m, func(v string) string {
switch v {
case "a":
return "a-1"
case "b":
return "b-2"
case "c":
return "c-3"
default:
return ""
}
})
sort.Strings(values)
fmt.Println(values)
// Output:
// [a-1 b-2 c-3]
}
```
### <span id="MapKeys">MapKeys</span>
<p>操作map的每个key然后转为新的map。</p>
<b>函数签名:</b>
```go
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V
```
<b>示例:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := maputil.MapKeys(m, func(k int, _ string) string {
return strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c]
}
```
### <span id="MapValues">MapValues</span>
<p>操作map的每个value然后转为新的map。</p>
<b>函数签名:</b>
```go
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := maputil.MapValues(m, func(k int, v string) string {
return v + strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a1 2:b2 3:c3]
}
```
### <span id="Entry">Entry</span>
<p>将map转换为键/值对切片。</p>
<b>函数签名:</b>
```go
type Entry[K comparable, V any] struct {
Key K
Value V
}
func Entries[K comparable, V any](m map[K]V) []Entry[K, V]
```
<b>示例:</b>
```go
package main
import (
"fmt"
"sort"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := maputil.Entries(m)
sort.Slice(result, func(i, j int) bool {
return result[i].Value < result[j].Value
})
fmt.Println(result)
// Output:
// [{a 1} {b 2} {c 3}]
}
```
### <span id="FromEntries">FromEntries</span>
<p>基于键/值对的切片创建map。</p>
<b>函数签名:</b>
```go
type Entry[K comparable, V any] struct {
Key K
Value V
}
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V
```
<b>示例:</b>
```go ```go
package main package main
@@ -323,30 +783,101 @@ import (
) )
func main() { func main() {
m1 := map[int]string{ result := maputil.FromEntries([]Entry[string, int]{
1: "a", {Key: "a", Value: 1},
2: "a", {Key: "b", Value: 2},
3: "b", {Key: "c", Value: 3},
4: "c", })
5: "d",
}
m2 := map[int]string{ fmt.Println(result)
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
m3 := map[int]string{ // Output:
6: "a", // map[a:1 b:2 c:3]
} }
```
ok := maputil.IsDisjoint(m2, m1)
fmt.Println(ok) // false ### <span id="Transform">Transform</span>
ok = maputil.IsDisjoint(m2, m3) <p>将map转换为其他类型的map。</p>
fmt.Println(ok) // true
<b>函数签名:</b>
```go
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2
```
<b>示例:</b>
```go
package main
import (
"fmt"
"strconv"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Transform(m, func(k string, v int) (string, string) {
return k, strconv.Itoa(v)
})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>验证两个map是否具有不同的key</p>
<b>函数签名:</b>
```go
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"d": 22,
}
m3 := map[string]int{
"a": 22,
}
result1 := maputil.IsDisjoint(m1, m2)
result2 := maputil.IsDisjoint(m1, m3)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Mathutil # Mathutil
Package mathutil implements some functions for math calculation. Package mathutil implements some functions for math calculation.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ Package mathutil implements some functions for math calculation.
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go) - [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Example: ## Example:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/mathutil" "github.com/duke-git/lancet/v2/mathutil"
@@ -20,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [Average](#Average) - [Average](#Average)
- [Exponent](#Exponent) - [Exponent](#Exponent)
- [Fibonacci](#Fibonacci) - [Fibonacci](#Fibonacci)
@@ -37,9 +39,8 @@ import (
## Documentation ## Documentation
### <span id="Average">Average</span> ### <span id="Average">Average</span>
<p>Return average value of numbers. Maybe call RoundToFloat to round result.</p> <p>Return average value of numbers. Maybe call RoundToFloat to round result.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -47,6 +48,7 @@ import (
```go ```go
func Average[T constraints.Integer | constraints.Float](numbers ...T) T func Average[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -58,16 +60,22 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Average(0, 0)) //0 result1 := mathutil.Average(1, 2)
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998 avg := mathutil.Average(1.2, 1.4)
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3 result2 := mathutil.RoundToFloat(avg, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.3
} }
``` ```
### <span id="Exponent">Exponent</span> ### <span id="Exponent">Exponent</span>
<p>Calculate x to the nth power.</p> <p>Calculate x to the nth power.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -75,6 +83,7 @@ func main() {
```go ```go
func Exponent(x, n int64) int64 func Exponent(x, n int64) int64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -86,15 +95,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Exponent(10, 0)) //1 result1 := mathutil.Exponent(10, 0)
fmt.Println(mathutil.Exponent(10, 1)) //10 result2 := mathutil.Exponent(10, 1)
fmt.Println(mathutil.Exponent(10, 2)) //100 result3 := mathutil.Exponent(10, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 10
// 100
} }
``` ```
### <span id="Fibonacci">Fibonacci</span> ### <span id="Fibonacci">Fibonacci</span>
<p>Calculate the nth number of fibonacci sequence.</p> <p>Calculate the nth number of fibonacci sequence.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -102,6 +119,7 @@ func main() {
```go ```go
func Fibonacci(first, second, n int) int func Fibonacci(first, second, n int) int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -113,17 +131,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1 result1 := mathutil.Fibonacci(1, 1, 1)
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1 result2 := mathutil.Fibonacci(1, 1, 2)
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2 result3 := mathutil.Fibonacci(1, 1, 5)
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 1
// 5
} }
``` ```
### <span id="Factorial">Factorial</span> ### <span id="Factorial">Factorial</span>
<p>Calculate the factorial of x.</p> <p>Calculate the factorial of x.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -131,6 +155,7 @@ func main() {
```go ```go
func Factorial(x uint) uint func Factorial(x uint) uint
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -142,16 +167,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Factorial(0)) //1 result1 := mathutil.Factorial(1)
fmt.Println(mathutil.Factorial(1)) //1 result2 := mathutil.Factorial(2)
fmt.Println(mathutil.Factorial(2)) //2 result3 := mathutil.Factorial(3)
fmt.Println(mathutil.Factorial(3)) //6
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 6
} }
``` ```
### <span id="Max">Max</span> ### <span id="Max">Max</span>
<p>Return max value of numbers.</p> <p>Return max value of numbers.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -159,6 +191,7 @@ func main() {
```go ```go
func Max[T constraints.Integer | constraints.Float](numbers ...T) T func Max[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -170,16 +203,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Max(0, 0)) //0 result1 := mathutil.Max(1, 2, 3)
fmt.Println(mathutil.Max(1, 2, 3)) //3 result2 := mathutil.Max(1.2, 1.4, 1.1, 1.4)
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 3
// 1.4
} }
``` ```
### <span id="MaxBy">MaxBy</span> ### <span id="MaxBy">MaxBy</span>
<p>Return the maximum value of a slice using the given comparator function.</p> <p>Return the maximum value of a slice using the given comparator function.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -187,6 +224,7 @@ func main() {
```go ```go
func MaxBy[T any](slice []T, comparator func(T, T) bool) T func MaxBy[T any](slice []T, comparator func(T, T) bool) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -198,26 +236,31 @@ import (
) )
func main() { func main() {
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool { result1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res1) //abc
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool { result2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res2) //abd
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool { result3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res3) //“”
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abc
// abd
//
} }
``` ```
### <span id="Min">Min</span> ### <span id="Min">Min</span>
<p>Return the minimum value of numbers.</p> <p>Return the minimum value of numbers.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -225,6 +268,7 @@ func main() {
```go ```go
func Min[T constraints.Integer | constraints.Float](numbers ...T) T func Min[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -236,15 +280,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Min(0, 0)) //0 result1 := mathutil.Min(1, 2, 3)
fmt.Println(mathutil.Min(1, 2, 3)) //1 result2 := mathutil.Min(1.2, 1.4, 1.1, 1.4)
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.1
} }
``` ```
### <span id="MinBy">MinBy</span> ### <span id="MinBy">MinBy</span>
<p>Return the minimum value of a slice using the given comparator function.</p> <p>Return the minimum value of a slice using the given comparator function.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -252,6 +301,7 @@ func main() {
```go ```go
func MinBy[T any](slice []T, comparator func(T, T) bool) T func MinBy[T any](slice []T, comparator func(T, T) bool) T
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -263,27 +313,31 @@ import (
) )
func main() { func main() {
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool { result1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res1) //a
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool { result2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res2) //ab
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool { result3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res3) //“”
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// a
// ab
//
} }
``` ```
### <span id="Percent">Percent</span> ### <span id="Percent">Percent</span>
<p>calculate the percentage of val to total, retain n decimal places.</p> <p>calculate the percentage of val to total, retain n decimal places.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -291,6 +345,7 @@ func main() {
```go ```go
func Percent(val, total float64, n int) float64 func Percent(val, total float64, n int) float64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -302,14 +357,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5 result1 := mathutil.Percent(1, 2, 2)
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33 result2 := mathutil.Percent(0.1, 0.3, 2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0.5
// 0.33
} }
``` ```
### <span id="RoundToFloat">RoundToFloat</span> ### <span id="RoundToFloat">RoundToFloat</span>
<p>Round float up to n decimal places.</p> <p>Round float up to n decimal places.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -317,6 +378,7 @@ func main() {
```go ```go
func RoundToFloat(x float64, n int) float64 func RoundToFloat(x float64, n int) float64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -328,18 +390,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.RoundToFloat(0, 0)) //0 result1 := mathutil.RoundToFloat(0.124, 2)
fmt.Println(mathutil.RoundToFloat(0, 1)) //0 result2 := mathutil.RoundToFloat(0.125, 2)
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12 result3 := mathutil.RoundToFloat(0.125, 3)
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
} }
``` ```
### <span id="RoundToString">RoundToString</span> ### <span id="RoundToString">RoundToString</span>
<p>Round float up to n decimal places. will return string.</p> <p>Round float up to n decimal places. will return string.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -347,6 +414,7 @@ func main() {
```go ```go
func RoundToString(x float64, n int) string func RoundToString(x float64, n int) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -358,17 +426,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.RoundToString(0, 0)) //"0" result1 := mathutil.RoundToString(0.124, 2)
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0: result2 := mathutil.RoundToString(0.125, 2)
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12" result3 := mathutil.RoundToString(0.125, 3)
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125" fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
} }
``` ```
### <span id="TruncRound">TruncRound</span> ### <span id="TruncRound">TruncRound</span>
<p>Round float off n decimal places.</p> <p>Round float off n decimal places.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -376,6 +450,7 @@ func main() {
```go ```go
func TruncRound(x float64, n int) float64 func TruncRound(x float64, n int) float64
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -387,13 +462,17 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.TruncRound(0, 0)) //0 result1 := mathutil.TruncRound(0.124, 2)
fmt.Println(mathutil.TruncRound(0, 1)) //0 result2 := mathutil.TruncRound(0.125, 2)
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12 result3 := mathutil.TruncRound(0.125, 3)
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.12
// 0.125
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Mathutil # Mathutil
mathutil包实现了一些数学计算的函数.
mathutil 包实现了一些数学计算的函数.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ mathutil包实现了一些数学计算的函数.
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go) - [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/mathutil" "github.com/duke-git/lancet/v2/mathutil"
@@ -20,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [Average](#Average) - [Average](#Average)
- [Exponent](#Exponent) - [Exponent](#Exponent)
- [Fibonacci](#Fibonacci) - [Fibonacci](#Fibonacci)
@@ -37,8 +39,8 @@ import (
## Documentation ## Documentation
### <span id="Average">Average</span> ### <span id="Average">Average</span>
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p> <p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -46,7 +48,8 @@ import (
```go ```go
func Average[T constraints.Integer | constraints.Float](numbers ...T) T func Average[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -57,15 +60,22 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Average(0, 0)) //0 result1 := mathutil.Average(1, 2)
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998 avg := mathutil.Average(1.2, 1.4)
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3 result2 := mathutil.RoundToFloat(avg, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.3
} }
``` ```
### <span id="Exponent">Exponent</span> ### <span id="Exponent">Exponent</span>
<p>指数计算x的n次方</p> <p>指数计算x的n次方</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -73,7 +83,8 @@ func main() {
```go ```go
func Exponent(x, n int64) int64 func Exponent(x, n int64) int64
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -84,15 +95,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Exponent(10, 0)) //1 result1 := mathutil.Exponent(10, 0)
fmt.Println(mathutil.Exponent(10, 1)) //10 result2 := mathutil.Exponent(10, 1)
fmt.Println(mathutil.Exponent(10, 2)) //100 result3 := mathutil.Exponent(10, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 10
// 100
} }
``` ```
### <span id="Fibonacci">Fibonacci</span> ### <span id="Fibonacci">Fibonacci</span>
<p>计算斐波那契数列的第n个数</p> <p>计算斐波那契数列的第n个数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -100,7 +119,8 @@ func main() {
```go ```go
func Fibonacci(first, second, n int) int func Fibonacci(first, second, n int) int
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -111,17 +131,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1 result1 := mathutil.Fibonacci(1, 1, 1)
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1 result2 := mathutil.Fibonacci(1, 1, 2)
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2 result3 := mathutil.Fibonacci(1, 1, 5)
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 1
// 5
} }
``` ```
### <span id="Factorial">Factorial</span> ### <span id="Factorial">Factorial</span>
<p>计算阶乘</p> <p>计算阶乘</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -129,7 +155,8 @@ func main() {
```go ```go
func Factorial(x uint) uint func Factorial(x uint) uint
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -140,15 +167,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Factorial(0)) //1 result1 := mathutil.Factorial(1)
fmt.Println(mathutil.Factorial(1)) //1 result2 := mathutil.Factorial(2)
fmt.Println(mathutil.Factorial(2)) //2 result3 := mathutil.Factorial(3)
fmt.Println(mathutil.Factorial(3)) //6
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 6
} }
``` ```
### <span id="Max">Max</span> ### <span id="Max">Max</span>
<p>返回参数中的最大数</p> <p>返回参数中的最大数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -156,7 +191,8 @@ func main() {
```go ```go
func Max[T constraints.Integer | constraints.Float](numbers ...T) T func Max[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -167,15 +203,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Max(0, 0)) //0 result1 := mathutil.Max(1, 2, 3)
fmt.Println(mathutil.Max(1, 2, 3)) //3 result2 := mathutil.Max(1.2, 1.4, 1.1, 1.4)
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 3
// 1.4
} }
``` ```
### <span id="MaxBy">MaxBy</span> ### <span id="MaxBy">MaxBy</span>
<p>使用给定的比较器函数返回切片的最大值</p> <p>使用给定的比较器函数返回切片的最大值</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -183,7 +224,8 @@ func main() {
```go ```go
func MaxBy[T any](slice []T, comparator func(T, T) bool) T func MaxBy[T any](slice []T, comparator func(T, T) bool) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -194,27 +236,31 @@ import (
) )
func main() { func main() {
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool { result1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res1) //abc
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool { result2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res2) //abd
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool { result3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2) return len(v1) > len(v2)
}) })
fmt.Println(res3) //“”
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abc
// abd
//
} }
``` ```
### <span id="Min">Min</span> ### <span id="Min">Min</span>
<p>返回参数中的最小数</p> <p>返回参数中的最小数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -222,7 +268,8 @@ func main() {
```go ```go
func Min[T constraints.Integer | constraints.Float](numbers ...T) T func Min[T constraints.Integer | constraints.Float](numbers ...T) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -233,15 +280,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Min(0, 0)) //0 result1 := mathutil.Min(1, 2, 3)
fmt.Println(mathutil.Min(1, 2, 3)) //1 result2 := mathutil.Min(1.2, 1.4, 1.1, 1.4)
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.1
} }
``` ```
### <span id="MinBy">MinBy</span> ### <span id="MinBy">MinBy</span>
<p>使用给定的比较器函数返回切片的最小值</p> <p>使用给定的比较器函数返回切片的最小值</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -249,7 +301,8 @@ func main() {
```go ```go
func MinBy[T any](slice []T, comparator func(T, T) bool) T func MinBy[T any](slice []T, comparator func(T, T) bool) T
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -260,27 +313,31 @@ import (
) )
func main() { func main() {
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool { result1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res1) //a
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool { result2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res2) //ab
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool { result3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2) return len(v1) < len(v2)
}) })
fmt.Println(res3) //“”
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// a
// ab
//
} }
``` ```
### <span id="Percent">Percent</span> ### <span id="Percent">Percent</span>
<p>计算百分比保留n位小数</p> <p>计算百分比保留n位小数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -288,7 +345,8 @@ func main() {
```go ```go
func Percent(val, total float64, n int) float64 func Percent(val, total float64, n int) float64
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -299,14 +357,20 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5 result1 := mathutil.Percent(1, 2, 2)
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33 result2 := mathutil.Percent(0.1, 0.3, 2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0.5
// 0.33
} }
``` ```
### <span id="RoundToFloat">RoundToFloat</span> ### <span id="RoundToFloat">RoundToFloat</span>
<p>四舍五入保留n位小数</p> <p>四舍五入保留n位小数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -314,7 +378,8 @@ func main() {
```go ```go
func RoundToFloat(x float64, n int) float64 func RoundToFloat(x float64, n int) float64
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -325,18 +390,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.RoundToFloat(0, 0)) //0 result1 := mathutil.RoundToFloat(0.124, 2)
fmt.Println(mathutil.RoundToFloat(0, 1)) //0 result2 := mathutil.RoundToFloat(0.125, 2)
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12 result3 := mathutil.RoundToFloat(0.125, 3)
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
} }
``` ```
### <span id="RoundToString">RoundToString</span> ### <span id="RoundToString">RoundToString</span>
<p>四舍五入保留n位小数返回字符串</p> <p>四舍五入保留n位小数返回字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -344,7 +414,8 @@ func main() {
```go ```go
func RoundToString(x float64, n int) string func RoundToString(x float64, n int) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -355,17 +426,23 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.RoundToString(0, 0)) //"0" result1 := mathutil.RoundToString(0.124, 2)
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0: result2 := mathutil.RoundToString(0.125, 2)
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12" result3 := mathutil.RoundToString(0.125, 3)
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125" fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
} }
``` ```
### <span id="TruncRound">TruncRound</span> ### <span id="TruncRound">TruncRound</span>
<p>截短n位小数不进行四舍五入</p> <p>截短n位小数不进行四舍五入</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -373,7 +450,8 @@ func main() {
```go ```go
func TruncRound(x float64, n int) float64 func TruncRound(x float64, n int) float64
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -384,13 +462,17 @@ import (
) )
func main() { func main() {
fmt.Println(mathutil.TruncRound(0, 0)) //0 result1 := mathutil.TruncRound(0.124, 2)
fmt.Println(mathutil.TruncRound(0, 1)) //0 result2 := mathutil.TruncRound(0.125, 2)
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12 result3 := mathutil.TruncRound(0.125, 3)
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125 fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.12
// 0.125
} }
``` ```

View File

@@ -1,4 +1,5 @@
# Netutil # Netutil
Package netutil contains functions to get net information and send http request. Package netutil contains functions to get net information and send http request.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,13 +8,12 @@ Package netutil contains functions to get net information and send http request.
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go) - [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go) - [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/netutil" "github.com/duke-git/lancet/v2/netutil"
@@ -23,6 +23,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [ConvertMapToQueryString](#ConvertMapToQueryString) - [ConvertMapToQueryString](#ConvertMapToQueryString)
- [EncodeUrl](#EncodeUrl) - [EncodeUrl](#EncodeUrl)
- [GetInternalIp](#GetInternalIp) - [GetInternalIp](#GetInternalIp)
@@ -48,8 +49,8 @@ import (
## Documentation ## Documentation
### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span> ### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span>
<p>Convert map to url query string.</p> <p>Convert map to url query string.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -57,6 +58,7 @@ import (
```go ```go
func ConvertMapToQueryString(param map[string]any) string func ConvertMapToQueryString(param map[string]any) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -75,13 +77,13 @@ func main() {
} }
qs := netutil.ConvertMapToQueryString(m) qs := netutil.ConvertMapToQueryString(m)
fmt.Println(qs) //a=1&b=2&c=3 // Output:
// a=1&b=2&c=3
} }
``` ```
### <span id="EncodeUrl">EncodeUrl</span> ### <span id="EncodeUrl">EncodeUrl</span>
<p>Encode url query string values.</p> <p>Encode url query string values.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -89,6 +91,7 @@ func main() {
```go ```go
func EncodeUrl(urlStr string) (string, error) func EncodeUrl(urlStr string) (string, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -102,16 +105,20 @@ import (
func main() { func main() {
urlAddr := "http://www.lancet.com?a=1&b=[2]" urlAddr := "http://www.lancet.com?a=1&b=[2]"
encodedUrl, err := netutil.EncodeUrl(urlAddr) encodedUrl, err := netutil.EncodeUrl(urlAddr)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(encodedUrl) //http://www.lancet.com?a=1&b=%5B2%5D
fmt.Println(encodedUrl)
// Output:
// http://www.lancet.com?a=1&b=%5B2%5D
} }
``` ```
### <span id="GetInternalIp">GetInternalIp</span> ### <span id="GetInternalIp">GetInternalIp</span>
<p>Get internal ip information.</p> <p>Get internal ip information.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -119,6 +126,7 @@ func main() {
```go ```go
func GetInternalIp() string func GetInternalIp() string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -134,13 +142,15 @@ func main() {
internalIp := netutil.GetInternalIp() internalIp := netutil.GetInternalIp()
ip := net.ParseIP(internalIp) ip := net.ParseIP(internalIp)
fmt.Println(ip) //192.168.1.9 fmt.Println(ip)
// Output:
// 192.168.1.9
} }
``` ```
### <span id="GetIps">GetIps</span> ### <span id="GetIps">GetIps</span>
<p>Get all ipv4 list.</p> <p>Get all ipv4 list.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -148,6 +158,7 @@ func main() {
```go ```go
func GetIps() []string func GetIps() []string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -161,13 +172,15 @@ import (
func main() { func main() {
ips := netutil.GetIps() ips := netutil.GetIps()
fmt.Println(ips) //[192.168.1.9] fmt.Println(ips)
// Output:
// [192.168.1.9]
} }
``` ```
### <span id="GetMacAddrs">GetMacAddrs</span> ### <span id="GetMacAddrs">GetMacAddrs</span>
<p>Get all mac addresses list.</p> <p>Get all mac addresses list.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -175,6 +188,7 @@ func main() {
```go ```go
func GetMacAddrs() []string { func GetMacAddrs() []string {
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -187,14 +201,16 @@ import (
) )
func main() { func main() {
addrs := netutil.GetMacAddrs() macAddrs := netutil.GetMacAddrs()
fmt.Println(addrs) fmt.Println(macAddrs)
// Output:
// [18:31:bf:09:d1:56 76:ee:2a:e6:2e:0f 74:ee:2a:e6:2e:0f 74:ee:2a:e6:2e:0f]
} }
``` ```
### <span id="GetPublicIpInfo">GetPublicIpInfo</span> ### <span id="GetPublicIpInfo">GetPublicIpInfo</span>
<p>Get public ip information.</p> <p>Get public ip information.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -216,6 +232,7 @@ type PublicIpInfo struct {
Ip string `json:"query"` Ip string `json:"query"`
} }
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -236,9 +253,8 @@ func main() {
} }
``` ```
### <span id="GetRequestPublicIp">GetRequestPublicIp</span> ### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>Get http request public ip.</p> <p>Get http request public ip.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -246,6 +262,7 @@ func main() {
```go ```go
func GetRequestPublicIp(req *http.Request) string func GetRequestPublicIp(req *http.Request) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -259,29 +276,23 @@ import (
func main() { func main() {
ip := "36.112.24.10" ip := "36.112.24.10"
request1 := http.Request{ request := http.Request{
Method: "GET", Method: "GET",
Header: http.Header{ Header: http.Header{
"X-Forwarded-For": {ip}, "X-Forwarded-For": {ip},
}, },
} }
publicIp1 := netutil.GetRequestPublicIp(&request1) publicIp := netutil.GetRequestPublicIp(&request)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{ fmt.Println(publicIp)
Method: "GET",
Header: http.Header{ // Output:
"X-Real-Ip": {ip}, // 36.112.24.10
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
} }
``` ```
### <span id="IsPublicIP">IsPublicIP</span> ### <span id="IsPublicIP">IsPublicIP</span>
<p>Checks if an ip is public or not.</p> <p>Checks if an ip is public or not.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -289,6 +300,7 @@ func main() {
```go ```go
func IsPublicIP(IP net.IP) bool func IsPublicIP(IP net.IP) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -301,18 +313,23 @@ import (
) )
func main() { func main() {
ip1 := net.ParseIP("192.168.0.1") ip1 := netutil.IsPublicIP(net.ParseIP("127.0.0.1"))
ip2 := net.ParseIP("36.112.24.10") ip2 := netutil.IsPublicIP(net.ParseIP("192.168.0.1"))
ip3 := netutil.IsPublicIP(net.ParseIP("36.112.24.10"))
fmt.Println(netutil.IsPublicIP(ip1)) //false fmt.Println(ip1)
fmt.Println(netutil.IsPublicIP(ip2)) //true fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// false
// false
// true
} }
``` ```
### <span id="IsInternalIP">IsInternalIP</span> ### <span id="IsInternalIP">IsInternalIP</span>
<p>Checks if an ip is intranet or not.</p> <p>Checks if an ip is intranet or not.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -320,6 +337,7 @@ func main() {
```go ```go
func IsInternalIP(IP net.IP) bool func IsInternalIP(IP net.IP) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -332,16 +350,23 @@ import (
) )
func main() { func main() {
ip1 := net.ParseIP("127.0.0.1") ip1 := netutil.IsInternalIP(net.ParseIP("127.0.0.1"))
ip2 := net.ParseIP("36.112.24.10") ip2 := netutil.IsInternalIP(net.ParseIP("192.168.0.1"))
ip3 := netutil.IsInternalIP(net.ParseIP("36.112.24.10"))
fmt.Println(netutil.IsInternalIP(ip1)) //true fmt.Println(ip1)
fmt.Println(netutil.IsInternalIP(ip2)) //false fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// true
// true
// false
} }
``` ```
### <span id="HttpRequest">HttpRequest</span> ### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest is a struct used to abstract HTTP request entity.</p> <p>HttpRequest is a struct used to abstract HTTP request entity.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -356,6 +381,7 @@ type HttpRequest struct {
Body []byte Body []byte
} }
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -384,8 +410,8 @@ func main() {
} }
``` ```
### <span id="HttpClient">HttpClient</span> ### <span id="HttpClient">HttpClient</span>
<p>HttpClient is a struct used to send HTTP request. It can be instanced with some configurations or none config.</p> <p>HttpClient is a struct used to send HTTP request. It can be instanced with some configurations or none config.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -412,6 +438,7 @@ func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -433,9 +460,8 @@ func main() {
} }
``` ```
### <span id="SendRequest">SendRequest</span> ### <span id="SendRequest">SendRequest</span>
<p>Use HttpClient to send HTTP request.</p> <p>Use HttpClient to send HTTP request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -443,6 +469,7 @@ func main() {
```go ```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -464,7 +491,7 @@ func main() {
httpClient := netutil.NewHttpClient() httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request) resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
log.Fatal(err) return
} }
type Todo struct { type Todo struct {
@@ -475,15 +502,20 @@ func main() {
} }
var todo Todo var todo Todo
httpClient.DecodeResponse(resp, &todo) err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
return
}
fmt.Println(todo.Id) //1 fmt.Println(todo.Id)
// Output:
// 1
} }
``` ```
### <span id="DecodeResponse">DecodeResponse</span> ### <span id="DecodeResponse">DecodeResponse</span>
<p>Decode http response into target object.</p> <p>Decode http response into target object.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -491,6 +523,7 @@ func main() {
```go ```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -512,7 +545,7 @@ func main() {
httpClient := netutil.NewHttpClient() httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request) resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
log.Fatal(err) return
} }
type Todo struct { type Todo struct {
@@ -523,14 +556,20 @@ func main() {
} }
var todo Todo var todo Todo
httpClient.DecodeResponse(resp, &todo) err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
return
}
fmt.Println(todo.Id) //1 fmt.Println(todo.Id)
// Output:
// 1
} }
``` ```
### <span id="StructToUrlValues">StructToUrlValues</span> ### <span id="StructToUrlValues">StructToUrlValues</span>
<p>Convert struct to url values, only convert the field which is exported and has `json` tag.</p> <p>Convert struct to url values, only convert the field which is exported and has `json` tag.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -538,6 +577,7 @@ func main() {
```go ```go
func StructToUrlValues(targetStruct any) url.Values func StructToUrlValues(targetStruct any) url.Values
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -551,22 +591,25 @@ import (
func main() { func main() {
type TodoQuery struct { type TodoQuery struct {
Id int `json:"id"` Id int `json:"id"`
UserId int `json:"userId"` Name string `json:"name"`
} }
todoQuery := TodoQuery{ todoQuery := TodoQuery{
Id: 1, Id: 1,
UserId: 2, Name: "Test",
} }
todoValues := netutil.StructToUrlValues(todoQuery) todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1 fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("userId")) //2 fmt.Println(todoValues.Get("name"))
// Output:
// 1
// Test
} }
``` ```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>Send http get request.</p> <p>Send http get request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -578,6 +621,7 @@ func main() {
// params[3] is http client which type should be http.Client. // params[3] is http client which type should be http.Client.
func HttpGet(url string, params ...any) (*http.Response, error) func HttpGet(url string, params ...any) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -606,9 +650,8 @@ func main() {
} }
``` ```
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>Send http post request.</p> <p>Send http post request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -620,6 +663,7 @@ func main() {
// params[3] is http client which type should be http.Client. // params[3] is http client which type should be http.Client.
func HttpPost(url string, params ...any) (*http.Response, error) func HttpPost(url string, params ...any) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -655,9 +699,8 @@ func main() {
} }
``` ```
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>Send http put request.</p> <p>Send http put request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -669,6 +712,7 @@ func main() {
// params[3] is http client which type should be http.Client. // params[3] is http client which type should be http.Client.
func HttpPut(url string, params ...any) (*http.Response, error) func HttpPut(url string, params ...any) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -705,9 +749,8 @@ func main() {
} }
``` ```
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>Send http delete request.</p> <p>Send http delete request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -719,6 +762,7 @@ func main() {
// params[3] is http client which type should be http.Client. // params[3] is http client which type should be http.Client.
func HttpDelete(url string, params ...any) (*http.Response, error) func HttpDelete(url string, params ...any) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -744,9 +788,8 @@ func main() {
} }
``` ```
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>Send http patch request.</p> <p>Send http patch request.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -758,6 +801,7 @@ func main() {
// params[3] is http client which type should be http.Client. // params[3] is http client which type should be http.Client.
func HttpPatch(url string, params ...any) (*http.Response, error) func HttpPatch(url string, params ...any) (*http.Response, error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -794,9 +838,8 @@ func main() {
} }
``` ```
### <span id="ParseHttpResponse">ParseHttpResponse</span> ### <span id="ParseHttpResponse">ParseHttpResponse</span>
<p>Decode http response to specified interface.</p> <p>Decode http response to specified interface.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -804,6 +847,7 @@ func main() {
```go ```go
func ParseHttpResponse(resp *http.Response, obj any) error func ParseHttpResponse(resp *http.Response, obj any) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -844,4 +888,3 @@ func main() {
fmt.Println(toDoResp) fmt.Println(toDoResp)
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Netutil # Netutil
netutil网络包支持获取ip地址发送http请求。
netutil 网络包支持获取 ip 地址,发送 http 请求。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,13 +8,12 @@ netutil网络包支持获取ip地址发送http请求。
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go) - [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go) - [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/netutil" "github.com/duke-git/lancet/v2/netutil"
@@ -23,6 +23,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [ConvertMapToQueryString](#ConvertMapToQueryString) - [ConvertMapToQueryString](#ConvertMapToQueryString)
- [EncodeUrl](#EncodeUrl) - [EncodeUrl](#EncodeUrl)
- [GetInternalIp](#GetInternalIp) - [GetInternalIp](#GetInternalIp)
@@ -48,8 +49,8 @@ import (
## 文档 ## 文档
### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span> ### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span>
<p>将map转换成http查询字符串.</p> <p>将map转换成http查询字符串.</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -57,7 +58,8 @@ import (
```go ```go
func ConvertMapToQueryString(param map[string]any) string func ConvertMapToQueryString(param map[string]any) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -75,13 +77,15 @@ func main() {
} }
qs := netutil.ConvertMapToQueryString(m) qs := netutil.ConvertMapToQueryString(m)
fmt.Println(qs) //a=1&b=2&c=3 fmt.Println(qs)
// Output:
// a=1&b=2&c=3
} }
``` ```
### <span id="EncodeUrl">EncodeUrl</span> ### <span id="EncodeUrl">EncodeUrl</span>
<p>编码url query string的值</p> <p>编码url query string的值</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -89,7 +93,8 @@ func main() {
```go ```go
func EncodeUrl(urlStr string) (string, error) func EncodeUrl(urlStr string) (string, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -102,17 +107,20 @@ import (
func main() { func main() {
urlAddr := "http://www.lancet.com?a=1&b=[2]" urlAddr := "http://www.lancet.com?a=1&b=[2]"
encodedUrl, err := netutil.EncodeUrl(urlAddr) encodedUrl, err := netutil.EncodeUrl(urlAddr)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(encodedUrl) //http://www.lancet.com?a=1&b=%5B2%5D
fmt.Println(encodedUrl)
// Output:
// http://www.lancet.com?a=1&b=%5B2%5D
} }
``` ```
### <span id="GetInternalIp">GetInternalIp</span> ### <span id="GetInternalIp">GetInternalIp</span>
<p>获取内部ip</p> <p>获取内部ip</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -120,7 +128,8 @@ func main() {
```go ```go
func GetInternalIp() string func GetInternalIp() string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -135,12 +144,15 @@ func main() {
internalIp := netutil.GetInternalIp() internalIp := netutil.GetInternalIp()
ip := net.ParseIP(internalIp) ip := net.ParseIP(internalIp)
fmt.Println(ip) //192.168.1.9 fmt.Println(ip)
// Output:
// 192.168.1.9
} }
``` ```
### <span id="GetIps">GetIps</span> ### <span id="GetIps">GetIps</span>
<p>获取ipv4地址列表</p> <p>获取ipv4地址列表</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -148,7 +160,8 @@ func main() {
```go ```go
func GetIps() []string func GetIps() []string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -161,13 +174,15 @@ import (
func main() { func main() {
ips := netutil.GetIps() ips := netutil.GetIps()
fmt.Println(ips) //[192.168.1.9] fmt.Println(ips)
// Output:
// [192.168.1.9]
} }
``` ```
### <span id="GetMacAddrs">GetMacAddrs</span> ### <span id="GetMacAddrs">GetMacAddrs</span>
<p>获取mac地址列</p> <p>获取mac地址列</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -175,7 +190,8 @@ func main() {
```go ```go
func GetMacAddrs() []string { func GetMacAddrs() []string {
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -187,14 +203,16 @@ import (
) )
func main() { func main() {
addrs := netutil.GetMacAddrs() macAddrs := netutil.GetMacAddrs()
fmt.Println(addrs) fmt.Println(macAddrs)
// Output:
// [18:31:bf:09:d1:56 76:ee:2a:e6:2e:0f 74:ee:2a:e6:2e:0f 74:ee:2a:e6:2e:0f]
} }
``` ```
### <span id="GetPublicIpInfo">GetPublicIpInfo</span> ### <span id="GetPublicIpInfo">GetPublicIpInfo</span>
<p>获取公网ip信息</p> <p>获取公网ip信息</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -216,7 +234,8 @@ type PublicIpInfo struct {
Ip string `json:"query"` Ip string `json:"query"`
} }
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -236,9 +255,8 @@ func main() {
} }
``` ```
### <span id="GetRequestPublicIp">GetRequestPublicIp</span> ### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>获取http请求ip</p> <p>获取http请求ip</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -246,7 +264,8 @@ func main() {
```go ```go
func GetRequestPublicIp(req *http.Request) string func GetRequestPublicIp(req *http.Request) string
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -259,30 +278,23 @@ import (
func main() { func main() {
ip := "36.112.24.10" ip := "36.112.24.10"
request1 := http.Request{ request := http.Request{
Method: "GET", Method: "GET",
Header: http.Header{ Header: http.Header{
"X-Forwarded-For": {ip}, "X-Forwarded-For": {ip},
}, },
} }
publicIp1 := netutil.GetRequestPublicIp(&request1) publicIp := netutil.GetRequestPublicIp(&request)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{ fmt.Println(publicIp)
Method: "GET",
Header: http.Header{ // Output:
"X-Real-Ip": {ip}, // 36.112.24.10
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
} }
``` ```
### <span id="IsPublicIP">IsPublicIP</span> ### <span id="IsPublicIP">IsPublicIP</span>
<p>判断ip是否是公共ip</p> <p>判断ip是否是公共ip</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -290,7 +302,8 @@ func main() {
```go ```go
func IsPublicIP(IP net.IP) bool func IsPublicIP(IP net.IP) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -302,17 +315,23 @@ import (
) )
func main() { func main() {
ip1 := net.ParseIP("192.168.0.1") ip1 := netutil.IsPublicIP(net.ParseIP("127.0.0.1"))
ip2 := net.ParseIP("36.112.24.10") ip2 := netutil.IsPublicIP(net.ParseIP("192.168.0.1"))
ip3 := netutil.IsPublicIP(net.ParseIP("36.112.24.10"))
fmt.Println(netutil.IsPublicIP(ip1)) //false fmt.Println(ip1)
fmt.Println(netutil.IsPublicIP(ip2)) //true fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// false
// false
// true
} }
``` ```
### <span id="IsInternalIP">IsInternalIP</span> ### <span id="IsInternalIP">IsInternalIP</span>
<p>判断ip是否是局域网ip.</p> <p>判断ip是否是局域网ip.</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -320,7 +339,8 @@ func main() {
```go ```go
func IsInternalIP(IP net.IP) bool func IsInternalIP(IP net.IP) bool
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -332,16 +352,23 @@ import (
) )
func main() { func main() {
ip1 := net.ParseIP("127.0.0.1") ip1 := netutil.IsInternalIP(net.ParseIP("127.0.0.1"))
ip2 := net.ParseIP("36.112.24.10") ip2 := netutil.IsInternalIP(net.ParseIP("192.168.0.1"))
ip3 := netutil.IsInternalIP(net.ParseIP("36.112.24.10"))
fmt.Println(netutil.IsInternalIP(ip1)) //true fmt.Println(ip1)
fmt.Println(netutil.IsInternalIP(ip2)) //false fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// true
// true
// false
} }
``` ```
### <span id="HttpRequest">HttpRequest</span> ### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest用于抽象HTTP请求实体的结构</p> <p>HttpRequest用于抽象HTTP请求实体的结构</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -356,7 +383,8 @@ type HttpRequest struct {
Body []byte Body []byte
} }
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -384,8 +412,8 @@ func main() {
} }
``` ```
### <span id="HttpClient">HttpClient</span> ### <span id="HttpClient">HttpClient</span>
<p>HttpClient是用于发送HTTP请求的结构体。它可以用一些配置参数或无配置实例化.</p> <p>HttpClient是用于发送HTTP请求的结构体。它可以用一些配置参数或无配置实例化.</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -412,7 +440,8 @@ func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -433,9 +462,8 @@ func main() {
} }
``` ```
### <span id="SendRequest">SendRequest</span> ### <span id="SendRequest">SendRequest</span>
<p>HttpClient发送http请求</p> <p>HttpClient发送http请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -443,7 +471,8 @@ func main() {
```go ```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -464,7 +493,7 @@ func main() {
httpClient := netutil.NewHttpClient() httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request) resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
log.Fatal(err) return
} }
type Todo struct { type Todo struct {
@@ -475,15 +504,20 @@ func main() {
} }
var todo Todo var todo Todo
httpClient.DecodeResponse(resp, &todo) err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
return
}
fmt.Println(todo.Id) //1 fmt.Println(todo.Id)
// Output:
// 1
} }
``` ```
### <span id="DecodeResponse">DecodeResponse</span> ### <span id="DecodeResponse">DecodeResponse</span>
<p>解析http响应体到目标结构体</p> <p>解析http响应体到目标结构体</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -491,7 +525,8 @@ func main() {
```go ```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -512,7 +547,7 @@ func main() {
httpClient := netutil.NewHttpClient() httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request) resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
log.Fatal(err) return
} }
type Todo struct { type Todo struct {
@@ -523,22 +558,29 @@ func main() {
} }
var todo Todo var todo Todo
httpClient.DecodeResponse(resp, &todo) err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
return
}
fmt.Println(todo.Id) //1 fmt.Println(todo.Id)
// Output:
// 1
} }
``` ```
### <span id="StructToUrlValues">StructToUrlValues</span> ### <span id="StructToUrlValues">StructToUrlValues</span>
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag.</p>
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func StructToUrlValues(targetStruct any) url.Values func StructToUrlValues(targetStruct any) url.Values
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -551,22 +593,25 @@ import (
func main() { func main() {
type TodoQuery struct { type TodoQuery struct {
Id int `json:"id"` Id int `json:"id"`
UserId int `json:"userId"` Name string `json:"name"`
} }
todoQuery := TodoQuery{ todoQuery := TodoQuery{
Id: 1, Id: 1,
UserId: 2, Name: "Test",
} }
todoValues := netutil.StructToUrlValues(todoQuery) todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1 fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("userId")) //2 fmt.Println(todoValues.Get("name"))
// Output:
// 1
// Test
} }
``` ```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>发送http get请求</p> <p>发送http get请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -578,7 +623,8 @@ func main() {
// params[3] http client类型必须是http.Client // params[3] http client类型必须是http.Client
func HttpGet(url string, params ...any) (*http.Response, error) func HttpGet(url string, params ...any) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -606,9 +652,8 @@ func main() {
} }
``` ```
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>发送http post请求</p> <p>发送http post请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -620,7 +665,8 @@ func main() {
// params[3] http client类型必须是http.Client // params[3] http client类型必须是http.Client
func HttpPost(url string, params ...any) (*http.Response, error) func HttpPost(url string, params ...any) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -655,9 +701,8 @@ func main() {
} }
``` ```
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>发送http put请求</p> <p>发送http put请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -669,7 +714,8 @@ func main() {
// params[3] http client类型必须是http.Client // params[3] http client类型必须是http.Client
func HttpPut(url string, params ...any) (*http.Response, error) func HttpPut(url string, params ...any) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -705,9 +751,8 @@ func main() {
} }
``` ```
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>发送http delete请求</p> <p>发送http delete请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -719,7 +764,8 @@ func main() {
// params[3] http client类型必须是http.Client // params[3] http client类型必须是http.Client
func HttpDelete(url string, params ...any) (*http.Response, error) func HttpDelete(url string, params ...any) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -744,9 +790,8 @@ func main() {
} }
``` ```
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span> ### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>发送http patch请求</p> <p>发送http patch请求</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -758,7 +803,8 @@ func main() {
// params[3] http client类型必须是http.Client // params[3] http client类型必须是http.Client
func HttpPatch(url string, params ...any) (*http.Response, error) func HttpPatch(url string, params ...any) (*http.Response, error)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -794,9 +840,8 @@ func main() {
} }
``` ```
### <span id="ParseHttpResponse">ParseHttpResponse</span> ### <span id="ParseHttpResponse">ParseHttpResponse</span>
<p>将http请求响应解码成特定struct值</p> <p>将http请求响应解码成特定struct值</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -804,7 +849,8 @@ func main() {
```go ```go
func ParseHttpResponse(resp *http.Response, obj any) error func ParseHttpResponse(resp *http.Response, obj any) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -844,4 +890,3 @@ func main() {
fmt.Println(toDoResp) fmt.Println(toDoResp)
} }
``` ```

View File

@@ -45,7 +45,7 @@ import (
func RandBytes(length int) []byte func RandBytes(length int) []byte
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -71,7 +71,7 @@ func main() {
func RandInt(min, max int) int func RandInt(min, max int) int
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -97,7 +97,7 @@ func main() {
func RandString(length int) string func RandString(length int) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -123,7 +123,7 @@ func main() {
func RandUpper(length int) string func RandUpper(length int) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -149,7 +149,7 @@ func main() {
func RandLower(length int) string func RandLower(length int) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -175,7 +175,7 @@ func main() {
func RandNumeral(length int) string func RandNumeral(length int) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -201,7 +201,7 @@ func main() {
func RandNumeralOrLetter(length int) string func RandNumeralOrLetter(length int) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -227,7 +227,7 @@ func main() {
func UUIdV4() (string, error) func UUIdV4() (string, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main

View File

@@ -1,4 +1,5 @@
# Retry # Retry
Package retry is for executing a function repeatedly until it was successful or canceled by the context. Package retry is for executing a function repeatedly until it was successful or canceled by the context.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ Package retry is for executing a function repeatedly until it was successful or
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go) - [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/retry" "github.com/duke-git/lancet/v2/retry"
@@ -20,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [Context](#Context) - [Context](#Context)
- [Retry](#Retry) - [Retry](#Retry)
- [RetryFunc](#RetryFunc) - [RetryFunc](#RetryFunc)
@@ -30,8 +32,8 @@ import (
## Documentation ## Documentation
### <span id="Context">Context</span> ### <span id="Context">Context</span>
<p>Set retry context config, can cancel the retry with context.</p> <p>Set retry context config, can cancel the retry with context.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -39,6 +41,7 @@ import (
```go ```go
func Context(ctx context.Context) func Context(ctx context.Context)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -52,7 +55,8 @@ import (
func main() { func main() {
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
var number int
number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number > 3 { if number > 3 {
@@ -61,21 +65,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, duration := retry.RetryDuration(time.Microsecond*50)
retry.RetryDuration(time.Microsecond*50),
retry.Retry(increaseNumber,
duration,
retry.Context(ctx), retry.Context(ctx),
) )
if err != nil { fmt.Println(number)
fmt.Println(err) //retry is cancelled
} // Output:
// 4
} }
``` ```
### <span id="RetryFunc">RetryFunc</span> ### <span id="RetryFunc">RetryFunc</span>
<p>Function that retry executes.</p> <p>Function that retry executes.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -83,6 +88,7 @@ func main() {
```go ```go
type RetryFunc func() error type RetryFunc func() error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -96,9 +102,8 @@ import (
) )
func main() { func main() {
var number int number := 0
var increaseNumber retry.RetryFunc = func() error {
increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
return nil return nil
@@ -106,18 +111,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```
### <span id="RetryTimes">RetryTimes</span> ### <span id="RetryTimes">RetryTimes</span>
<p>Set times of retry. Default times is 5.</p> <p>Set times of retry. Default times is 5.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -125,6 +134,7 @@ func main() {
```go ```go
func RetryTimes(n uint) func RetryTimes(n uint)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -138,7 +148,7 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
@@ -150,14 +160,16 @@ func main() {
err := retry.Retry(increaseNumber, retry.RetryTimes(2)) err := retry.Retry(increaseNumber, retry.RetryTimes(2))
if err != nil { if err != nil {
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1 fmt.Println(err)
} }
// Output:
// function main.main.func1 run failed after 2 times retry
} }
``` ```
### <span id="RetryDuration">RetryDuration</span> ### <span id="RetryDuration">RetryDuration</span>
<p>Set duration of retries. Default duration is 3 second.</p> <p>Set duration of retries. Default duration is 3 second.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -165,6 +177,7 @@ func main() {
```go ```go
func RetryDuration(d time.Duration) func RetryDuration(d time.Duration)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -178,7 +191,7 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
@@ -187,17 +200,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```
### <span id="Retry">Retry</span> ### <span id="Retry">Retry</span>
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p> <p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -205,6 +223,7 @@ func main() {
```go ```go
func Retry(retryFunc RetryFunc, opts ...Option) error func Retry(retryFunc RetryFunc, opts ...Option) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -218,7 +237,7 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
@@ -227,11 +246,16 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Retry # Retry
retry重试执行函数直到函数运行成功或被context cancel。
retry 重试执行函数直到函数运行成功或被 context cancel。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ retry重试执行函数直到函数运行成功或被context cancel。
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go) - [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/retry" "github.com/duke-git/lancet/v2/retry"
@@ -20,20 +21,19 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [Context](#Context) - [Context](#Context)
- [Retry](#Retry) - [Retry](#Retry)
- [RetryFunc](#RetryFunc) - [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration) - [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes) - [RetryTimes](#RetryTimes)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Document 文档
## Document文档
### <span id="Context">Context</span> ### <span id="Context">Context</span>
<p>设置重试context参数</p> <p>设置重试context参数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -41,7 +41,8 @@ import (
```go ```go
func Context(ctx context.Context) func Context(ctx context.Context)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
import ( import (
@@ -54,7 +55,8 @@ import (
func main() { func main() {
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
var number int
number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number > 3 { if number > 3 {
@@ -63,21 +65,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, duration := retry.RetryDuration(time.Microsecond*50)
retry.RetryDuration(time.Microsecond*50),
retry.Retry(increaseNumber,
duration,
retry.Context(ctx), retry.Context(ctx),
) )
if err != nil { fmt.Println(number)
fmt.Println(err) //retry is cancelled
} // Output:
// 4
} }
``` ```
### <span id="RetryFunc">RetryFunc</span> ### <span id="RetryFunc">RetryFunc</span>
<p>被重试执行的函数</p> <p>被重试执行的函数</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -85,7 +88,8 @@ func main() {
```go ```go
type RetryFunc func() error type RetryFunc func() error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -98,8 +102,8 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { var increaseNumber retry.RetryFunc = func() error {
number++ number++
if number == 3 { if number == 3 {
return nil return nil
@@ -107,18 +111,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```
### <span id="RetryTimes">RetryTimes</span> ### <span id="RetryTimes">RetryTimes</span>
<p>设置重试次数默认5</p> <p>设置重试次数默认5</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -126,7 +134,8 @@ func main() {
```go ```go
func RetryTimes(n uint) func RetryTimes(n uint)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -139,7 +148,8 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
@@ -150,14 +160,16 @@ func main() {
err := retry.Retry(increaseNumber, retry.RetryTimes(2)) err := retry.Retry(increaseNumber, retry.RetryTimes(2))
if err != nil { if err != nil {
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1 fmt.Println(err)
} }
// Output:
// function main.main.func1 run failed after 2 times retry
} }
``` ```
### <span id="RetryDuration">RetryDuration</span> ### <span id="RetryDuration">RetryDuration</span>
<p>设置重试间隔时间默认3秒</p> <p>设置重试间隔时间默认3秒</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -165,7 +177,8 @@ func main() {
```go ```go
func RetryDuration(d time.Duration) func RetryDuration(d time.Duration)
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -178,7 +191,7 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
@@ -187,17 +200,22 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```
### <span id="Retry">Retry</span> ### <span id="Retry">Retry</span>
<p>重试执行函数retryFunc直到函数运行成功或被context停止</p> <p>重试执行函数retryFunc直到函数运行成功或被context停止</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -205,7 +223,8 @@ func main() {
```go ```go
func Retry(retryFunc RetryFunc, opts ...Option) error func Retry(retryFunc RetryFunc, opts ...Option) error
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -218,7 +237,7 @@ import (
) )
func main() { func main() {
var number int number := 0
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
if number == 3 { if number == 3 {
@@ -227,11 +246,16 @@ func main() {
return errors.New("error occurs") return errors.New("error occurs")
} }
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50)) duration := retry.RetryDuration(time.Microsecond*50)
err := retry.Retry(increaseNumber, duration)
if err != nil { if err != nil {
log.Fatal(err) return
} }
fmt.Println(number) //3 fmt.Println(number)
// Output:
// 3
} }
``` ```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
# System # System
Package system contains some functions about os, runtime, shell command. Package system contains some functions about os, runtime, shell command.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ Package system contains some functions about os, runtime, shell command.
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go) - [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/system" "github.com/duke-git/lancet/v2/system"
@@ -20,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [IsWindows](#IsWindows) - [IsWindows](#IsWindows)
- [IsLinux](#IsLinux) - [IsLinux](#IsLinux)
- [IsMac](#IsMac) - [IsMac](#IsMac)
@@ -30,13 +32,12 @@ import (
- [ExecCommand](#ExecCommand) - [ExecCommand](#ExecCommand)
- [GetOsBits](#GetOsBits) - [GetOsBits](#GetOsBits)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="IsWindows">IsWindows</span> ### <span id="IsWindows">IsWindows</span>
<p>Check if current os is windows.</p> <p>Check if current os is windows.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -44,6 +45,7 @@ import (
```go ```go
func IsWindows() bool func IsWindows() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -58,10 +60,8 @@ func main() {
} }
``` ```
### <span id="IsLinux">IsLinux</span> ### <span id="IsLinux">IsLinux</span>
<p>Check if current os is linux.</p> <p>Check if current os is linux.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -69,6 +69,7 @@ func main() {
```go ```go
func IsLinux() bool func IsLinux() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -83,9 +84,8 @@ func main() {
} }
``` ```
### <span id="IsMac">IsMac</span> ### <span id="IsMac">IsMac</span>
<p>Check if current os is macos.</p> <p>Check if current os is macos.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -93,6 +93,7 @@ func main() {
```go ```go
func IsMac() bool func IsMac() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -107,9 +108,8 @@ func main() {
} }
``` ```
### <span id="GetOsEnv">GetOsEnv</span> ### <span id="GetOsEnv">GetOsEnv</span>
<p>Gets the value of the environment variable named by the key.</p> <p>Gets the value of the environment variable named by the key.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -117,6 +117,7 @@ func main() {
```go ```go
func GetOsEnv(key string) string func GetOsEnv(key string) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -126,14 +127,19 @@ import (
) )
func main() { func main() {
fooEnv := system.GetOsEnv("foo") err := system.SetOsEnv("foo", "abc")
fmt.Println(fooEnv) result := system.GetOsEnv("foo")
fmt.Println(err)
fmt.Println(result)
// Output:
// <nil>
// abc
} }
``` ```
### <span id="SetOsEnv">SetOsEnv</span> ### <span id="SetOsEnv">SetOsEnv</span>
<p>Sets the value of the environment variable named by the key.</p> <p>Sets the value of the environment variable named by the key.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -141,6 +147,7 @@ func main() {
```go ```go
func SetOsEnv(key, value string) error func SetOsEnv(key, value string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -150,15 +157,19 @@ import (
) )
func main() { func main() {
err := system.SetOsEnv("foo", "foo_value") err := system.SetOsEnv("foo", "abc")
result := system.GetOsEnv("foo")
fmt.Println(err) fmt.Println(err)
fmt.Println(result)
// Output:
// <nil>
// abc
} }
``` ```
### <span id="RemoveOsEnv">RemoveOsEnv</span> ### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>Remove a single environment variable.</p> <p>Remove a single environment variable.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -166,6 +177,7 @@ func main() {
```go ```go
func RemoveOsEnv(key string) error func RemoveOsEnv(key string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -175,16 +187,27 @@ import (
) )
func main() { func main() {
err := system.RemoveOsEnv("foo") err1 := system.SetOsEnv("foo", "abc")
if err != nil { result1 := GetOsEnv("foo")
fmt.Println(err)
} err2 := system.RemoveOsEnv("foo")
result2 := GetOsEnv("foo")
fmt.Println(err1)
fmt.Println(err2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// <nil>
// <nil>
// abc
//
} }
``` ```
### <span id="CompareOsEnv">CompareOsEnv</span> ### <span id="CompareOsEnv">CompareOsEnv</span>
<p>Get env named by the key and compare it with comparedEnv.</p> <p>Get env named by the key and compare it with comparedEnv.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -192,6 +215,7 @@ func main() {
```go ```go
func CompareOsEnv(key, comparedEnv string) bool func CompareOsEnv(key, comparedEnv string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -201,16 +225,22 @@ import (
) )
func main() { func main() {
system.SetOsEnv("foo", "foo_value") err := system.SetOsEnv("foo", "abc")
res := system.CompareOsEnv("foo", "foo_value") if err != nil {
fmt.Println(res) //true return
}
result := system.CompareOsEnv("foo", "abc")
fmt.Println(result)
// Output:
// true
} }
``` ```
### <span id="ExecCommand">CompareOsEnv</span> ### <span id="ExecCommand">CompareOsEnv</span>
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p> <p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -218,6 +248,7 @@ func main() {
```go ```go
func ExecCommand(command string) (stdout, stderr string, err error) func ExecCommand(command string) (stdout, stderr string, err error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -248,10 +279,8 @@ func main() {
} }
``` ```
### <span id="GetOsBits">GetOsBits</span> ### <span id="GetOsBits">GetOsBits</span>
<p>Get current os bits, 32bit or 64bit. return 32 or 64</p> <p>Get current os bits, 32bit or 64bit. return 32 or 64</p>
<b>Signature:</b> <b>Signature:</b>
@@ -259,6 +288,7 @@ func main() {
```go ```go
func GetOsBits() int func GetOsBits() int
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -269,9 +299,6 @@ import (
func main() { func main() {
osBit := system.GetOsBits() osBit := system.GetOsBits()
fmt.Println(osBit) fmt.Println(osBit) // 32 or 64
} }
``` ```

View File

@@ -1,5 +1,6 @@
# System # System
system包含os, runtime, shell command相关函数。
system 包含 os, runtime, shell command 相关函数。
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -7,10 +8,10 @@ system包含os, runtime, shell command相关函数。
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go) - [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/system" "github.com/duke-git/lancet/v2/system"
@@ -20,6 +21,7 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [IsWindows](#IsWindows) - [IsWindows](#IsWindows)
- [IsLinux](#IsLinux) - [IsLinux](#IsLinux)
- [IsMac](#IsMac) - [IsMac](#IsMac)
@@ -30,13 +32,12 @@ import (
- [ExecCommand](#ExecCommand) - [ExecCommand](#ExecCommand)
- [GetOsBits](#GetOsBits) - [GetOsBits](#GetOsBits)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation文档 ## Documentation 文档
### <span id="IsWindows">IsWindows</span> ### <span id="IsWindows">IsWindows</span>
<p>检查当前操作系统是否是windows</p> <p>检查当前操作系统是否是windows</p>
<b>Signature:</b> <b>Signature:</b>
@@ -44,6 +45,7 @@ import (
```go ```go
func IsWindows() bool func IsWindows() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -58,10 +60,8 @@ func main() {
} }
``` ```
### <span id="IsLinux">IsLinux</span> ### <span id="IsLinux">IsLinux</span>
<p>检查当前操作系统是否是linux</p> <p>检查当前操作系统是否是linux</p>
<b>Signature:</b> <b>Signature:</b>
@@ -69,6 +69,7 @@ func main() {
```go ```go
func IsLinux() bool func IsLinux() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -83,9 +84,8 @@ func main() {
} }
``` ```
### <span id="IsMac">IsMac</span> ### <span id="IsMac">IsMac</span>
<p>检查当前操作系统是否是macos</p> <p>检查当前操作系统是否是macos</p>
<b>Signature:</b> <b>Signature:</b>
@@ -93,6 +93,7 @@ func main() {
```go ```go
func IsMac() bool func IsMac() bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -107,9 +108,8 @@ func main() {
} }
``` ```
### <span id="GetOsEnv">GetOsEnv</span> ### <span id="GetOsEnv">GetOsEnv</span>
<p>获取key命名的环境变量的值</p> <p>获取key命名的环境变量的值</p>
<b>Signature:</b> <b>Signature:</b>
@@ -117,6 +117,7 @@ func main() {
```go ```go
func GetOsEnv(key string) string func GetOsEnv(key string) string
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -126,14 +127,19 @@ import (
) )
func main() { func main() {
fooEnv := system.GetOsEnv("foo") err := system.SetOsEnv("foo", "abc")
fmt.Println(fooEnv) result := system.GetOsEnv("foo")
fmt.Println(err)
fmt.Println(result)
// Output:
// <nil>
// abc
} }
``` ```
### <span id="SetOsEnv">SetOsEnv</span> ### <span id="SetOsEnv">SetOsEnv</span>
<p>设置由key命名的环境变量的值</p> <p>设置由key命名的环境变量的值</p>
<b>Signature:</b> <b>Signature:</b>
@@ -141,6 +147,7 @@ func main() {
```go ```go
func SetOsEnv(key, value string) error func SetOsEnv(key, value string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -150,15 +157,19 @@ import (
) )
func main() { func main() {
err := system.SetOsEnv("foo", "foo_value") err := system.SetOsEnv("foo", "abc")
result := system.GetOsEnv("foo")
fmt.Println(err) fmt.Println(err)
fmt.Println(result)
// Output:
// <nil>
// abc
} }
``` ```
### <span id="RemoveOsEnv">RemoveOsEnv</span> ### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>删除单个环境变量</p> <p>删除单个环境变量</p>
<b>Signature:</b> <b>Signature:</b>
@@ -166,6 +177,7 @@ func main() {
```go ```go
func RemoveOsEnv(key string) error func RemoveOsEnv(key string) error
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -175,16 +187,27 @@ import (
) )
func main() { func main() {
err := system.RemoveOsEnv("foo") err1 := system.SetOsEnv("foo", "abc")
if err != nil { result1 := GetOsEnv("foo")
fmt.Println(err)
} err2 := system.RemoveOsEnv("foo")
result2 := GetOsEnv("foo")
fmt.Println(err1)
fmt.Println(err2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// <nil>
// <nil>
// abc
//
} }
``` ```
### <span id="CompareOsEnv">CompareOsEnv</span> ### <span id="CompareOsEnv">CompareOsEnv</span>
<p>获取key命名的环境变量值并与compareEnv进行比较</p> <p>获取key命名的环境变量值并与compareEnv进行比较</p>
<b>Signature:</b> <b>Signature:</b>
@@ -192,6 +215,7 @@ func main() {
```go ```go
func CompareOsEnv(key, comparedEnv string) bool func CompareOsEnv(key, comparedEnv string) bool
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -201,16 +225,22 @@ import (
) )
func main() { func main() {
system.SetOsEnv("foo", "foo_value") err := system.SetOsEnv("foo", "abc")
res := system.CompareOsEnv("foo", "foo_value") if err != nil {
fmt.Println(res) //true return
}
result := system.CompareOsEnv("foo", "abc")
fmt.Println(result)
// Output:
// true
} }
``` ```
### <span id="ExecCommand">ExecCommand</span> ### <span id="ExecCommand">ExecCommand</span>
<p>执行shell命令返回命令的stdout和stderr字符串如果出现错误则返回错误。参数`command`是一个完整的命令字符串如ls-alinuxdirwindowsping 127.0.0.1。在linux中使用/bin/bash-c执行命令在windows中使用powershell.exe执行命令。</p> <p>执行shell命令返回命令的stdout和stderr字符串如果出现错误则返回错误。参数`command`是一个完整的命令字符串如ls-alinuxdirwindowsping 127.0.0.1。在linux中使用/bin/bash-c执行命令在windows中使用powershell.exe执行命令。</p>
<b>Signature:</b> <b>Signature:</b>
@@ -218,6 +248,7 @@ func main() {
```go ```go
func ExecCommand(command string) (stdout, stderr string, err error) func ExecCommand(command string) (stdout, stderr string, err error)
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -248,10 +279,8 @@ func main() {
} }
``` ```
### <span id="GetOsBits">GetOsBits</span> ### <span id="GetOsBits">GetOsBits</span>
<p>获取当前操作系统位数返回32或64</p> <p>获取当前操作系统位数返回32或64</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -259,7 +288,8 @@ func main() {
```go ```go
func GetOsBits() int func GetOsBits() int
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
import ( import (
@@ -269,13 +299,6 @@ import (
func main() { func main() {
osBit := system.GetOsBits() osBit := system.GetOsBits()
fmt.Println(osBit) fmt.Println(osBit) // 32 or 64
} }
``` ```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
# Xerror # Xerror
Package xerror implements helpers for errors. Package xerror implements helpers for errors.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ Package xerror implements helpers for errors.
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Usage: ## Usage:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/xerror" "github.com/duke-git/lancet/v2/xerror"
@@ -19,22 +21,43 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Index ## Index
- [New](#New)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap) - [Unwrap](#Unwrap)
- [XError_Wrap](#XError_Wrap)
- [XError_Unwrap](#XError_Unwrap)
- [XError_With](#XError_With)
- [XError_Is](#XError_Is)
- [XError_Id](#XError_Id)
- [XError_Values](#XError_Values)
- [XError_StackTrace](#XError_StackTrace)
- [XError_Info](#XError_Info)
- [XError_Error](#XError_Error)
- [TryUnwrap](#TryUnwrap)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Documentation ## Documentation
### <span id="New">New</span>
<p>Creates a new XError pointer instance with message.</p>
### <span id="Unwrap">Unwrap</span>
<p>Unwrap if err is nil then it returns a valid value. If err is not nil, Unwrap panics with err.</p>
<b>Signature:</b> <b>Signature:</b>
```go ```go
func Unwrap[T any](val T, err error) T type XError struct {
id string
message string
stack *stack
cause error
values map[string]any
}
func New(format string, args ...any) *XError
``` ```
<b>Example:</b> <b>Example:</b>
```go ```go
@@ -46,12 +69,420 @@ import (
) )
func main() { func main() {
err := xerror.New("error")
fmt.Println(err.Error())
// Output:
// error
}
```
### <span id="Wrap">Wrap</span>
<p>Creates a new XError pointer instance based on error object, and add message.</p>
<b>Signature:</b>
```go
func Wrap(cause error, message ...any) *XError
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("wrong password")
wrapErr := xerror.Wrap(err, "error")
fmt.Println(wrapErr.Error())
// Output:
// error: wrong password
}
```
### <span id="Unwrap">Unwrap</span>
<p>Returns unwrapped XError from err by errors.As. If no XError, returns nil.</p>
<b>Signature:</b>
```go
func Unwrap(err error) *XError
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/pkg/errors"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").With("level", "high")
wrapErr := errors.Wrap(err1, "oops")
err := xerror.Unwrap(wrapErr)
values := err.Values()
fmt.Println(values["level"])
// Output:
// high
}
```
### <span id="XError_Wrap">XError_Wrap</span>
<p>Creates a new XError and copy message and id to new one.</p>
<b>Signature:</b>
```go
func (e *XError) Wrap(cause error) *XError
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("wrong password")
wrapErr := xerror.Wrap(err, "error")
fmt.Println(wrapErr.Error())
// Output:
// error: wrong password
}
```
### <span id="XError_Unwrap">XError_Unwrap</span>
<p>Compatible with github.com/pkg/errors.</p>
<b>Signature:</b>
```go
func (e *XError) Unwrap() error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").With("level", "high")
err2 := err1.Wrap(errors.New("invalid username"))
err := err2.Unwrap()
fmt.Println(err.Error())
// Output:
// invalid username
}
```
### <span id="XError_With">XError_With</span>
<p>Adds key and value related to the XError object.</p>
<b>Signature:</b>
```go
func (e *XError) With(key string, value any) *XError
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
```
### <span id="XError_Id">XError_Id</span>
<p>Sets XError object id to check equality in XError.Is.</p>
<b>Signature:</b>
```go
func (e *XError) Id(id string) *XError
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").Id("e001")
err2 := xerror.New("error").Id("e001")
err3 := xerror.New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
```
### <span id="XError_Is">XError_Is</span>
<p>Checks if target error is XError and Error.id of two errors are matched.</p>
<b>Signature:</b>
```go
func (e *XError) Is(target error) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").Id("e001")
err2 := xerror.New("error").Id("e001")
err3 := xerror.New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
```
### <span id="XError_Values">XError_Values</span>
<p>Returns map of key and value that is set by With. All wrapped xerror.XError key and values will be merged. Key and values of wrapped error is overwritten by upper xerror.XError.</p>
<b>Signature:</b>
```go
func (e *XError) Values() map[string]any
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
```
### <span id="XError_StackTrace">XError_StackTrace</span>
<p>Returns stack trace which is compatible with pkg/errors.</p>
<b>Signature:</b>
```go
func (e *XError) StackTrace() StackTrace
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error")
stacks := err.Stacks()
fmt.Println(stacks[0].Func)
fmt.Println(stacks[0].Line)
containFile := strings.Contains(stacks[0].File, "xxx.go")
fmt.Println(containFile)
}
```
### <span id="XError_Info">XError_Info</span>
<p>Returns information of xerror, which can be printed.</p>
<b>Signature:</b>
```go
func (e *XError) Info() *errInfo
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
cause := errors.New("error")
err := xerror.Wrap(cause, "invalid username").Id("e001").With("level", "high")
errInfo := err.Info()
fmt.Println(errInfo.Id)
fmt.Println(errInfo.Cause)
fmt.Println(errInfo.Values["level"])
fmt.Println(errInfo.Message)
// Output:
// e001
// error
// high
// invalid username
}
```
### <span id="XError_Error">XError_Error</span>
<p>Error implements standard error interface.</p>
<b>Signature:</b>
```go
func (e *XError) Error() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error")
fmt.Println(err.Error())
// Output:
// error
}
```
### <span id="TryUnwrap">TryUnwrap</span>
<p>TryUnwrap if err is nil then it returns a valid value. If err is not nil, Unwrap panics with err.</p>
<b>Signature:</b>
```go
func TryUnwrap[T any](val T, err error) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
result1 := xerror.TryUnwrap(strconv.Atoi("42"))
fmt.Println(result1)
_, err := strconv.Atoi("4o2") _, err := strconv.Atoi("4o2")
defer func() { defer func() {
v := recover() v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error() result2 := reflect.DeepEqual(err.Error(), v.(*strconv.NumError).Error())
fmt.Println(result2)
}() }()
xerror.Unwrap(strconv.Atoi("4o2")) xerror.TryUnwrap(strconv.Atoi("4o2"))
// Output:
// 42
// true
} }
``` ```

View File

@@ -1,5 +1,6 @@
# Xerror # Xerror
xerror错误处理逻辑封装
xerror 错误处理逻辑封装
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -10,6 +11,7 @@ xerror错误处理逻辑封装
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 用法: ## 用法:
```go ```go
import ( import (
"github.com/duke-git/lancet/v2/xerror" "github.com/duke-git/lancet/v2/xerror"
@@ -19,23 +21,44 @@ import (
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 目录 ## 目录
- [New](#New)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap) - [Unwrap](#Unwrap)
- [XError_Wrap](#XError_Wrap)
- [XError_Unwrap](#XError_Unwrap)
- [XError_With](#XError_With)
- [XError_Is](#XError_Is)
- [XError_Id](#XError_Id)
- [XError_Values](#XError_Values)
- [XError_StackTrace](#XError_StackTrace)
- [XError_Info](#XError_Info)
- [XError_Error](#XError_Error)
- [TryUnwrap](#TryUnwrap)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 文档 ## 文档
### <span id="New">New</span>
<p>创建XError对象实例。</p>
### <span id="Unwrap">Unwrap</span>
<p>如果err为nil则展开则它返回一个有效值。 如果err不是nil则Unwrap使用err发生恐慌。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Unwrap[T any](val T, err error) T type XError struct {
id string
message string
stack *stack
cause error
values map[string]any
}
func New(format string, args ...any) *XError
``` ```
<b>例子:</b>
<b>示例:</b>
```go ```go
package main package main
@@ -46,12 +69,421 @@ import (
) )
func main() { func main() {
err := xerror.New("error")
fmt.Println(err.Error())
// Output:
// error
}
```
### <span id="Wrap">Wrap</span>
<p>根据error对象创建XError对象实例可添加message。</p>
<b>函数签名:</b>
```go
func Wrap(cause error, message ...any) *XError
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("wrong password")
wrapErr := xerror.Wrap(err, "error")
fmt.Println(wrapErr.Error())
// Output:
// error: wrong password
}
```
### <span id="Unwrap">Unwrap</span>
<p>从error对象中解构出XError。</p>
<b>函数签名:</b>
```go
func Unwrap(err error) *XError
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/pkg/errors"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").With("level", "high")
wrapErr := errors.Wrap(err1, "oops")
err := xerror.Unwrap(wrapErr)
values := err.Values()
fmt.Println(values["level"])
// Output:
// high
}
```
### <span id="XError_Wrap">XError_Wrap</span>
<p>创建新的XError对象并将消息和id复制到新的对象中。</p>
<b>函数签名:</b>
```go
func (e *XError) Wrap(cause error) *XError
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("wrong password")
wrapErr := xerror.Wrap(err, "error")
fmt.Println(wrapErr.Error())
// Output:
// error: wrong password
}
```
### <span id="XError_Unwrap">XError_Unwrap</span>
<p>解构XEerror为error对象。适配github.com/pkg/errors。</p>
<b>函数签名:</b>
```go
func (e *XError) Unwrap() error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").With("level", "high")
err2 := err1.Wrap(errors.New("invalid username"))
err := err2.Unwrap()
fmt.Println(err.Error())
// Output:
// invalid username
}
```
### <span id="XError_With">XError_With</span>
<p>添加与XError对象的键和值。</p>
<b>函数签名:</b>
```go
func (e *XError) With(key string, value any) *XError
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
```
### <span id="XError_Id">XError_Id</span>
<p>设置XError对象的id。</p>
<b>函数签名:</b>
```go
func (e *XError) Id(id string) *XError
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").Id("e001")
err2 := xerror.New("error").Id("e001")
err3 := xerror.New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
```
### <span id="XError_Is">XError_Is</span>
<p>检查目标error是否为XError两个错误中的error.id是否匹配。</p>
<b>函数签名:</b>
```go
func (e *XError) Is(target error) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err1 := xerror.New("error").Id("e001")
err2 := xerror.New("error").Id("e001")
err3 := xerror.New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
```
### <span id="XError_Values">XError_Values</span>
<p>返回由With设置的键和值的映射。将合并所有XError键和值。</p>
<b>函数签名:</b>
```go
func (e *XError) Values() map[string]any
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
```
### <span id="XError_StackTrace">XError_StackTrace</span>
<p>返回与pkg/error兼容的堆栈信息。</p>
<b>函数签名:</b>
```go
func (e *XError) StackTrace() StackTrace
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error")
stacks := err.Stacks()
fmt.Println(stacks[0].Func)
fmt.Println(stacks[0].Line)
containFile := strings.Contains(stacks[0].File, "xxx.go")
fmt.Println(containFile)
}
```
### <span id="XError_Info">XError_Info</span>
<p>返回可打印的XError对象信息。</p>
<b>函数签名:</b>
```go
func (e *XError) Info() *errInfo
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
cause := errors.New("error")
err := xerror.Wrap(cause, "invalid username").Id("e001").With("level", "high")
errInfo := err.Info()
fmt.Println(errInfo.Id)
fmt.Println(errInfo.Cause)
fmt.Println(errInfo.Values["level"])
fmt.Println(errInfo.Message)
// Output:
// e001
// error
// high
// invalid username
}
```
### <span id="XError_Error">XError_Error</span>
<p>实现标准库的error接口。</p>
<b>函数签名:</b>
```go
func (e *XError) Error() string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
err := xerror.New("error")
fmt.Println(err.Error())
// Output:
// error
}
```
### <span id="TryUnwrap">TryUnwrap</span>
<p>检查error, 如果err为nil则展开则它返回一个有效值如果err不是nil则TryUnwrap使用err发生panic。</p>
<b>函数签名:</b>
```go
func TryUnwrap[T any](val T, err error) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
result1 := xerror.TryUnwrap(strconv.Atoi("42"))
fmt.Println(result1)
_, err := strconv.Atoi("4o2") _, err := strconv.Atoi("4o2")
defer func() { defer func() {
v := recover() v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error() result2 := reflect.DeepEqual(err.Error(), v.(*strconv.NumError).Error())
fmt.Println(result2)
}() }()
xerror.Unwrap(strconv.Atoi("4o2")) xerror.TryUnwrap(strconv.Atoi("4o2"))
// Output:
// 42
// true
} }
``` ```

View File

@@ -19,7 +19,7 @@ func ExampleIsExist() {
} }
func ExampleCreateFile() { func ExampleCreateFile() {
fname := "./test.txt" fname := "./a.txt"
result1 := IsExist(fname) result1 := IsExist(fname)
@@ -175,11 +175,11 @@ func ExampleReadFileByLine() {
} }
func ExampleListFileNames() { func ExampleListFileNames() {
fileList, _ := ListFileNames("./") fileList, _ := ListFileNames("../formatter/")
fmt.Println(fileList) fmt.Println(fileList)
// Output: // Output:
// [file.go file_example_test.go file_test.go] // [formatter.go formatter_example_test.go formatter_test.go]
} }
func ExampleZip() { func ExampleZip() {

View File

@@ -96,16 +96,6 @@ func TestCopyFile(t *testing.T) {
os.Remove(destFile) os.Remove(destFile)
} }
func TestListFileNames(t *testing.T) {
assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("./")
assert.IsNil(err)
expected := []string{"file.go", "file_test.go"}
assert.Equal(expected, filesInPath)
}
func TestReadFileToString(t *testing.T) { func TestReadFileToString(t *testing.T) {
assert := internal.NewAssert(t, "TestReadFileToString") assert := internal.NewAssert(t, "TestReadFileToString")
@@ -241,3 +231,13 @@ func TestMiMeType(t *testing.T) {
assert.Equal("text/plain; charset=utf-8", MiMeType(f)) assert.Equal("text/plain; charset=utf-8", MiMeType(f))
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go")) assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
} }
func TestListFileNames(t *testing.T) {
assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("../formatter/")
assert.IsNil(err)
expected := []string{"formatter.go", "formatter_example_test.go", "formatter_test.go"}
assert.Equal(expected, filesInPath)
}

View File

@@ -47,7 +47,7 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
type CurryFn[T any] func(...T) T type CurryFn[T any] func(...T) T
// New make a curry function for specific value. // New make a curry function for specific value.
// Play: Todo // Play: https://go.dev/play/p/5HopfDwANKX
func (cf CurryFn[T]) New(val T) func(...T) T { func (cf CurryFn[T]) New(val T) func(...T) T {
return func(vals ...T) T { return func(vals ...T) T {
args := append([]T{val}, vals...) args := append([]T{val}, vals...)
@@ -56,7 +56,7 @@ func (cf CurryFn[T]) New(val T) func(...T) T {
} }
// Compose compose the functions from right to left. // Compose compose the functions from right to left.
// Play: Todo // Play: https://go.dev/play/p/KKfugD4PKYF
func Compose[T any](fnList ...func(...T) T) func(...T) T { func Compose[T any](fnList ...func(...T) T) func(...T) T {
return func(args ...T) T { return func(args ...T) T {
firstFn := fnList[0] firstFn := fnList[0]
@@ -145,14 +145,6 @@ func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
return fv.Call(params) return fv.Call(params)
} }
func functionValue(function any) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}
func mustBeFunction(function any) { func mustBeFunction(function any) {
v := reflect.ValueOf(function) v := reflect.ValueOf(function)
if v.Kind() != reflect.Func { if v.Kind() != reflect.Func {

View File

@@ -108,21 +108,21 @@ func ExampleDebounced() {
} }
func ExampleSchedule() { func ExampleSchedule() {
var result []string count := 0
appendFn := func(s string) { increase := func() {
result = append(result, s) count++
} }
stop := Schedule(1*time.Second, appendFn, "*") stop := Schedule(2*time.Second, increase)
time.Sleep(3 * time.Second) time.Sleep(2 * time.Second)
close(stop) close(stop)
fmt.Println(result) fmt.Println(count)
// Output: // Output:
// [* * *] // 2
} }
func ExamplePipeline() { func ExamplePipeline() {

View File

@@ -3,7 +3,7 @@ package function
import "time" import "time"
// Watcher is used for record code excution time // Watcher is used for record code excution time
// Play: Todo // Play: https://go.dev/play/p/l2yrOpCLd1I
type Watcher struct { type Watcher struct {
startTime int64 startTime int64
stopTime int64 stopTime int64

View File

@@ -4,7 +4,11 @@
// Package maputil includes some functions to manipulate map. // Package maputil includes some functions to manipulate map.
package maputil package maputil
import "reflect" import (
"reflect"
"github.com/duke-git/lancet/v2/slice"
)
// Keys returns a slice of the map's keys. // Keys returns a slice of the map's keys.
// Play: https://go.dev/play/p/xNB5bTb97Wd // Play: https://go.dev/play/p/xNB5bTb97Wd
@@ -34,6 +38,30 @@ func Values[K comparable, V any](m map[K]V) []V {
return values return values
} }
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
// Play: todo
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
keys := make([]T, 0, len(m))
for k := range m {
keys = append(keys, mapper(k))
}
return keys
}
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
// Play: todo
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
keys := make([]T, 0, len(m))
for _, v := range m {
keys = append(keys, mapper(v))
}
return keys
}
// Merge maps, next key will overwrite previous key. // Merge maps, next key will overwrite previous key.
// Play: https://go.dev/play/p/H95LENF1uB- // Play: https://go.dev/play/p/H95LENF1uB-
func Merge[K comparable, V any](maps ...map[K]V) map[K]V { func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
@@ -69,6 +97,71 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
return result return result
} }
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
// Play: todo
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
result := make(map[K]V)
for k, v := range m {
if slice.Contain(keys, k) {
result[k] = v
}
}
return result
}
// FilterByValues iterates over map, return a new map whose values are all given values.
// Play: todo
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
result := make(map[K]V)
for k, v := range m {
if slice.Contain(values, v) {
result[k] = v
}
}
return result
}
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
// Play: todo
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
result := make(map[K]V)
for k, v := range m {
if !predicate(k, v) {
result[k] = v
}
}
return result
}
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
// Play: todo
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
result := make(map[K]V)
for k, v := range m {
if !slice.Contain(keys, k) {
result[k] = v
}
}
return result
}
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
// Play: todo
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
result := make(map[K]V)
for k, v := range m {
if !slice.Contain(values, v) {
result[k] = v
}
}
return result
}
// Intersect iterates over maps, return a new map of key and value pairs in all given maps. // Intersect iterates over maps, return a new map of key and value pairs in all given maps.
// Play: https://go.dev/play/p/Zld0oj3sjcC // Play: https://go.dev/play/p/Zld0oj3sjcC
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V { func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
@@ -126,3 +219,73 @@ func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool {
} }
return true return true
} }
// Entry is a key/value pairs.
type Entry[K comparable, V any] struct {
Key K
Value V
}
// Entries transforms a map into array of key/value pairs.
// Play: todo
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
entries := make([]Entry[K, V], 0, len(m))
for k, v := range m {
entries = append(entries, Entry[K, V]{
Key: k,
Value: v,
})
}
return entries
}
// FromEntries creates a map based on a slice of key/value pairs
// Play: todo
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
result := make(map[K]V, len(entries))
for _, v := range entries {
result[v.Key] = v.Value
}
return result
}
// Transform a map to another type map.
// Play: todo
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
result := make(map[K2]V2, len(m))
for k1, v1 := range m {
k2, v2 := iteratee(k1, v1)
result[k2] = v2
}
return result
}
// MapKeys transforms a map to other type map by manipulating it's keys.
// Play: todo
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
result := make(map[T]V, len(m))
for k, v := range m {
result[iteratee(k, v)] = v
}
return result
}
// MapValues transforms a map to other type map by manipulating it's values.
// Play: todo
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
result := make(map[K]T, len(m))
for k, v := range m {
result[k] = iteratee(k, v)
}
return result
}

View File

@@ -3,6 +3,7 @@ package maputil
import ( import (
"fmt" "fmt"
"sort" "sort"
"strconv"
) )
func ExampleKeys() { func ExampleKeys() {
@@ -41,6 +42,51 @@ func ExampleValues() {
// [a a b c d] // [a a b c d]
} }
func ExampleKeysBy() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
}
keys := KeysBy(m, func(n int) int {
return n + 1
})
sort.Ints(keys)
fmt.Println(keys)
// Output:
// [2 3 4]
}
func ExampleValuesBy() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
values := ValuesBy(m, func(v string) string {
switch v {
case "a":
return "a-1"
case "b":
return "b-2"
case "c":
return "c-3"
default:
return ""
}
})
sort.Strings(values)
fmt.Println(values)
// Output:
// [a-1 b-2 c-3]
}
func ExampleMerge() { func ExampleMerge() {
m1 := map[int]string{ m1 := map[int]string{
1: "a", 1: "a",
@@ -99,6 +145,40 @@ func ExampleFilter() {
// map[b:2 d:4] // map[b:2 d:4]
} }
func ExampleFilterByKeys() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := FilterByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[a:1 b:2]
}
func ExampleFilterByValues() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := FilterByValues(m, []int{3, 4})
fmt.Println(result)
// Output:
// map[c:3 d:4]
}
func ExampleIntersect() { func ExampleIntersect() {
m1 := map[string]int{ m1 := map[string]int{
"a": 1, "a": 1,
@@ -179,3 +259,141 @@ func ExampleIsDisjoint() {
// true // true
// false // false
} }
func ExampleEntries() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Entries(m)
sort.Slice(result, func(i, j int) bool {
return result[i].Value < result[j].Value
})
fmt.Println(result)
// Output:
// [{a 1} {b 2} {c 3}]
}
func ExampleFromEntries() {
result := FromEntries([]Entry[string, int]{
{Key: "a", Value: 1},
{Key: "b", Value: 2},
{Key: "c", Value: 3},
})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
func ExampleTransform() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Transform(m, func(k string, v int) (string, string) {
return k, strconv.Itoa(v)
})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}
func ExampleMapKeys() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := MapKeys(m, func(k int, _ string) string {
return strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a 2:b 3:c]
}
func ExampleMapValues() {
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := MapValues(m, func(k int, v string) string {
return v + strconv.Itoa(k)
})
fmt.Println(result)
// Output:
// map[1:a1 2:b2 3:c3]
}
func ExampleOmitBy() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
result := OmitBy(m, isEven)
fmt.Println(result)
// Output:
// map[a:1 c:3 e:5]
}
func ExampleOmitByKeys() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := OmitByKeys(m, []string{"a", "b"})
fmt.Println(result)
// Output:
// map[c:3 d:4 e:5]
}
func ExampleOmitByValues() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
result := OmitByValues(m, []int{4, 5})
fmt.Println(result)
// Output:
// map[a:1 b:2 c:3]
}

View File

@@ -2,6 +2,7 @@ package maputil
import ( import (
"sort" "sort"
"strconv"
"testing" "testing"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
@@ -41,6 +42,51 @@ func TestValues(t *testing.T) {
assert.Equal([]string{"a", "a", "b", "c", "d"}, values) assert.Equal([]string{"a", "a", "b", "c", "d"}, values)
} }
func TestKeysBy(t *testing.T) {
assert := internal.NewAssert(t, "TestKeysBy")
m := map[int]string{
1: "a",
2: "a",
3: "b",
}
keys := KeysBy(m, func(n int) int {
return n + 1
})
sort.Ints(keys)
assert.Equal([]int{2, 3, 4}, keys)
}
func TestValuesBy(t *testing.T) {
assert := internal.NewAssert(t, "TestValuesBy")
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
values := ValuesBy(m, func(v string) string {
switch v {
case "a":
return "a-1"
case "b":
return "b-2"
case "c":
return "c-3"
default:
return ""
}
})
sort.Strings(values)
assert.Equal([]string{"a-1", "b-2", "c-3"}, values)
}
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
assert := internal.NewAssert(t, "TestMerge") assert := internal.NewAssert(t, "TestMerge")
@@ -104,6 +150,107 @@ func TestFilter(t *testing.T) {
}, acturl) }, acturl)
} }
func TestFilterByKeys(t *testing.T) {
assert := internal.NewAssert(t, "TestFilterByKeys")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
acturl := FilterByKeys(m, []string{"a", "b"})
assert.Equal(map[string]int{
"a": 1,
"b": 2,
}, acturl)
}
func TestFilterByValues(t *testing.T) {
assert := internal.NewAssert(t, "TestFilterByValues")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
acturl := FilterByValues(m, []int{3, 4})
assert.Equal(map[string]int{
"c": 3,
"d": 4,
}, acturl)
}
func TestOmitBy(t *testing.T) {
assert := internal.NewAssert(t, "TestOmitBy")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
acturl := OmitBy(m, isEven)
assert.Equal(map[string]int{
"a": 1,
"c": 3,
"e": 5,
}, acturl)
}
func TestOmitByKeys(t *testing.T) {
assert := internal.NewAssert(t, "TestOmitByKeys")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
acturl := OmitByKeys(m, []string{"a", "b"})
assert.Equal(map[string]int{
"c": 3,
"d": 4,
"e": 5,
}, acturl)
}
func TestOmitByValues(t *testing.T) {
assert := internal.NewAssert(t, "TestOmitByValues")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
acturl := OmitByValues(m, []int{4, 5})
assert.Equal(map[string]int{
"a": 1,
"b": 2,
"c": 3,
}, acturl)
}
func TestIntersect(t *testing.T) { func TestIntersect(t *testing.T) {
assert := internal.NewAssert(t, "TestIntersect") assert := internal.NewAssert(t, "TestIntersect")
@@ -170,3 +317,104 @@ func TestIsDisjoint(t *testing.T) {
assert.Equal(false, IsDisjoint(m1, m3)) assert.Equal(false, IsDisjoint(m1, m3))
} }
func TestEntries(t *testing.T) {
assert := internal.NewAssert(t, "TestEntries")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Entries(m)
sort.Slice(result, func(i, j int) bool {
return result[i].Value < result[j].Value
})
expected := []Entry[string, int]{{Key: "a", Value: 1}, {Key: "b", Value: 2}, {Key: "c", Value: 3}}
assert.Equal(expected, result)
}
func TestFromEntries(t *testing.T) {
assert := internal.NewAssert(t, "TestFromEntries")
result := FromEntries([]Entry[string, int]{
{Key: "a", Value: 1},
{Key: "b", Value: 2},
{Key: "c", Value: 3},
})
assert.Equal(3, len(result))
assert.Equal(1, result["a"])
assert.Equal(2, result["b"])
assert.Equal(3, result["c"])
}
func TestTransform(t *testing.T) {
assert := internal.NewAssert(t, "TestTransform")
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
result := Transform(m, func(k string, v int) (string, string) {
return k, strconv.Itoa(v)
})
expected := map[string]string{
"a": "1",
"b": "2",
"c": "3",
}
assert.Equal(expected, result)
}
func TestMapKeys(t *testing.T) {
assert := internal.NewAssert(t, "TestMapKeys")
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := MapKeys(m, func(k int, _ string) string {
return strconv.Itoa(k)
})
expected := map[string]string{
"1": "a",
"2": "b",
"3": "c",
}
assert.Equal(expected, result)
}
func TestMapValues(t *testing.T) {
assert := internal.NewAssert(t, "TestMapKeys")
m := map[int]string{
1: "a",
2: "b",
3: "c",
}
result := MapValues(m, func(k int, v string) string {
return v + strconv.Itoa(k)
})
expected := map[int]string{
1: "a1",
2: "b2",
3: "c3",
}
assert.Equal(expected, result)
}

View File

@@ -55,7 +55,7 @@ func Factorial(x uint) uint {
} }
// Percent calculate the percentage of value to total. // Percent calculate the percentage of value to total.
// Play: Todo // Play: https://go.dev/play/p/QQM9B13coSP
func Percent(val, total float64, n int) float64 { func Percent(val, total float64, n int) float64 {
if total == 0 { if total == 0 {
return float64(0) return float64(0)

View File

@@ -13,40 +13,49 @@
package netutil package netutil
import ( import (
"bytes"
"crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/url"
"reflect"
"regexp"
"sort" "sort"
"strings" "strings"
"time"
"github.com/duke-git/lancet/v2/slice"
) )
//HttpGet send get http request // HttpGet send get http request.
func HttpGet(url string, params ...any) (*http.Response, error) { func HttpGet(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodGet, url, params...) return doHttpRequest(http.MethodGet, url, params...)
} }
//HttpPost send post http request // HttpPost send post http request.
func HttpPost(url string, params ...any) (*http.Response, error) { func HttpPost(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPost, url, params...) return doHttpRequest(http.MethodPost, url, params...)
} }
//HttpPut send put http request // HttpPut send put http request.
func HttpPut(url string, params ...any) (*http.Response, error) { func HttpPut(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPut, url, params...) return doHttpRequest(http.MethodPut, url, params...)
} }
//HttpDelete send delete http request // HttpDelete send delete http request.
func HttpDelete(url string, params ...any) (*http.Response, error) { func HttpDelete(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodDelete, url, params...) return doHttpRequest(http.MethodDelete, url, params...)
} }
// HttpPatch send patch http request // HttpPatch send patch http request.
func HttpPatch(url string, params ...any) (*http.Response, error) { func HttpPatch(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPatch, url, params...) return doHttpRequest(http.MethodPatch, url, params...)
} }
// ParseHttpResponse decode http response to specified interface // ParseHttpResponse decode http response to specified interface.
func ParseHttpResponse(resp *http.Response, obj any) error { func ParseHttpResponse(resp *http.Response, obj any) error {
if resp == nil { if resp == nil {
return errors.New("InvalidResp") return errors.New("InvalidResp")
@@ -55,7 +64,8 @@ func ParseHttpResponse(resp *http.Response, obj any) error {
return json.NewDecoder(resp.Body).Decode(obj) return json.NewDecoder(resp.Body).Decode(obj)
} }
// ConvertMapToQueryString convert map to sorted url query string // ConvertMapToQueryString convert map to sorted url query string.
// Play: https://go.dev/play/p/jnNt_qoSnRi
func ConvertMapToQueryString(param map[string]any) string { func ConvertMapToQueryString(param map[string]any) string {
if param == nil { if param == nil {
return "" return ""
@@ -77,3 +87,220 @@ func ConvertMapToQueryString(param map[string]any) string {
} }
return build.String() return build.String()
} }
// HttpRequest struct is a composed http request
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
// HttpClientConfig contains some configurations for http client
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
// defaultHttpClientConfig defalut client config
var defaultHttpClientConfig = &HttpClientConfig{
Compressed: false,
HandshakeTimeout: 20 * time.Second,
ResponseTimeout: 40 * time.Second,
}
// HttpClient is used for sending http request
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
// NewHttpClient make a HttpClient instance
func NewHttpClient() *HttpClient {
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
DisableCompression: !defaultHttpClientConfig.Compressed,
},
},
Config: *defaultHttpClientConfig,
}
return client
}
// NewHttpClientWithConfig make a HttpClient instance with pass config
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
if config == nil {
config = defaultHttpClientConfig
}
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: config.HandshakeTimeout,
ResponseHeaderTimeout: config.ResponseTimeout,
DisableCompression: !config.Compressed,
},
},
Config: *config,
}
if config.SSLEnabled {
client.TLS = config.TLSConfig
}
return client
}
// SendRequest send http request.
// Play: https://go.dev/play/p/jUSgynekH7G
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) {
err := validateRequest(request)
if err != nil {
return nil, err
}
rawUrl := request.RawURL
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
if err != nil {
return nil, err
}
client.setTLS(rawUrl)
client.setHeader(req, request.Headers)
err = client.setQueryParam(req, rawUrl, request.QueryParams)
if err != nil {
return nil, err
}
if request.FormData != nil {
client.setFormData(req, request.FormData)
}
client.Request = req
resp, err := client.Client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
// DecodeResponse decode response into target object.
// Play: https://go.dev/play/p/jUSgynekH7G
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
if resp == nil {
return errors.New("invalid target param")
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(target)
}
// setTLS set http client transport TLSClientConfig
func (client *HttpClient) setTLS(rawUrl string) {
if strings.HasPrefix(rawUrl, "https") {
if transport, ok := client.Client.Transport.(*http.Transport); ok {
transport.TLSClientConfig = client.TLS
}
}
}
// setHeader set http rquest header
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
if headers == nil {
headers = make(http.Header)
}
if _, ok := headers["Accept"]; !ok {
headers["Accept"] = []string{"*/*"}
}
if _, ok := headers["Accept-Encoding"]; !ok && client.Config.Compressed {
headers["Accept-Encoding"] = []string{"deflate, gzip"}
}
req.Header = headers
}
// setQueryParam set http request query string param
func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryParam url.Values) error {
if queryParam != nil {
if !strings.Contains(reqUrl, "?") {
reqUrl = reqUrl + "?" + queryParam.Encode()
} else {
reqUrl = reqUrl + "&" + queryParam.Encode()
}
u, err := url.Parse(reqUrl)
if err != nil {
return err
}
req.URL = u
}
return nil
}
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
formData := []byte(values.Encode())
req.Body = io.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
}
// validateRequest check if a request has url, and valid method.
func validateRequest(req *HttpRequest) error {
if req.RawURL == "" {
return errors.New("invalid request url")
}
// common HTTP methods
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH",
"HEAD", "CONNECT", "OPTIONS", "TRACE"}
if !slice.Contain(methods, strings.ToUpper(req.Method)) {
return errors.New("invalid request method")
}
return nil
}
// StructToUrlValues convert struct to url valuse,
// only convert the field which is exported and has `json` tag.
// Play: https://go.dev/play/p/pFqMkM40w9z
func StructToUrlValues(targetStruct any) url.Values {
rv := reflect.ValueOf(targetStruct)
rt := reflect.TypeOf(targetStruct)
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
}
result := url.Values{}
fieldNum := rt.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := rt.Field(i).Name
tag := rt.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
}
}
return result
}

View File

@@ -1,232 +0,0 @@
package netutil
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
"regexp"
"strings"
"time"
"github.com/duke-git/lancet/v2/slice"
)
// HttpRequest struct is a composed http request
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
// HttpClientConfig contains some configurations for http client
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
// defaultHttpClientConfig defalut client config
var defaultHttpClientConfig = &HttpClientConfig{
Compressed: false,
HandshakeTimeout: 20 * time.Second,
ResponseTimeout: 40 * time.Second,
}
// HttpClient is used for sending http request
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
// NewHttpClient make a HttpClient instance
func NewHttpClient() *HttpClient {
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
DisableCompression: !defaultHttpClientConfig.Compressed,
},
},
Config: *defaultHttpClientConfig,
}
return client
}
// NewHttpClientWithConfig make a HttpClient instance with pass config
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
if config == nil {
config = defaultHttpClientConfig
}
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: config.HandshakeTimeout,
ResponseHeaderTimeout: config.ResponseTimeout,
DisableCompression: !config.Compressed,
},
},
Config: *config,
}
if config.SSLEnabled {
client.TLS = config.TLSConfig
}
return client
}
// SendRequest send http request
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) {
err := validateRequest(request)
if err != nil {
return nil, err
}
rawUrl := request.RawURL
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
if err != nil {
return nil, err
}
client.setTLS(rawUrl)
client.setHeader(req, request.Headers)
err = client.setQueryParam(req, rawUrl, request.QueryParams)
if err != nil {
return nil, err
}
if request.FormData != nil {
client.setFormData(req, request.FormData)
}
client.Request = req
resp, err := client.Client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
// DecodeResponse decode response into target object
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
if resp == nil {
return errors.New("invalid target param")
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(target)
}
// setTLS set http client transport TLSClientConfig
func (client *HttpClient) setTLS(rawUrl string) {
if strings.HasPrefix(rawUrl, "https") {
if transport, ok := client.Client.Transport.(*http.Transport); ok {
transport.TLSClientConfig = client.TLS
}
}
}
// setHeader set http rquest header
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
if headers == nil {
headers = make(http.Header)
}
if _, ok := headers["Accept"]; !ok {
headers["Accept"] = []string{"*/*"}
}
if _, ok := headers["Accept-Encoding"]; !ok && client.Config.Compressed {
headers["Accept-Encoding"] = []string{"deflate, gzip"}
}
req.Header = headers
}
// setQueryParam set http request query string param
func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryParam url.Values) error {
if queryParam != nil {
if !strings.Contains(reqUrl, "?") {
reqUrl = reqUrl + "?" + queryParam.Encode()
} else {
reqUrl = reqUrl + "&" + queryParam.Encode()
}
u, err := url.Parse(reqUrl)
if err != nil {
return err
}
req.URL = u
}
return nil
}
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
formData := []byte(values.Encode())
req.Body = io.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
}
// validateRequest check if a request has url, and valid method.
func validateRequest(req *HttpRequest) error {
if req.RawURL == "" {
return errors.New("invalid request url")
}
// common HTTP methods
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH",
"HEAD", "CONNECT", "OPTIONS", "TRACE"}
if !slice.Contain(methods, strings.ToUpper(req.Method)) {
return errors.New("invalid request method")
}
return nil
}
// StructToUrlValues convert struct to url valuse,
// only convert the field which is exported and has `json` tag
func StructToUrlValues(targetStruct any) url.Values {
rv := reflect.ValueOf(targetStruct)
rt := reflect.TypeOf(targetStruct)
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
}
result := url.Values{}
fieldNum := rt.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := rt.Field(i).Name
tag := rt.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
}
}
return result
}

View File

@@ -1,98 +0,0 @@
package netutil
import (
"io"
"log"
"net/http"
"net/url"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHttpClient_Get(t *testing.T) {
assert := internal.NewAssert(t, "TestHttpClient_Get")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
t.Log(err)
}
assert.Equal(1, todo.Id)
}
func TestHttpClent_Post(t *testing.T) {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestStructToUrlValues(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToUrlValues")
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 1,
}
todoValues := StructToUrlValues(todoQuery)
assert.Equal("1", todoValues.Get("id"))
assert.Equal("1", todoValues.Get("userId"))
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "GET",
QueryParams: todoValues,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", string(body))
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"log" "log"
"net/http"
"net/url" "net/url"
"testing" "testing"
@@ -156,3 +157,90 @@ func TestParseResponse(t *testing.T) {
} }
t.Log("response: ", toDoResp) t.Log("response: ", toDoResp)
} }
func TestHttpClient_Get(t *testing.T) {
assert := internal.NewAssert(t, "TestHttpClient_Get")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
t.Log(err)
}
assert.Equal(1, todo.Id)
}
func TestHttpClent_Post(t *testing.T) {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestStructToUrlValues(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToUrlValues")
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 1,
}
todoValues := StructToUrlValues(todoQuery)
assert.Equal("1", todoValues.Get("id"))
assert.Equal("1", todoValues.Get("userId"))
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "GET",
QueryParams: todoValues,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", string(body))
}

View File

@@ -9,7 +9,8 @@ import (
"strings" "strings"
) )
// GetInternalIp return internal ipv4 // GetInternalIp return internal ipv4.
// Play: https://go.dev/play/p/5mbu-gFp7ei
func GetInternalIp() string { func GetInternalIp() string {
addr, err := net.InterfaceAddrs() addr, err := net.InterfaceAddrs()
if err != nil { if err != nil {
@@ -26,7 +27,8 @@ func GetInternalIp() string {
return "" return ""
} }
// GetRequestPublicIp return the requested public ip // GetRequestPublicIp return the requested public ip.
// Play: https://go.dev/play/p/kxU-YDc_eBo
func GetRequestPublicIp(req *http.Request) string { func GetRequestPublicIp(req *http.Request) string {
var ip string var ip string
for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") { for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
@@ -47,7 +49,8 @@ func GetRequestPublicIp(req *http.Request) string {
} }
// GetPublicIpInfo return public ip information // GetPublicIpInfo return public ip information
// return the PublicIpInfo struct // return the PublicIpInfo struct.
// Play: https://go.dev/play/p/YDxIfozsRHR
func GetPublicIpInfo() (*PublicIpInfo, error) { func GetPublicIpInfo() (*PublicIpInfo, error) {
resp, err := http.Get("http://ip-api.com/json/") resp, err := http.Get("http://ip-api.com/json/")
if err != nil { if err != nil {
@@ -69,7 +72,8 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
return &ip, nil return &ip, nil
} }
// GetIps return all ipv4 of system // GetIps return all ipv4 of system.
// Play: https://go.dev/play/p/NUFfcEmukx1
func GetIps() []string { func GetIps() []string {
var ips []string var ips []string
@@ -89,7 +93,8 @@ func GetIps() []string {
return ips return ips
} }
// GetMacAddrs get mac address // GetMacAddrs get mac address.
// Play: https://go.dev/play/p/Rq9UUBS_Xp1
func GetMacAddrs() []string { func GetMacAddrs() []string {
var macAddrs []string var macAddrs []string
@@ -125,7 +130,8 @@ type PublicIpInfo struct {
Ip string `json:"query"` Ip string `json:"query"`
} }
// IsPublicIP verify a ip is public or not // IsPublicIP verify a ip is public or not.
// Play: https://go.dev/play/p/nmktSQpJZnn
func IsPublicIP(IP net.IP) bool { func IsPublicIP(IP net.IP) bool {
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() { if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
return false return false
@@ -145,7 +151,8 @@ func IsPublicIP(IP net.IP) bool {
return false return false
} }
// IsInternalIP verify an ip is intranet or not // IsInternalIP verify an ip is intranet or not.
// Play: https://go.dev/play/p/sYGhXbgO4Cb
func IsInternalIP(IP net.IP) bool { func IsInternalIP(IP net.IP) bool {
if IP.IsLoopback() { if IP.IsLoopback() {
return true return true
@@ -159,7 +166,8 @@ func IsInternalIP(IP net.IP) bool {
return false return false
} }
// EncodeUrl encode url // EncodeUrl encode url.
// Play: https://go.dev/play/p/bsZ6BRC4uKI
func EncodeUrl(urlStr string) (string, error) { func EncodeUrl(urlStr string) (string, error) {
URL, err := url.Parse(urlStr) URL, err := url.Parse(urlStr)
if err != nil { if err != nil {

156
netutil/net_example_test.go Normal file
View File

@@ -0,0 +1,156 @@
package netutil
import (
"fmt"
"net"
"net/http"
)
func ExampleGetInternalIp() {
internalIp := GetInternalIp()
result := IsInternalIP(net.ParseIP(internalIp))
fmt.Println(result)
// Output:
// true
}
func ExampleGetPublicIpInfo() {
ipInfo, err := GetPublicIpInfo()
if err != nil {
return
}
result := IsPublicIP(net.ParseIP(ipInfo.Ip))
fmt.Println(result)
// Output:
// true
}
func ExampleGetRequestPublicIp() {
ip := "36.112.24.10"
request := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp := GetRequestPublicIp(&request)
fmt.Println(publicIp)
// Output:
// 36.112.24.10
}
func ExampleIsInternalIP() {
ip1 := IsInternalIP(net.ParseIP("127.0.0.1"))
ip2 := IsInternalIP(net.ParseIP("192.168.0.1"))
ip3 := IsInternalIP(net.ParseIP("36.112.24.10"))
fmt.Println(ip1)
fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// true
// true
// false
}
func ExampleIsPublicIP() {
ip1 := IsPublicIP(net.ParseIP("127.0.0.1"))
ip2 := IsPublicIP(net.ParseIP("192.168.0.1"))
ip3 := IsPublicIP(net.ParseIP("36.112.24.10"))
fmt.Println(ip1)
fmt.Println(ip2)
fmt.Println(ip3)
// Output:
// false
// false
// true
}
func ExampleEncodeUrl() {
urlAddr := "http://www.lancet.com?a=1&b=[2]"
encodedUrl, err := EncodeUrl(urlAddr)
if err != nil {
return
}
fmt.Println(encodedUrl)
// Output:
// http://www.lancet.com?a=1&b=%5B2%5D
}
func ExampleHttpClient_DecodeResponse() {
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
return
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
return
}
fmt.Println(todo.Id)
// Output:
// 1
}
func ExampleStructToUrlValues() {
type TodoQuery struct {
Id int `json:"id"`
Name string `json:"name"`
}
todoQuery := TodoQuery{
Id: 1,
Name: "Test",
}
todoValues := StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("name"))
// Output:
// 1
// Test
}
func ExampleConvertMapToQueryString() {
var m = map[string]any{
"c": 3,
"a": 1,
"b": 2,
}
qs := ConvertMapToQueryString(m)
fmt.Println(qs)
// Output:
// a=1&b=2&c=3
}

View File

@@ -13,12 +13,16 @@ import (
) )
const ( const (
NUMERAL = "0123456789" Numeral = "0123456789"
LOWER_LETTERS = "abcdefghijklmnopqrstuvwxyz" LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
UPPER_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
) )
func init() {
rand.Seed(time.Now().UnixNano())
}
// RandInt generate random int between min and max, maybe min, not be max. // RandInt generate random int between min and max, maybe min, not be max.
// Play: https://go.dev/play/p/pXyyAAI5YxD // Play: https://go.dev/play/p/pXyyAAI5YxD
func RandInt(min, max int) int { func RandInt(min, max int) int {
@@ -28,9 +32,12 @@ func RandInt(min, max int) int {
if max < min { if max < min {
min, max = max, min min, max = max, min
} }
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return r.Intn(max-min) + min // fix: https://github.com/duke-git/lancet/issues/75
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
// return r.Intn(max-min) + min
return rand.Intn(max-min) + min
} }
// RandBytes generate random byte slice. // RandBytes generate random byte slice.
@@ -51,40 +58,42 @@ func RandBytes(length int) []byte {
// RandString generate random string of specified length. // RandString generate random string of specified length.
// Play: https://go.dev/play/p/W2xvRUXA7Mi // Play: https://go.dev/play/p/W2xvRUXA7Mi
func RandString(length int) string { func RandString(length int) string {
return random(LETTERS, length) return random(Letters, length)
} }
// RandUpper generate a random upper case string. // RandUpper generate a random upper case string.
// Play: https://go.dev/play/p/29QfOh0DVuh // Play: https://go.dev/play/p/29QfOh0DVuh
func RandUpper(length int) string { func RandUpper(length int) string {
return random(UPPER_LETTERS, length) return random(UpperLetters, length)
} }
// RandLower generate a random lower case string. // RandLower generate a random lower case string.
// Play: https://go.dev/play/p/XJtZ471cmtI // Play: https://go.dev/play/p/XJtZ471cmtI
func RandLower(length int) string { func RandLower(length int) string {
return random(LOWER_LETTERS, length) return random(LowwerLetters, length)
} }
// RandNumeral generate a random numeral string of specified length. // RandNumeral generate a random numeral string of specified length.
// Play: https://go.dev/play/p/g4JWVpHsJcf // Play: https://go.dev/play/p/g4JWVpHsJcf
func RandNumeral(length int) string { func RandNumeral(length int) string {
return random(NUMERAL, length) return random(Numeral, length)
} }
// RandNumeralOrLetter generate a random numeral or letter string. // RandNumeralOrLetter generate a random numeral or letter string.
// Play: https://go.dev/play/p/19CEQvpx2jD // Play: https://go.dev/play/p/19CEQvpx2jD
func RandNumeralOrLetter(length int) string { func RandNumeralOrLetter(length int) string {
return random(NUMERAL+LETTERS, length) return random(Numeral+Letters, length)
} }
// random generate a random string based on given string range. // random generate a random string based on given string range.
func random(s string, length int) string { func random(s string, length int) string {
b := make([]byte, length) b := make([]byte, length)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
// fix: https://github.com/duke-git/lancet/issues/75
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b { for i := range b {
b[i] = s[r.Int63()%int64(len(s))] b[i] = s[rand.Int63()%int64(len(s))]
} }
return string(b) return string(b)

View File

@@ -6,7 +6,6 @@ import (
) )
func ExampleRandInt() { func ExampleRandInt() {
result := RandInt(1, 10) result := RandInt(1, 10)
if result >= 1 && result < 10 { if result >= 1 && result < 10 {

View File

@@ -6,7 +6,6 @@ package slice
import ( import (
"fmt" "fmt"
"math"
"math/rand" "math/rand"
"reflect" "reflect"
"sort" "sort"
@@ -23,7 +22,7 @@ var (
) )
// Contain check if the target value is in the slice or not. // Contain check if the target value is in the slice or not.
// Play: https://go.dev/play/p/_454yEHcNjf // Play: todo
func Contain[T comparable](slice []T, target T) bool { func Contain[T comparable](slice []T, target T) bool {
for _, item := range slice { for _, item := range slice {
if item == target { if item == target {
@@ -34,6 +33,17 @@ func Contain[T comparable](slice []T, target T) bool {
return false return false
} }
// ContainBy returns true if predicate function return true.
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
for _, item := range slice {
if predicate(item) {
return true
}
}
return false
}
// ContainSubSlice check if the slice contain a given subslice or not. // ContainSubSlice check if the slice contain a given subslice or not.
// Play: https://go.dev/play/p/bcuQ3UT6Sev // Play: https://go.dev/play/p/bcuQ3UT6Sev
func ContainSubSlice[T comparable](slice, subSlice []T) bool { func ContainSubSlice[T comparable](slice, subSlice []T) bool {
@@ -422,6 +432,35 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
return result return result
} }
// FilterMap returns a slice which apply both filtering and mapping to the given slice.
// iteratee callback function should returntwo values:
// 1, mapping result.
// 2, whether the result element should be included or not
// Play: todo
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
result := []U{}
for i, v := range slice {
if a, ok := iteratee(i, v); ok {
result = append(result, a)
}
}
return result
}
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
// Play: todo
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
result := make([]U, 0, len(slice))
for i, v := range slice {
result = append(result, iteratee(i, v)...)
}
return result
}
// Reduce creates an slice of values by running each element of slice thru iteratee function. // Reduce creates an slice of values by running each element of slice thru iteratee function.
// Play: https://go.dev/play/p/_RfXJJWIsIm // Play: https://go.dev/play/p/_RfXJJWIsIm
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T { func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
@@ -559,24 +598,72 @@ func DeleteAt[T any](slice []T, start int, end ...int) []T {
return slice return slice
} }
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0. // Drop drop n elements from the start of a slice.
// Play: https://go.dev/play/p/pJ-d6MUWcvK // Play: https://go.dev/play/p/jnPO2yQsT8H
func Drop[T any](slice []T, n int) []T { func Drop[T any](slice []T, n int) []T {
size := len(slice) size := len(slice)
if size == 0 || n == 0 { if size <= n {
return slice
}
if math.Abs(float64(n)) >= float64(size) {
return []T{} return []T{}
} }
if n < 0 { if n <= 0 {
return slice[0 : size+n] return slice
} }
return slice[n:size] result := make([]T, 0, size-n)
return append(result, slice[n:]...)
}
// DropRight drop n elements from the end of a slice.
// Play: https://go.dev/play/p/8bcXvywZezG
func DropRight[T any](slice []T, n int) []T {
size := len(slice)
if size <= n {
return []T{}
}
if n <= 0 {
return slice
}
result := make([]T, 0, size-n)
return append(result, slice[:size-n]...)
}
// DropWhile drop n elements from the start of a slice while predicate function returns true.
// Play: https://go.dev/play/p/4rt252UV_qs
func DropWhile[T any](slice []T, predicate func(item T) bool) []T {
i := 0
for ; i < len(slice); i++ {
if !predicate(slice[i]) {
break
}
}
result := make([]T, 0, len(slice)-i)
return append(result, slice[i:]...)
}
// DropRightWhile drop n elements from the end of a slice while predicate function returns true.
// Play: https://go.dev/play/p/6wyK3zMY56e
func DropRightWhile[T any](slice []T, predicate func(item T) bool) []T {
i := len(slice) - 1
for ; i >= 0; i-- {
if !predicate(slice[i]) {
break
}
}
result := make([]T, 0, i+1)
return append(result, slice[:i+1]...)
} }
// InsertAt insert the value or other slice into slice at index. // InsertAt insert the value or other slice into slice at index.
@@ -783,6 +870,64 @@ func Shuffle[T any](slice []T) []T {
return slice return slice
} }
// IsAscending checks if a slice is ascending order.
// Play: https://go.dev/play/p/9CtsFjet4SH
func IsAscending[T constraints.Ordered](slice []T) bool {
for i := 1; i < len(slice); i++ {
if slice[i-1] > slice[i] {
return false
}
}
return true
}
// IsDescending checks if a slice is descending order.
// Play: https://go.dev/play/p/U_LljFXma14
func IsDescending[T constraints.Ordered](slice []T) bool {
for i := 1; i < len(slice); i++ {
if slice[i-1] < slice[i] {
return false
}
}
return true
}
// IsSorted checks if a slice is sorted(ascending or descending).
// Play: https://go.dev/play/p/nCE8wPLwSA-
func IsSorted[T constraints.Ordered](slice []T) bool {
return IsAscending(slice) || IsDescending(slice)
}
// IsSortedByKey checks if a slice is sorted by iteratee function.
// Play: https://go.dev/play/p/tUoGB7DOHI4
func IsSortedByKey[T any, K constraints.Ordered](slice []T, iteratee func(item T) K) bool {
size := len(slice)
isAscending := func(data []T) bool {
for i := 0; i < size-1; i++ {
if iteratee(data[i]) > iteratee(data[i+1]) {
return false
}
}
return true
}
isDescending := func(data []T) bool {
for i := 0; i < size-1; i++ {
if iteratee(data[i]) < iteratee(data[i+1]) {
return false
}
}
return true
}
return isAscending(slice) || isDescending(slice)
}
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm. // Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`. // default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`.
// Play: https://go.dev/play/p/V9AVjzf_4Fk // Play: https://go.dev/play/p/V9AVjzf_4Fk

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"math" "math"
"reflect" "reflect"
"strconv"
) )
func ExampleContain() { func ExampleContain() {
@@ -18,6 +19,32 @@ func ExampleContain() {
// false // false
} }
func ExampleContainBy() {
type foo struct {
A string
B int
}
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array2 := []string{"a", "b", "c"}
result3 := ContainBy(array2, func(t string) bool { return t == "a" })
result4 := ContainBy(array2, func(t string) bool { return t == "d" })
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// false
// true
// false
}
func ExampleContainSubSlice() { func ExampleContainSubSlice() {
result1 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"}) result1 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"})
result2 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "d"}) result2 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "d"})
@@ -367,6 +394,38 @@ func ExampleMap() {
// [2 3 4] // [2 3 4]
} }
func ExampleFilterMap() {
nums := []int{1, 2, 3, 4, 5}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
result := FilterMap(nums, getEvenNumStr)
fmt.Printf("%#v", result)
// Output:
// []string{"2", "4"}
}
func ExampleFlatMap() {
nums := []int{1, 2, 3, 4}
result := FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
fmt.Printf("%#v", result)
// Output:
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
}
func ExampleReduce() { func ExampleReduce() {
nums := []int{1, 2, 3} nums := []int{1, 2, 3}
@@ -482,10 +541,74 @@ func ExampleDrop() {
// Output: // Output:
// [a b c] // [a b c]
// [b c] // [b c]
// [a b] // [a b c]
// [] // []
} }
func ExampleDropRight() {
result1 := DropRight([]string{"a", "b", "c"}, 0)
result2 := DropRight([]string{"a", "b", "c"}, 1)
result3 := DropRight([]string{"a", "b", "c"}, -1)
result4 := DropRight([]string{"a", "b", "c"}, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [a b]
// [a b c]
// []
}
func ExampleDropWhile() {
numbers := []int{1, 2, 3, 4, 5}
result1 := DropWhile(numbers, func(n int) bool {
return n != 2
})
result2 := DropWhile(numbers, func(n int) bool {
return true
})
result3 := DropWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [2 3 4 5]
// []
// [1 2 3 4 5]
}
func ExampleDropRightWhile() {
numbers := []int{1, 2, 3, 4, 5}
result1 := DropRightWhile(numbers, func(n int) bool {
return n != 2
})
result2 := DropRightWhile(numbers, func(n int) bool {
return true
})
result3 := DropRightWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [1 2]
// []
// [1 2 3 4 5]
}
func ExampleInsertAt() { func ExampleInsertAt() {
result1 := InsertAt([]string{"a", "b", "c"}, 0, "1") result1 := InsertAt([]string{"a", "b", "c"}, 0, "1")
result2 := InsertAt([]string{"a", "b", "c"}, 1, "1") result2 := InsertAt([]string{"a", "b", "c"}, 1, "1")
@@ -621,6 +744,75 @@ func ExampleReverse() {
// [d c b a] // [d c b a]
} }
func ExampleIsAscending() {
result1 := IsAscending([]int{1, 2, 3, 4, 5})
result2 := IsAscending([]int{5, 4, 3, 2, 1})
result3 := IsAscending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
}
func ExampleIsDescending() {
result1 := IsDescending([]int{5, 4, 3, 2, 1})
result2 := IsDescending([]int{1, 2, 3, 4, 5})
result3 := IsDescending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
}
func ExampleIsSorted() {
result1 := IsSorted([]int{1, 2, 3, 4, 5})
result2 := IsSorted([]int{5, 4, 3, 2, 1})
result3 := IsSorted([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
func ExampleIsSortedByKey() {
result1 := IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
return len(s)
})
result2 := IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
})
result3 := IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
func ExampleSort() { func ExampleSort() {
nums := []int{1, 4, 3, 2, 5} nums := []int{1, 4, 3, 2, 5}

View File

@@ -3,6 +3,7 @@ package slice
import ( import (
"fmt" "fmt"
"math" "math"
"strconv"
"testing" "testing"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
@@ -19,6 +20,28 @@ func TestContain(t *testing.T) {
assert.Equal(true, Contain([]int{1, 2, 3}, 1)) assert.Equal(true, Contain([]int{1, 2, 3}, 1))
} }
func TestContainBy(t *testing.T) {
assert := internal.NewAssert(t, "TestContainBy")
type foo struct {
A string
B int
}
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array2 := []string{"a", "b", "c"}
result3 := ContainBy(array2, func(t string) bool { return t == "a" })
result4 := ContainBy(array2, func(t string) bool { return t == "d" })
assert.Equal(true, result1)
assert.Equal(false, result2)
assert.Equal(true, result3)
assert.Equal(false, result4)
}
func TestContainSubSlice(t *testing.T) { func TestContainSubSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestContainSubSlice") assert := internal.NewAssert(t, "TestContainSubSlice")
assert.Equal(true, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "a"})) assert.Equal(true, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "a"}))
@@ -315,6 +338,36 @@ func TestMap(t *testing.T) {
assert.Equal(studentsOfAdd10Aage, Map(students, mapFunc)) assert.Equal(studentsOfAdd10Aage, Map(students, mapFunc))
} }
func TestFilterMap(t *testing.T) {
assert := internal.NewAssert(t, "TestFilterMap")
nums := []int{1, 2, 3, 4, 5}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
result := FilterMap(nums, getEvenNumStr)
assert.Equal([]string{"2", "4"}, result)
}
func TestFlatMap(t *testing.T) {
assert := internal.NewAssert(t, "TestFlatMap")
nums := []int{1, 2, 3, 4}
result := FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
assert.Equal([]string{"hi-1", "hi-2", "hi-3", "hi-4"}, result)
}
func TestReduce(t *testing.T) { func TestReduce(t *testing.T) {
cases := [][]int{ cases := [][]int{
{}, {},
@@ -377,7 +430,7 @@ func TestDeleteAt(t *testing.T) {
} }
func TestDrop(t *testing.T) { func TestDrop(t *testing.T) {
assert := internal.NewAssert(t, "TestInterfaceSlice") assert := internal.NewAssert(t, "TestDrop")
assert.Equal([]int{}, Drop([]int{}, 0)) assert.Equal([]int{}, Drop([]int{}, 0))
assert.Equal([]int{}, Drop([]int{}, 1)) assert.Equal([]int{}, Drop([]int{}, 1))
@@ -388,9 +441,64 @@ func TestDrop(t *testing.T) {
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5)) assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 5))
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6)) assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, 6))
assert.Equal([]int{1, 2, 3, 4}, Drop([]int{1, 2, 3, 4, 5}, -1)) assert.Equal([]int{1, 2, 3, 4, 5}, Drop([]int{1, 2, 3, 4, 5}, -1))
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6)) }
assert.Equal([]int{}, Drop([]int{1, 2, 3, 4, 5}, -6))
func TestDropRight(t *testing.T) {
assert := internal.NewAssert(t, "TestDropRight")
assert.Equal([]int{}, DropRight([]int{}, 0))
assert.Equal([]int{}, DropRight([]int{}, 1))
assert.Equal([]int{}, DropRight([]int{}, -1))
assert.Equal([]int{1, 2, 3, 4, 5}, DropRight([]int{1, 2, 3, 4, 5}, 0))
assert.Equal([]int{1, 2, 3, 4}, DropRight([]int{1, 2, 3, 4, 5}, 1))
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 5))
assert.Equal([]int{}, DropRight([]int{1, 2, 3, 4, 5}, 6))
assert.Equal([]int{1, 2, 3, 4, 5}, DropRight([]int{1, 2, 3, 4, 5}, -1))
}
func TestDropWhile(t *testing.T) {
assert := internal.NewAssert(t, "TestDropWhile")
numbers := []int{1, 2, 3, 4, 5}
r1 := DropWhile(numbers, func(n int) bool {
return n != 2
})
assert.Equal([]int{2, 3, 4, 5}, r1)
r2 := DropWhile(numbers, func(n int) bool {
return true
})
assert.Equal([]int{}, r2)
r3 := DropWhile(numbers, func(n int) bool {
return n == 0
})
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
}
func TestDropRightWhile(t *testing.T) {
assert := internal.NewAssert(t, "TestDropRightWhile")
numbers := []int{1, 2, 3, 4, 5}
r1 := DropRightWhile(numbers, func(n int) bool {
return n != 2
})
assert.Equal([]int{1, 2}, r1)
r2 := DropRightWhile(numbers, func(n int) bool {
return true
})
assert.Equal([]int{}, r2)
r3 := DropRightWhile(numbers, func(n int) bool {
return n == 0
})
assert.Equal([]int{1, 2, 3, 4, 5}, r3)
} }
func TestInsertAt(t *testing.T) { func TestInsertAt(t *testing.T) {
@@ -548,6 +656,46 @@ func TestDifferenceBy(t *testing.T) {
assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne)) assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne))
} }
func TestIsAscending(t *testing.T) {
assert := internal.NewAssert(t, "TestIsAscending")
assert.Equal(true, IsAscending([]int{1, 2, 3, 4, 5}))
assert.Equal(false, IsAscending([]int{5, 4, 3, 2, 1}))
assert.Equal(false, IsAscending([]int{2, 1, 3, 4, 5}))
}
func TestIsDescending(t *testing.T) {
assert := internal.NewAssert(t, "TestIsDescending")
assert.Equal(true, IsDescending([]int{5, 4, 3, 2, 1}))
assert.Equal(false, IsDescending([]int{1, 2, 3, 4, 5}))
assert.Equal(false, IsDescending([]int{2, 1, 3, 4, 5}))
}
func TestIsSorted(t *testing.T) {
assert := internal.NewAssert(t, "TestIsSorted")
assert.Equal(true, IsSorted([]int{5, 4, 3, 2, 1}))
assert.Equal(true, IsSorted([]int{1, 2, 3, 4, 5}))
assert.Equal(false, IsSorted([]int{2, 1, 3, 4, 5}))
}
func TestIsSortedByKey(t *testing.T) {
assert := internal.NewAssert(t, "TestIsSortedByKey")
assert.Equal(true, IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
return len(s)
}))
assert.Equal(true, IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
}))
assert.Equal(false, IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
}))
}
func TestSort(t *testing.T) { func TestSort(t *testing.T) {
assert := internal.NewAssert(t, "TestSort") assert := internal.NewAssert(t, "TestSort")

364
stream/stream.go Normal file
View File

@@ -0,0 +1,364 @@
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
// Use of this source code is governed by MIT license
// Package stream implements a sequence of elements supporting sequential and parallel aggregate operations.
// this package is an experiment to explore if stream in go can work as the way java does. it's complete, but not
// powerful like other libs
package stream
import (
"bytes"
"encoding/gob"
"github.com/duke-git/lancet/v2/slice"
"golang.org/x/exp/constraints"
)
// A stream should implements methods:
// type StreamI[T any] interface {
// // part methods of Java Stream Specification.
// Distinct() StreamI[T]
// Filter(predicate func(item T) bool) StreamI[T]
// FlatMap(mapper func(item T) StreamI[T]) StreamI[T]
// Map(mapper func(item T) T) StreamI[T]
// Peek(consumer func(item T)) StreamI[T]
// Sorted(less func(a, b T) bool) StreamI[T]
// Max(less func(a, b T) bool) (T, bool)
// Min(less func(a, b T) bool) (T, bool)
// Limit(maxSize int) StreamI[T]
// Skip(n int) StreamI[T]
// AllMatch(predicate func(item T) bool) bool
// AnyMatch(predicate func(item T) bool) bool
// NoneMatch(predicate func(item T) bool) bool
// ForEach(consumer func(item T))
// Reduce(init T, accumulator func(a, b T) T) T
// Count() int
// FindFirst() (T, bool)
// ToSlice() []T
// // part of methods custom extension
// Reverse() StreamI[T]
// Range(start, end int) StreamI[T]
// Concat(streams ...StreamI[T]) StreamI[T]
// }
type stream[T any] struct {
source []T
}
// Of creates a stream stream whose elements are the specified values.
func Of[T any](elems ...T) stream[T] {
return FromSlice(elems)
}
// Generate stream where each element is generated by the provided generater function
// generater function: func() func() (item T, ok bool) {}
func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
source := make([]T, 0)
var zeroValue T
for next, item, ok := generator(), zeroValue, true; ok; {
item, ok = next()
if ok {
source = append(source, item)
}
}
return FromSlice(source)
}
// FromSlice creates stream from slice.
func FromSlice[T any](source []T) stream[T] {
return stream[T]{source: source}
}
// FromChannel creates stream from channel.
func FromChannel[T any](source <-chan T) stream[T] {
s := make([]T, 0)
for v := range source {
s = append(s, v)
}
return FromSlice(s)
}
// FromRange creates a number stream from start to end. both start and end are included. [start, end]
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T] {
if end < start {
panic("stream.FromRange: param start should be before param end")
} else if step <= 0 {
panic("stream.FromRange: param step should be positive")
}
l := int((end-start)/step) + 1
source := make([]T, l, l)
for i := 0; i < l; i++ {
source[i] = start + (T(i) * step)
}
return FromSlice(source)
}
// Concat creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
func Concat[T any](a, b stream[T]) stream[T] {
source := make([]T, 0)
source = append(source, a.source...)
source = append(source, b.source...)
return FromSlice(source)
}
// Distinct returns a stream that removes the duplicated items.
func (s stream[T]) Distinct() stream[T] {
source := make([]T, 0)
distinct := map[string]bool{}
for _, v := range s.source {
// todo: performance issue
k := hashKey(v)
if _, ok := distinct[k]; !ok {
distinct[k] = true
source = append(source, v)
}
}
return FromSlice(source)
}
func hashKey(data any) string {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(data)
if err != nil {
panic("stream.hashKey: get hashkey failed")
}
return buffer.String()
}
// Filter returns a stream consisting of the elements of this stream that match the given predicate.
func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
source := make([]T, 0)
for _, v := range s.source {
if predicate(v) {
source = append(source, v)
}
}
return FromSlice(source)
}
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
source := make([]T, s.Count(), s.Count())
for i, v := range s.source {
source[i] = mapper(v)
}
return FromSlice(source)
}
// Peek returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
func (s stream[T]) Peek(consumer func(item T)) stream[T] {
for _, v := range s.source {
consumer(v)
}
return s
}
// Skip returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
// If this stream contains fewer than n elements then an empty stream will be returned.
func (s stream[T]) Skip(n int) stream[T] {
if n <= 0 {
return s
}
source := make([]T, 0)
l := len(s.source)
if n > l {
return FromSlice(source)
}
for i := n; i < l; i++ {
source = append(source, s.source[i])
}
return FromSlice(source)
}
// Limit returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
func (s stream[T]) Limit(maxSize int) stream[T] {
if s.source == nil {
return s
}
if maxSize < 0 {
return FromSlice([]T{})
}
source := make([]T, 0, maxSize)
for i := 0; i < len(s.source) && i < maxSize; i++ {
source = append(source, s.source[i])
}
return FromSlice(source)
}
// AllMatch returns whether all elements of this stream match the provided predicate.
func (s stream[T]) AllMatch(predicate func(item T) bool) bool {
for _, v := range s.source {
if !predicate(v) {
return false
}
}
return true
}
// AnyMatch returns whether any elements of this stream match the provided predicate.
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool {
for _, v := range s.source {
if predicate(v) {
return true
}
}
return false
}
// NoneMatch returns whether no elements of this stream match the provided predicate.
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool {
return !s.AnyMatch(predicate)
}
// ForEach performs an action for each element of this stream.
func (s stream[T]) ForEach(action func(item T)) {
for _, v := range s.source {
action(v)
}
}
// Reduce performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
func (s stream[T]) Reduce(init T, accumulator func(a, b T) T) T {
for _, v := range s.source {
init = accumulator(init, v)
}
return init
}
// Count returns the count of elements in the stream.
func (s stream[T]) Count() int {
return len(s.source)
}
// FindFirst returns the first element of this stream and true, or zero value and false if the stream is empty.
func (s stream[T]) FindFirst() (T, bool) {
var result T
if s.source == nil || len(s.source) == 0 {
return result, false
}
return s.source[0], true
}
// Reverse returns a stream whose elements are reverse order of given stream.
func (s stream[T]) Reverse() stream[T] {
l := len(s.source)
source := make([]T, l)
for i := 0; i < l; i++ {
source[i] = s.source[l-1-i]
}
return FromSlice(source)
}
// Range returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
func (s stream[T]) Range(start, end int) stream[T] {
if start < 0 {
start = 0
}
if end < 0 {
end = 0
}
if start >= end {
return FromSlice([]T{})
}
source := make([]T, 0)
if end > len(s.source) {
end = len(s.source)
}
for i := start; i < end; i++ {
source = append(source, s.source[i])
}
return FromSlice(source)
}
// Sorted returns a stream consisting of the elements of this stream, sorted according to the provided less function.
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
source := []T{}
source = append(source, s.source...)
slice.SortBy(source, less)
return FromSlice(source)
}
// Max returns the maximum element of this stream according to the provided less function.
// less: a > b
func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
var max T
if len(s.source) == 0 {
return max, false
}
for i, v := range s.source {
if less(v, max) || i == 0 {
max = v
}
}
return max, true
}
// Min returns the minimum element of this stream according to the provided less function.
// less: a < b
func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
var min T
if len(s.source) == 0 {
return min, false
}
for i, v := range s.source {
if less(v, min) || i == 0 {
min = v
}
}
return min, true
}
// ToSlice return the elements in the stream.
func (s stream[T]) ToSlice() []T {
return s.source
}

338
stream/stream_test.go Normal file
View File

@@ -0,0 +1,338 @@
package stream
import (
"fmt"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestOf(t *testing.T) {
assert := internal.NewAssert(t, "TestFromSlice")
stream := Of(1, 2, 3)
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
}
func TestGenerate(t *testing.T) {
assert := internal.NewAssert(t, "TestFromSlice")
n := 0
max := 4
generator := func() func() (int, bool) {
return func() (int, bool) {
n++
return n, n < max
}
}
stream := Generate(generator)
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
}
func TestFromSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestFromSlice")
stream := FromSlice([]int{1, 2, 3})
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
}
func TestFromChannel(t *testing.T) {
assert := internal.NewAssert(t, "TestFromChannel")
ch := make(chan int)
go func() {
for i := 1; i < 4; i++ {
ch <- i
}
close(ch)
}()
stream := FromChannel(ch)
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
}
func TestFromRange(t *testing.T) {
assert := internal.NewAssert(t, "TestFromRange")
s1 := FromRange(1, 5, 1)
s2 := FromRange(1.1, 5.0, 1.0)
assert.Equal([]int{1, 2, 3, 4, 5}, s1.ToSlice())
assert.Equal([]float64{1.1, 2.1, 3.1, 4.1}, s2.ToSlice())
}
func TestStream_Distinct(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Distinct")
nums := FromSlice([]int{1, 2, 2, 3, 3, 3})
distinctNums := nums.Distinct()
assert.Equal([]int{1, 2, 2, 3, 3, 3}, nums.ToSlice())
assert.Equal([]int{1, 2, 3}, distinctNums.ToSlice())
type Person struct {
Id string
Name string
Age uint
}
people := []Person{
{Id: "001", Name: "Tom", Age: 10},
{Id: "001", Name: "Tom", Age: 10},
{Id: "002", Name: "Jim", Age: 20},
{Id: "003", Name: "Mike", Age: 30},
}
stream := FromSlice(people)
distinctStream := stream.Distinct()
// {[{001 Tom 10} {001 Tom 10} {002 Jim 20} {003 Mike 30}]}
t.Log(stream)
// {[{001 Tom 10} {002 Jim 20} {003 Mike 30}]}
t.Log(distinctStream)
}
func TestStream_Filter(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Filter")
stream := FromSlice([]int{1, 2, 3, 4, 5})
isEven := func(n int) bool {
return n%2 == 0
}
even := stream.Filter(isEven)
assert.Equal([]int{2, 4}, even.ToSlice())
}
func TestStream_Map(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Map")
stream := FromSlice([]int{1, 2, 3})
addOne := func(n int) int {
return n + 1
}
s := stream.Map(addOne)
assert.Equal([]int{2, 3, 4}, s.ToSlice())
}
func TestStream_Peek(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Peek")
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
result := []string{}
stream = stream.Filter(func(n int) bool {
return n <= 3
}).Peek(func(n int) {
result = append(result, fmt.Sprint("current: ", n))
})
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
assert.Equal([]string{
"current: 1", "current: 2", "current: 3",
}, result)
}
func TestStream_Skip(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Peek")
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
s1 := stream.Skip(-1)
s2 := stream.Skip(0)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s1.ToSlice())
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s2.ToSlice())
}
func TestStream_Limit(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Limit")
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
s1 := stream.Limit(-1)
s2 := stream.Limit(0)
s3 := stream.Limit(1)
s4 := stream.Limit(6)
assert.Equal([]int{}, s1.ToSlice())
assert.Equal([]int{}, s2.ToSlice())
assert.Equal([]int{1}, s3.ToSlice())
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s4.ToSlice())
}
func TestStream_AllMatch(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_AllMatch")
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
result1 := stream.AllMatch(func(item int) bool {
return item > 0
})
result2 := stream.AllMatch(func(item int) bool {
return item > 1
})
assert.Equal(true, result1)
assert.Equal(false, result2)
}
func TestStream_AnyMatch(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_AnyMatch")
stream := FromSlice([]int{1, 2, 3})
result1 := stream.AnyMatch(func(item int) bool {
return item > 3
})
result2 := stream.AnyMatch(func(item int) bool {
return item > 1
})
assert.Equal(false, result1)
assert.Equal(true, result2)
}
func TestStream_NoneMatch(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_NoneMatch")
stream := FromSlice([]int{1, 2, 3})
result1 := stream.NoneMatch(func(item int) bool {
return item > 3
})
result2 := stream.NoneMatch(func(item int) bool {
return item > 1
})
assert.Equal(true, result1)
assert.Equal(false, result2)
}
func TestStream_ForEach(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_ForEach")
stream := FromSlice([]int{1, 2, 3})
result := 0
stream.ForEach(func(item int) {
result += item
})
assert.Equal(6, result)
}
func TestStream_Reduce(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Reduce")
stream := FromSlice([]int{1, 2, 3})
result := stream.Reduce(0, func(a, b int) int {
return a + b
})
assert.Equal(6, result)
}
func TestStream_FindFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_FindFirst")
stream := FromSlice([]int{1, 2, 3})
result, ok := stream.FindFirst()
assert.Equal(1, result)
assert.Equal(true, ok)
}
func TestStream_Reverse(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Reverse")
s := FromSlice([]int{1, 2, 3})
rs := s.Reverse()
assert.Equal([]int{3, 2, 1}, rs.ToSlice())
}
func TestStream_Range(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Range")
s := FromSlice([]int{1, 2, 3})
s1 := s.Range(-1, 0)
assert.Equal([]int{}, s1.ToSlice())
s2 := s.Range(0, -1)
assert.Equal([]int{}, s2.ToSlice())
s3 := s.Range(0, 0)
assert.Equal([]int{}, s3.ToSlice())
s4 := s.Range(1, 1)
assert.Equal([]int{}, s4.ToSlice())
s5 := s.Range(0, 1)
assert.Equal([]int{1}, s5.ToSlice())
s6 := s.Range(0, 4)
assert.Equal([]int{1, 2, 3}, s6.ToSlice())
}
func TestStream_Concat(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Concat")
s1 := FromSlice([]int{1, 2, 3})
s2 := FromSlice([]int{4, 5, 6})
s := Concat(s1, s2)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s.ToSlice())
}
func TestStream_Sorted(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Sorted")
s := FromSlice([]int{4, 2, 1, 3})
s1 := s.Sorted(func(a, b int) bool { return a < b })
assert.Equal([]int{4, 2, 1, 3}, s.ToSlice())
assert.Equal([]int{1, 2, 3, 4}, s1.ToSlice())
}
func TestStream_Max(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Max")
s := FromSlice([]int{4, 2, 1, 3})
max, ok := s.Max(func(a, b int) bool { return a > b })
assert.Equal(4, max)
assert.Equal(true, ok)
}
func TestStream_Min(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Min")
s := FromSlice([]int{4, 2, 1, 3})
max, ok := s.Max(func(a, b int) bool { return a < b })
assert.Equal(1, max)
assert.Equal(true, ok)
}

View File

@@ -67,44 +67,25 @@ func LowerFirst(s string) string {
return string(r) + s[size:] return string(r) + s[size:]
} }
// PadEnd pads string on the right side if it's shorter than size. // PadStart pads string on the left and right side if it's shorter than size.
// Padding characters are truncated if they exceed size. // Padding characters are truncated if they exceed size.
// Play: https://go.dev/play/p/9xP8rN0vz-- // Play: todo
func PadEnd(source string, size int, padStr string) string { func Pad(source string, size int, padStr string) string {
len1 := len(source) return padAtPosition(source, size, padStr, 0)
len2 := len(padStr)
if len1 >= size {
return source
}
fill := ""
if len2 >= size-len1 {
fill = padStr[0 : size-len1]
} else {
fill = strings.Repeat(padStr, size-len1)
}
return source + fill[0:size-len1]
} }
// PadStart pads string on the left side if it's shorter than size. // PadStart pads string on the left side if it's shorter than size.
// Padding characters are truncated if they exceed size. // Padding characters are truncated if they exceed size.
// Play: https://go.dev/play/p/xpTfzArDfvT // Play: https://go.dev/play/p/xpTfzArDfvT
func PadStart(source string, size int, padStr string) string { func PadStart(source string, size int, padStr string) string {
len1 := len(source) return padAtPosition(source, size, padStr, 1)
len2 := len(padStr) }
if len1 >= size { // PadEnd pads string on the right side if it's shorter than size.
return source // Padding characters are truncated if they exceed size.
} // Play: https://go.dev/play/p/9xP8rN0vz--
func PadEnd(source string, size int, padStr string) string {
fill := "" return padAtPosition(source, size, padStr, 2)
if len2 >= size-len1 {
fill = padStr[0 : size-len1]
} else {
fill = strings.Repeat(padStr, size-len1)
}
return fill[0:size-len1] + source
} }
// KebabCase coverts string to kebab-case, non letters and numbers will be ignored. // KebabCase coverts string to kebab-case, non letters and numbers will be ignored.
@@ -283,7 +264,7 @@ func SplitEx(s, sep string, removeEmptyString bool) []string {
} }
// Substring returns a substring of the specified length starting at the specified offset position. // Substring returns a substring of the specified length starting at the specified offset position.
// Play: Todo // Play: https://go.dev/play/p/q3sM6ehnPDp
func Substring(s string, offset int, length uint) string { func Substring(s string, offset int, length uint) string {
rs := []rune(s) rs := []rune(s)
size := len(rs) size := len(rs)
@@ -306,3 +287,76 @@ func Substring(s string, offset int, length uint) string {
return strings.Replace(str, "\x00", "", -1) return strings.Replace(str, "\x00", "", -1)
} }
// SplitWords splits a string into words, word only contains alphabetic characters.
// Play: todo
func SplitWords(s string) []string {
var word string
var words []string
var r rune
var size, pos int
isWord := false
for len(s) > 0 {
r, size = utf8.DecodeRuneInString(s)
switch {
case isLetter(r):
if !isWord {
isWord = true
word = s
pos = 0
}
case isWord && (r == '\'' || r == '-'):
// is word
default:
if isWord {
isWord = false
words = append(words, word[:pos])
}
}
pos += size
s = s[size:]
}
if isWord {
words = append(words, word[:pos])
}
return words
}
// WordCount return the number of meaningful word, word only contains alphabetic characters.
// Play: todo
func WordCount(s string) int {
var r rune
var size, count int
isWord := false
for len(s) > 0 {
r, size = utf8.DecodeRuneInString(s)
switch {
case isLetter(r):
if !isWord {
isWord = true
count++
}
case isWord && (r == '\'' || r == '-'):
// is word
default:
isWord = false
}
s = s[size:]
}
return count
}

View File

@@ -186,6 +186,33 @@ func ExampleUpperFirst() {
// Bar大 // Bar大
} }
func ExamplePad() {
result1 := Pad("foo", 1, "bar")
result2 := Pad("foo", 2, "bar")
result3 := Pad("foo", 3, "bar")
result4 := Pad("foo", 4, "bar")
result5 := Pad("foo", 5, "bar")
result6 := Pad("foo", 6, "bar")
result7 := Pad("foo", 7, "bar")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// foo
// foo
// foo
// foob
// bfoob
// bfooba
// bafooba
}
func ExamplePadEnd() { func ExamplePadEnd() {
result1 := PadEnd("foo", 1, "bar") result1 := PadEnd("foo", 1, "bar")
result2 := PadEnd("foo", 2, "bar") result2 := PadEnd("foo", 2, "bar")
@@ -361,3 +388,53 @@ func ExampleSubstring() {
// de // de
// 你好 // 你好
} }
func ExampleSplitWords() {
result1 := SplitWords("a word")
result2 := SplitWords("I'am a programmer")
result3 := SplitWords("Bonjour, je suis programmeur")
result4 := SplitWords("a -b-c' 'd'e")
result5 := SplitWords("你好,我是一名码农")
result6 := SplitWords("こんにちは,私はプログラマーです")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// [a word]
// [I'am a programmer]
// [Bonjour je suis programmeur]
// [a b-c' d'e]
// []
// []
}
func ExampleWordCount() {
result1 := WordCount("a word")
result2 := WordCount("I'am a programmer")
result3 := WordCount("Bonjour, je suis programmeur")
result4 := WordCount("a -b-c' 'd'e")
result5 := WordCount("你好,我是一名码农")
result6 := WordCount("こんにちは,私はプログラマーです")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 2
// 3
// 4
// 3
// 0
// 0
}

View File

@@ -98,3 +98,73 @@ func toUpperAll(rs []rune) []rune {
} }
return rs return rs
} }
// padWithPosition pads string
func padAtPosition(str string, length int, padStr string, position int) string {
if len(str) >= length {
return str
}
if padStr == "" {
padStr = " "
}
length = length - len(str)
startPadLen := 0
if position == 0 {
startPadLen = length / 2
} else if position == 1 {
startPadLen = length
}
endPadLen := length - startPadLen
charLen := len(padStr)
leftPad := ""
cur := 0
for cur < startPadLen {
leftPad += string(padStr[cur%charLen])
cur++
}
cur = 0
rightPad := ""
for cur < endPadLen {
rightPad += string(padStr[cur%charLen])
cur++
}
return leftPad + str + rightPad
}
// isLetter checks r is a letter but not CJK character.
func isLetter(r rune) bool {
if !unicode.IsLetter(r) {
return false
}
switch {
// cjk char: /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/
// hiragana and katakana (Japanese only)
case r >= '\u3034' && r < '\u30ff':
return false
// CJK unified ideographs extension A (Chinese, Japanese, and Korean)
case r >= '\u3400' && r < '\u4dbf':
return false
// CJK unified ideographs (Chinese, Japanese, and Korean)
case r >= '\u4e00' && r < '\u9fff':
return false
// CJK compatibility ideographs (Chinese, Japanese, and Korean)
case r >= '\uf900' && r < '\ufaff':
return false
// half-width katakana (Japanese only)
case r >= '\uff66' && r < '\uff9f':
return false
}
return true
}

View File

@@ -168,9 +168,19 @@ func TestLowerFirst(t *testing.T) {
} }
} }
func TestPad(t *testing.T) {
assert := internal.NewAssert(t, "TestPad")
assert.Equal("a ", Pad("a", 2, ""))
assert.Equal("a", Pad("a", 1, "b"))
assert.Equal("ab", Pad("a", 2, "b"))
assert.Equal("mabcdm", Pad("abcd", 6, "m"))
}
func TestPadEnd(t *testing.T) { func TestPadEnd(t *testing.T) {
assert := internal.NewAssert(t, "TestPadEnd") assert := internal.NewAssert(t, "TestPadEnd")
assert.Equal("a ", PadEnd("a", 2, " "))
assert.Equal("a", PadEnd("a", 1, "b")) assert.Equal("a", PadEnd("a", 1, "b"))
assert.Equal("ab", PadEnd("a", 2, "b")) assert.Equal("ab", PadEnd("a", 2, "b"))
assert.Equal("abcdmn", PadEnd("abcd", 6, "mno")) assert.Equal("abcdmn", PadEnd("abcd", 6, "mno"))
@@ -298,3 +308,37 @@ func TestSubstring(t *testing.T) {
assert.Equal("de", Substring("abcde", -2, 3)) assert.Equal("de", Substring("abcde", -2, 3))
assert.Equal("你好", Substring("你好,欢迎你", 0, 2)) assert.Equal("你好", Substring("你好,欢迎你", 0, 2))
} }
func TestSplitWords(t *testing.T) {
assert := internal.NewAssert(t, "TestSplitWords")
cases := map[string][]string{
"a word": {"a", "word"},
"I'am a programmer": {"I'am", "a", "programmer"},
"Bonjour, je suis programmeur": {"Bonjour", "je", "suis", "programmeur"},
"a -b-c' 'd'e": {"a", "b-c'", "d'e"},
"你好,我是一名码农": nil,
"こんにちは,私はプログラマーです": nil,
}
for k, v := range cases {
assert.Equal(v, SplitWords(k))
}
}
func TestWordCount(t *testing.T) {
assert := internal.NewAssert(t, "TestSplitWords")
cases := map[string]int{
"a word": 2, // {"a", "word"},
"I'am a programmer": 3, // {"I'am", "a", "programmer"},
"Bonjour, je suis programmeur": 4, // {"Bonjour", "je", "suis", "programmeur"},
"a -b-c' 'd'e": 3, // {"a", "b-c'", "d'e"},
"你好,我是一名码农": 0, // nil,
"こんにちは,私はプログラマーです": 0, // nil,
}
for k, v := range cases {
assert.Equal(v, WordCount(k))
}
}

View File

@@ -3,10 +3,10 @@ package system
import "fmt" import "fmt"
func ExampleSetOsEnv() { func ExampleSetOsEnv() {
ok := SetOsEnv("foo", "abc") err := SetOsEnv("foo", "abc")
result := GetOsEnv("foo") result := GetOsEnv("foo")
fmt.Println(ok) fmt.Println(err)
fmt.Println(result) fmt.Println(result)
// Output: // Output:
// <nil> // <nil>
@@ -25,14 +25,14 @@ func ExampleGetOsEnv() {
} }
func ExampleRemoveOsEnv() { func ExampleRemoveOsEnv() {
ok1 := SetOsEnv("foo", "abc") err1 := SetOsEnv("foo", "abc")
result1 := GetOsEnv("foo") result1 := GetOsEnv("foo")
ok2 := RemoveOsEnv("foo") err2 := RemoveOsEnv("foo")
result2 := GetOsEnv("foo") result2 := GetOsEnv("foo")
fmt.Println(ok1) fmt.Println(err1)
fmt.Println(ok2) fmt.Println(err2)
fmt.Println(result1) fmt.Println(result1)
fmt.Println(result2) fmt.Println(result2)
@@ -49,9 +49,10 @@ func ExampleCompareOsEnv() {
return return
} }
result1 := CompareOsEnv("foo", "abc") result := CompareOsEnv("foo", "abc")
fmt.Println(result)
fmt.Println(result1)
// Output: // Output:
// true // true
} }

View File

@@ -25,7 +25,7 @@ var (
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`) chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`) chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]") chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}`) chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`) creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`) base64Matcher *regexp.Regexp = regexp.MustCompile(`^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$`)
) )
@@ -281,6 +281,10 @@ func IsZeroValue(value any) bool {
} }
rv := reflect.ValueOf(value) rv := reflect.ValueOf(value)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if !rv.IsValid() { if !rv.IsValid() {
return true return true
} }

View File

@@ -208,6 +208,7 @@ func TestIsChinesePhone(t *testing.T) {
assert.Equal(true, IsChinesePhone("010-32116675")) assert.Equal(true, IsChinesePhone("010-32116675"))
assert.Equal(true, IsChinesePhone("0464-8756213")) assert.Equal(true, IsChinesePhone("0464-8756213"))
assert.Equal(true, IsChinesePhone("0731-82251545")) //长沙晚报电话
assert.Equal(false, IsChinesePhone("123-87562")) assert.Equal(false, IsChinesePhone("123-87562"))
} }

228
xerror/stack.go Normal file
View File

@@ -0,0 +1,228 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
package xerror
import (
"fmt"
"io"
"path"
"runtime"
"strconv"
"strings"
)
// Stack contains function, file and line number info in the stack trace.
type Stack struct {
Func string `json:"func"`
File string `json:"file"`
Line int `json:"line"`
}
// Stacks returns stack trace array generated by pkg/errors
func (e *XError) Stacks() []*Stack {
resp := make([]*Stack, len(*e.stack))
for i, st := range *e.stack {
f := frame(st)
resp[i] = &Stack{
Func: f.name(),
File: f.file(),
Line: f.line(),
}
}
return resp
}
// StackTrace returns stack trace which is compatible with pkg/errors
func (e *XError) StackTrace() StackTrace {
return e.stack.StackTrace()
}
// ---------------------------------------
// Stacktrace part is implemented based on copy of https://github.com/pkg/errors
//
// Copyright (c) 2015, Dave Cheney <dave@cheney.net>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
type frame uintptr
type stack []uintptr
// StackTrace is array of frame. It's exported for compatibility with github.com/pkg/errors
type StackTrace []frame
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// name returns the name of this function, if known.
func (f frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}
// Format of frame formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s function name and path of source file relative to the compile time
// GOPATH separated by \n\t (<funcname>\n\t<path>)
// %+v equivalent to %+s:%d
func (f frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
_, _ = io.WriteString(s, f.name())
_, _ = io.WriteString(s, "\n\t")
_, _ = io.WriteString(s, f.file())
default:
_, _ = io.WriteString(s, path.Base(f.file()))
}
case 'd':
_, _ = io.WriteString(s, strconv.Itoa(f.line()))
case 'n':
_, _ = io.WriteString(s, funcname(f.name()))
case 'v':
f.Format(s, 's')
_, _ = io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// MarshalText formats a stacktrace Frame as a text string. The output is the
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
func (f frame) MarshalText() ([]byte, error) {
name := f.name()
if name == "unknown" {
return []byte(name), nil
}
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
}
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
_, _ = io.WriteString(s, "\n")
f.Format(s, verb)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []frame(st))
default:
st.formatSlice(s, verb)
}
case 's':
st.formatSlice(s, verb)
}
}
// formatSlice will format this StackTrace into the given buffer as a slice of
// Frame, only valid when called with '%s' or '%v'.
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
_, _ = io.WriteString(s, "[")
for i, f := range st {
if i > 0 {
_, _ = io.WriteString(s, " ")
}
f.Format(s, verb)
}
_, _ = io.WriteString(s, "]")
}
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
frames := make([]frame, len(*s))
for i := 0; i < len(frames); i++ {
frames[i] = frame((*s)[i])
}
return frames
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(4, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}

View File

@@ -4,9 +4,202 @@
// Package xerror implements helpers for errors // Package xerror implements helpers for errors
package xerror package xerror
// Unwrap if err is nil then it returns a valid value import (
"errors"
"fmt"
"io"
"strings"
"github.com/duke-git/lancet/v2/random"
)
// XError is to handle error related information.
type XError struct {
id string
message string
stack *stack
cause error
values map[string]any
}
// New creates a new XError with message
func New(format string, args ...any) *XError {
err := newXError()
err.message = fmt.Sprintf(format, args...)
return err
}
// Wrap creates a new XError and add message.
func Wrap(cause error, message ...any) *XError {
err := newXError()
if len(message) > 0 {
var newMsgs []string
for _, m := range message {
newMsgs = append(newMsgs, fmt.Sprintf("%v", m))
}
err.message = strings.Join(newMsgs, " ")
}
err.cause = cause
return err
}
// Unwrap returns unwrapped XError from err by errors.As. If no XError, returns nil
func Unwrap(err error) *XError {
var e *XError
if errors.As(err, &e) {
return e
}
return nil
}
func newXError() *XError {
id, err := random.UUIdV4()
if err != nil {
return nil
}
return &XError{
id: id,
stack: callers(),
values: make(map[string]any),
}
}
func (e *XError) copy(dest *XError) {
dest.message = e.message
dest.id = e.id
dest.cause = e.cause
for k, v := range e.values {
dest.values[k] = v
}
}
// Error implements standard error interface.
func (e *XError) Error() string {
msg := e.message
cause := e.cause
if cause == nil {
return msg
}
msg = fmt.Sprintf("%s: %v", msg, cause.Error())
return msg
}
// Format returns:
// - %v, %s, %q: formatted message
// - %+v: formatted message with stack trace
func (e *XError) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
_, _ = io.WriteString(s, e.Error())
e.stack.Format(s, verb)
return
}
fallthrough
case 's':
_, _ = io.WriteString(s, e.Error())
case 'q':
fmt.Fprintf(s, "%q", e.Error())
}
}
// Wrap creates a new XError and copy message and id to new one.
func (e *XError) Wrap(cause error) *XError {
err := newXError()
e.copy(err)
err.cause = cause
return err
}
// Unwrap compatible with github.com/pkg/errors
func (e *XError) Unwrap() error {
return e.cause
}
// With adds key and value related to the error object
func (e *XError) With(key string, value any) *XError {
e.values[key] = value
return e
}
// Is checks if target error is XError and Error.id of two errors are matched.
func (e *XError) Is(target error) bool {
var err *XError
if errors.As(target, &err) {
if e.id != "" && e.id == err.id {
return true
}
}
return e == target
}
// Id sets id to check equality in XError.Is
func (e *XError) Id(id string) *XError {
e.id = id
return e
}
// Values returns map of key and value that is set by With. All wrapped xerror.XError key and values will be merged.
// Key and values of wrapped error is overwritten by upper xerror.XError.
func (e *XError) Values() map[string]any {
var values map[string]any
if cause := e.Unwrap(); cause != nil {
if err, ok := cause.(*XError); ok {
values = err.Values()
}
}
if values == nil {
values = make(map[string]any)
}
for key, value := range e.values {
values[key] = value
}
return values
}
type errInfo struct {
Message string `json:"message"`
Id string `json:"id"`
StackTrace []*Stack `json:"stacktrace"`
Cause error `json:"cause"`
Values map[string]any `json:"values"`
}
// Info returns information of xerror, which can be printed.
func (e *XError) Info() *errInfo {
errInfo := &errInfo{
Message: e.message,
Id: e.id,
StackTrace: e.Stacks(),
Cause: e.cause,
Values: make(map[string]any),
}
for k, v := range e.values {
errInfo.Values[k] = v
}
return errInfo
}
// TryUnwrap if err is nil then it returns a valid value
// If err is not nil, Unwrap panics with err. // If err is not nil, Unwrap panics with err.
func Unwrap[T any](val T, err error) T { // Play: https://go.dev/play/p/w84d7Mb3Afk
func TryUnwrap[T any](val T, err error) T {
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -0,0 +1,156 @@
package xerror
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)
func ExampleNew() {
err := New("error")
fmt.Println(err.Error())
// Output:
// error
}
func ExampleWrap() {
err := New("wrong password")
wrapErr := Wrap(err, "error")
fmt.Println(wrapErr.Error())
// Output:
// error: wrong password
}
func ExampleXError_Wrap() {
err1 := New("error").With("level", "high")
err2 := err1.Wrap(errors.New("invalid username"))
fmt.Println(err2.Error())
// Output:
// error: invalid username
}
func ExampleXError_Unwrap() {
err1 := New("error").With("level", "high")
err2 := err1.Wrap(errors.New("invalid username"))
err := err2.Unwrap()
fmt.Println(err.Error())
// Output:
// invalid username
}
func ExampleXError_StackTrace() {
err := New("error")
stacks := err.Stacks()
fmt.Println(stacks[0].Func)
fmt.Println(stacks[0].Line)
containFile := strings.Contains(stacks[0].File, "xerror_example_test.go")
fmt.Println(containFile)
// Output:
// github.com/duke-git/lancet/v2/xerror.ExampleXError_StackTrace
// 52
// true
}
func ExampleXError_With() {
err := New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
func ExampleXError_Id() {
err1 := New("error").Id("e001")
err2 := New("error").Id("e001")
err3 := New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
func ExampleXError_Is() {
err1 := New("error").Id("e001")
err2 := New("error").Id("e001")
err3 := New("error").Id("e003")
equal := err1.Is(err2)
notEqual := err1.Is(err3)
fmt.Println(equal)
fmt.Println(notEqual)
// Output:
// true
// false
}
func ExampleXError_Values() {
err := New("error").With("level", "high")
errLevel := err.Values()["level"]
fmt.Println(errLevel)
// Output:
// high
}
func ExampleXError_Info() {
cause := errors.New("error")
err := Wrap(cause, "invalid username").Id("e001").With("level", "high")
errInfo := err.Info()
fmt.Println(errInfo.Id)
fmt.Println(errInfo.Cause)
fmt.Println(errInfo.Values["level"])
fmt.Println(errInfo.Message)
// Output:
// e001
// error
// high
// invalid username
}
func ExampleTryUnwrap() {
result1 := TryUnwrap(strconv.Atoi("42"))
fmt.Println(result1)
_, err := strconv.Atoi("4o2")
defer func() {
v := recover()
result2 := reflect.DeepEqual(err.Error(), v.(*strconv.NumError).Error())
fmt.Println(result2)
}()
TryUnwrap(strconv.Atoi("4o2"))
// Output:
// 42
// true
}

View File

@@ -1,19 +1,21 @@
package xerror package xerror
import ( import (
"errors"
"strconv" "strconv"
"strings"
"testing" "testing"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
) )
func TestUnwrap(t *testing.T) { func TestTryUnwrap(t *testing.T) {
assert := internal.NewAssert(t, "TestUnwrap") assert := internal.NewAssert(t, "TestTryUnwrap")
assert.Equal(42, Unwrap(strconv.Atoi("42"))) assert.Equal(42, TryUnwrap(strconv.Atoi("42")))
} }
func TestUnwrapFail(t *testing.T) { func TestTryUnwrapFail(t *testing.T) {
assert := internal.NewAssert(t, "TestUnwrapFail") assert := internal.NewAssert(t, "TestTryUnwrapFail")
_, err := strconv.Atoi("4o2") _, err := strconv.Atoi("4o2")
defer func() { defer func() {
@@ -21,5 +23,85 @@ func TestUnwrapFail(t *testing.T) {
assert.Equal(err.Error(), v.(*strconv.NumError).Error()) assert.Equal(err.Error(), v.(*strconv.NumError).Error())
}() }()
Unwrap(strconv.Atoi("4o2")) TryUnwrap(strconv.Atoi("4o2"))
}
func TestNew(t *testing.T) {
assert := internal.NewAssert(t, "TestNew")
err := New("error occurs")
assert.Equal("error occurs", err.Error())
}
func TestWrap(t *testing.T) {
assert := internal.NewAssert(t, "TestWrap")
err := New("wrong password")
wrapErr := Wrap(err, "error")
assert.Equal("error: wrong password", wrapErr.Error())
}
func TestXError_Wrap(t *testing.T) {
assert := internal.NewAssert(t, "TestXError_Wrap")
err1 := New("error").With("level", "high")
err2 := err1.Wrap(errors.New("bad"))
assert.Equal("error: bad", err2.Error())
}
func TestXError_Unwrap(t *testing.T) {
assert := internal.NewAssert(t, "TestXError_Unwrap")
err1 := New("error").With("level", "high")
err2 := err1.Wrap(errors.New("bad"))
err := err2.Unwrap()
assert.Equal("bad", err.Error())
}
func TestXError_StackTrace(t *testing.T) {
assert := internal.NewAssert(t, "TestXError_StackTrace")
err := New("error")
stacks := err.Stacks()
assert.Equal(3, len(stacks))
assert.Equal("github.com/duke-git/lancet/v2/xerror.TestXError_StackTrace", stacks[0].Func)
assert.Equal(69, stacks[0].Line)
assert.Equal(true, strings.Contains(stacks[0].File, "xerror_test.go"))
}
func TestXError_With_Id_Is_Values(t *testing.T) {
assert := internal.NewAssert(t, "TestXError_With_Id_Is_Values")
baseErr := New("baseError")
err1 := New("error1").Id("e001").With("level", "high")
err2 := New("error2").Id("e002").With("level", "low")
err := err1.Wrap(baseErr).With("v", "1.0")
assert.Equal(true, errors.Is(err, baseErr))
assert.NotEqual(err, err1)
assert.IsNotNil(err.Values()["v"])
assert.IsNil(err1.Values()["v"])
assert.Equal(false, errors.Is(err, err2))
}
func TestXError_Info(t *testing.T) {
assert := internal.NewAssert(t, "TestXError_Info")
cause := errors.New("error")
err := Wrap(cause, "invalid username").Id("e001").With("level", "high")
errInfo := err.Info()
assert.Equal("invalid username", errInfo.Message)
assert.Equal("e001", errInfo.Id)
assert.Equal(cause, errInfo.Cause)
assert.Equal("high", errInfo.Values["level"])
} }