mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-05 13:22:26 +08:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8120c4db78 | ||
|
|
0d0f213d36 | ||
|
|
41d4bbf0e3 | ||
|
|
fed1d5220e | ||
|
|
29a8318d6e | ||
|
|
3696213e5d | ||
|
|
90a3b87b67 | ||
|
|
a7b28ee864 | ||
|
|
f2823014f2 | ||
|
|
4181c42805 | ||
|
|
a09f5623d6 | ||
|
|
a9c75b081d | ||
|
|
db479ef1bc | ||
|
|
df8121fbbd | ||
|
|
0e7297cb97 | ||
|
|
2e619e48a3 | ||
|
|
3069acba4a | ||
|
|
fc43138a0e | ||
|
|
1e56e9964c | ||
|
|
f861e18bc3 | ||
|
|
e27df00fa8 | ||
|
|
23e61f1acf | ||
|
|
cb308f628c | ||
|
|
7653afa919 | ||
|
|
a0d97cf38e | ||
|
|
1f6bab467c | ||
|
|
2e5b9bc200 | ||
|
|
ab89f0aee1 | ||
|
|
1f64e02df4 | ||
|
|
d4b425e39c | ||
|
|
a1652c7523 | ||
|
|
ecafed511c | ||
|
|
4ffff0e3f3 | ||
|
|
8ebb8a028e | ||
|
|
995ffb799f | ||
|
|
3cd546d7f2 | ||
|
|
7fb49515ce | ||
|
|
8f3ea60636 | ||
|
|
58a37b7e8d | ||
|
|
6bd61460d3 | ||
|
|
05b85a2131 | ||
|
|
1eb793420e | ||
|
|
05f9854945 | ||
|
|
3be706e23f | ||
|
|
b5e7312353 | ||
|
|
95a894e53f | ||
|
|
8322951475 | ||
|
|
6b2c91b0f6 | ||
|
|
ec161f335d | ||
|
|
d1a8f37a71 | ||
|
|
a769257017 | ||
|
|
f3579fc142 | ||
|
|
de877e5278 | ||
|
|
08f14d2b08 | ||
|
|
0ed2b11ba1 | ||
|
|
643edc1468 | ||
|
|
e2ff83649a | ||
|
|
a7fecfc73b | ||
|
|
8bbae69175 | ||
|
|
840ea8f3c5 | ||
|
|
a4e89bd7c1 | ||
|
|
2015d36b08 | ||
|
|
921f218ef7 | ||
|
|
0a2cc9c928 | ||
|
|
ed93aae970 | ||
|
|
1671f7856a | ||
|
|
1008dd4956 | ||
|
|
a254ebdc8e | ||
|
|
0bc11001a4 | ||
|
|
85d98ad915 | ||
|
|
cb08613ac3 | ||
|
|
bad1b05224 | ||
|
|
527328739a | ||
|
|
213e2b4ead |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,7 +8,7 @@ fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
fileutil/tempdir/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
# cryptor/*.pem
|
||||
test
|
||||
docs/node_modules
|
||||
docs/.vitepress/cache
|
||||
|
||||
242
README.md
242
README.md
@@ -4,12 +4,13 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
[](https://codecov.io/gh/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||
[](https://gurubase.io/g/lancet)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
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.4.4. </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.4.6. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
@@ -320,12 +321,19 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
- **<big>ToStdBase64</big>** : converts a value to a string encoded in standard Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToStdBase64)]
|
||||
[[play](https://go.dev/play/p/_fLJqJD3NMo)]
|
||||
- **<big>ToUrlBase64</big>** : converts a value to a string encoded in url Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToUrlBase64)]
|
||||
[[play](https://go.dev/play/p/C_d0GlvEeUR)]
|
||||
- **<big>ToRawStdBase64</big>** : converts a value to a string encoded in raw standard Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawStdBase64)]
|
||||
[[play](https://go.dev/play/p/wSAr3sfkDcv)]
|
||||
- **<big>ToRawUrlBase64</big>** : converts a value to a string encoded in raw url Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawUrlBase64)]
|
||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||
- **<big>ToBigInt</big>** : converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToBigInt)]
|
||||
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
||||
|
||||
<h3 id="cryptor"> 6. Cryptor package is for data encryption and decryption. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -364,10 +372,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>AesGcmEncrypt</big>** : encrypt byte slice data with key use AES GCM algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#AesGcmEncrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>AesGcmDecrypt</big>** : decrypt byte slice data with key use AES GCM algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#AesGcmDecrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>Base64StdEncode</big>** : encode string with base64 encoding.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Base64StdEncode)]
|
||||
[[play](https://go.dev/play/p/VOaUyQUreoK)]
|
||||
@@ -461,10 +469,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||
- **<big>RsaEncrypt</big>** : encrypt data with ras algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaEncrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
[[play](https://go.dev/play/p/7_zo6mrx-eX)]
|
||||
- **<big>RsaDecrypt</big>** : decrypt data with ras algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
[[play](https://go.dev/play/p/7_zo6mrx-eX)]
|
||||
- **<big>GenerateRsaKeyPair</big>** : creates rsa private and public key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
@@ -474,7 +482,12 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- **<big>RsaDecryptOAEP</big>** : decrypts the data with RSA-OAEP
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
- **<big>RsaSign</big>** : signs the data with RSA.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaSign)]
|
||||
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||
- **<big>RsaVerifySign</big>** : verifies the signature of the data with RSA.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaVerifySign)]
|
||||
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||
|
||||
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -493,9 +506,24 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>AddMinute</big>** : add or sub day to the time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMinute)]
|
||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||
- **<big>AddWeek</big>** : add or sub week to time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddWeek)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddMonth</big>** : add or sub months to time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMonth)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddYear</big>** : add or sub year to the time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddYear)]
|
||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||
- **<big>AddDaySafe</big>** : add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddDaySafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddMonthSafe</big>** : add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMonthSafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddYearSafe</big>** : Add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddYearSafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>BeginOfMinute</big>** : return the date time at the begin of minute of specific date.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#BeginOfMinute)]
|
||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||
@@ -611,14 +639,22 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
- **<big>TrackFuncTime</big>** : tracks function execution time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#TrackFuncTime)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QBSEdfXHPTp)]
|
||||
- **<big>DaysBetween</big>** : returns the number of days between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#DaysBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/qD6qGb3TbOy)]
|
||||
- **<big>GenerateDatetimesBetween</big>** : returns a slice of strings between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](todo)]
|
||||
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
- **<big>Min</big>** : returns the earliest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Min)]
|
||||
[[play](https://go.dev/play/p/MCIDvHNOGGb)]
|
||||
- **<big>Max</big>** : returns the latest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Max)]
|
||||
[[play](https://go.dev/play/p/9m6JMk1LB7-)]
|
||||
- **<big>MaxMin</big>** : returns the latest and earliest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#MaxMin)]
|
||||
[[play](https://go.dev/play/p/rbW51cDtM_2)]
|
||||
|
||||
<h3 id="datastructure"> 8. Datastructure package contains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -659,6 +695,45 @@ import optional "github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datastructure/optional.md)]
|
||||
|
||||
|
||||
<h3 id="eventbus"> 9. EventBus is an event bus used for handling events within an application. <a href="#index">Index</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/eventbus"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>NewEventBus</big>** : Create an EventBus instance.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#NewEventBus)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Subscribe</big>** : subscribes to an event with a specific event topic and listener function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Subscribe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Unsubscribe</big>** : unsubscribes from an event with a specific event topic and listener function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Unsubscribe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Publish</big>** : publishes an event with a specific event topic and data payload.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Publish)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ClearListeners</big>** : clears all the listeners.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#ClearListeners)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ClearListenersByTopic</big>** : clears all the listeners by topic.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#ClearListenersByTopic)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetListenersCount</big>** : returns the number of listeners for a specific event topic.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetListenersCount)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetAllListenersCount</big>** : returns the total number of all listeners.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetAllListenersCount)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetEvents</big>** : returns all the events topics.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetEvents)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>SetErrorHandler</big>** : sets the error handler function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#SetErrorHandler)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
@@ -754,6 +829,9 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ParallelChunkRead</big>** : reads the file in parallel and send each chunk of lines to the specified channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ParallelChunkRead)]
|
||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||
- **<big>GetExeOrDllVersion</big>** : Get the version of exe or dll file on windows os.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||
|
||||
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -813,10 +891,10 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Debounce</big>** : creates a debounced version of the provided function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Debounce)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/-dGFrYn_1Zi)]
|
||||
- **<big>Throttle</big>** : creates a throttled version of the provided function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Throttle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/HpoMov-tJSN)]
|
||||
- **<big>Schedule</big>** : invoke function every duration time, util close the returned bool channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
@@ -937,58 +1015,58 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewOrderedMap</big>** : creates a new OrderedMap.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewOrderedMap)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Set</big>** : sets the given key-value pair for ordered map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Set)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Get</big>** : returns the value for the given key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Get)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Delete</big>** : deletes the key-value pair for the given key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Delete)]
|
||||
[[play](todo)]
|
||||
[[play](ttps://go.dev/play/p/5bIi4yaZ3K-)]
|
||||
- **<big>OrderedMap_Clear</big>** : clears the ordered map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Clear)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8LwoJyEfuFr)]
|
||||
- **<big>OrderedMap_Front</big>** : returns the first key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Front)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/ty57XSimpoe)]
|
||||
- **<big>OrderedMap_Back</big>** : returns the last key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Back)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rQMjp1yQmpa)]
|
||||
- **<big>OrderedMap_Range</big>** : calls the given function for each key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Range)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/U-KpORhc7LZ)]
|
||||
- **<big>OrderedMap_Keys</big>** : returns the keys in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Keys)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Vv_y9ExKclA)]
|
||||
- **<big>OrderedMap_Values</big>** : returns the values in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Values)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/TWj5n1-PUfx)]
|
||||
- **<big>OrderedMap_Elements</big>** : returns the key-value pairs in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Elements)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/4BHG4kKz6bB)]
|
||||
- **<big>OrderedMap_Len</big>** : returns the number of key-value pairs.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Len)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cLe6z2VX5N-)]
|
||||
- **<big>OrderedMap_Contains</big>** : returns true if the given key exists.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Contains)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QuwqqnzwDNX)]
|
||||
- **<big>OrderedMap_Iter</big>** : returns a channel that yields key-value pairs in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Iter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/tlq2tdvicPt)]
|
||||
- **<big>OrderedMap_ReverseIter</big>** : returns a channel that yields key-value pairs in reverse order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_ReverseIter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8Q0ssg6hZzO)]
|
||||
- **<big>OrderedMap_SortByKey</big>** : sorts the map by key given less function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/N7hjD_alZPq)]
|
||||
- **<big>OrderedMap_MarshalJSON</big>** : implements the json.Marshaler interface.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_MarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/C-wAwydIAC7)]
|
||||
- **<big>OrderedMap_UnmarshalJSON</big>** : implements the json.Unmarshaler interface.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_UnmarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>NewConcurrentMap</big>** : creates a ConcurrentMap with specific shard count.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1015,10 +1093,10 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
- **<big>SortByKey</big>** : sorts the map by its keys and returns a new map with sorted keys.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/PVdmBSnm6P_W)]
|
||||
- **<big>GetOrDefault</big>** : returns the value of the given key or a default value if the key is not present.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#GetOrDefault)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
||||
|
||||
|
||||
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</a></h3>
|
||||
@@ -1119,7 +1197,18 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- **<big>Div</big>** : returns the result of x divided by y.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Div)]
|
||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||
|
||||
- **<big>Variance</big>** : returns the variance of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Variance)]
|
||||
[[play](https://go.dev/play/p/uHuV4YgXf8F)]
|
||||
- **<big>StdDev</big>** : returns the standard deviation of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#StdDev)]
|
||||
[[play](https://go.dev/play/p/FkNZDXvHD2l)]
|
||||
- **<big>Permutation</big>** : calculates P(n, k).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Permutation)]
|
||||
[[play](https://go.dev/play/p/MgobwH_FOxj)]
|
||||
- **<big>Combination</big>** : calculates C(n, k).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Combination)]
|
||||
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
|
||||
|
||||
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1264,23 +1353,25 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[play](https://go.dev/play/p/I3yndUQ-rhh)]
|
||||
- **<big>RandStringSlice</big>** : generate a slice of random string of length strLen based on charset.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandStringSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/2_-PiDv3tGn)]
|
||||
- **<big>RandBool</big>** : generate a random boolean value (true or false).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandBool)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/to6BLc26wBv)]
|
||||
- **<big>RandBoolSlice</big>** : generate a random boolean slice of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandBoolSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/o-VSjPjnILI)]
|
||||
- **<big>RandIntSlice</big>** : generate a slice of random int. Number range in [min, max)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandIntSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/GATTQ5xTEG8)]
|
||||
- **<big>RandFromGivenSlice</big>** : generate a random element from given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/UrkWueF6yYo)]
|
||||
- **<big>RandSliceFromGivenSlice</big>** : generate a random slice of length num from given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
- **<big>RandNumberOfLength</big>** : generates a random int number of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandNumberOfLength)]
|
||||
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
|
||||
|
||||
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1386,6 +1477,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>EqualWith</big>** : checks if two slices are equal with comparator func.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>EqualUnordered</big>** : Checks if two slices are equal: the same length and all elements value are equal (unordered).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#EqualUnordered)]
|
||||
[[play](todo)]
|
||||
- **<big>Every</big>** : return true if all of the values in the slice pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
@@ -1424,7 +1518,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||
- **<big>ForEachConcurrent</big>** : applies the iteratee function to each item in the slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ForEachConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/kT4XW7DKVoV)]
|
||||
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#GroupBy)]
|
||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||
@@ -1454,7 +1548,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>MapConcurrent</big>** : applies the iteratee function to each item in the slice by concrrent.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#MapConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/H1ehfPkPen0)]
|
||||
- **<big>Merge</big>** : merge all given slices into one slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
@@ -1472,7 +1566,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qT9dZC03A1K)]
|
||||
- **<big>ReduceConcurrent</big>** : reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ReduceConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Tjwe6OtaG07)]
|
||||
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
@@ -1485,6 +1579,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Shuffle</big>** : shuffle the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Shuffle)]
|
||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||
- **<big>ShuffleCopy</big>** : return a new slice with elements shuffled.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ShuffleCopy)]
|
||||
[[play](todo)]
|
||||
- **<big>IsAscending</big>** : Checks if a slice is ascending order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#IsAscending)]
|
||||
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
||||
@@ -1526,16 +1623,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : remove duplicate elements from the input slice based on the values returned by the iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
[[play](https://go.dev/play/p/GY7JE4yikrl)]
|
||||
- **<big>UniqueByComparator</big>** : remove duplicate elements from the input slice using the provided comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByComparator)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rwSacr-ZHsR)]
|
||||
- **<big>UniqueByField</big>** : remove duplicate elements in struct slice by struct field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByField)]
|
||||
[[play](https://go.dev/play/p/6cifcZSPIGu)]
|
||||
- **<big>UniqueByConcurrent</big>** : remove duplicate elements from the slice by concurrent.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/wXZ7LcYRMGL)]
|
||||
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
@@ -1573,8 +1670,13 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
- **<big>Frequency</big>** : counts the frequency of each element in the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Frequency)]
|
||||
[[play](todo)]
|
||||
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
- **<big>JoinFunc</big>** : joins the slice elements into a single string with the given separator.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#JoinFunc)]
|
||||
[[play](https://go.dev/play/p/55ib3SB5fM2)]
|
||||
- **<big>ConcatBy</big>** : concats the elements of a slice into a single value using the provided separator and connector function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ConcatBy)]
|
||||
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
|
||||
|
||||
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1610,7 +1712,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>FilterConcurrent</big>** : Applies the provided filter function `predicate` to each element of the input slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FilterConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>Map</big>** : returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
@@ -1626,6 +1728,9 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>Reverse</big>** : returns a stream whose elements are reverse order of given stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/A8_zkJnLHm4)]
|
||||
- **<big>ReverseCopy</big>** : returns a new slice of element order is reversed to the given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#ReverseCopy)]
|
||||
[[play](todo)]
|
||||
- **<big>Range</big>** : returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Range)]
|
||||
[[play](https://go.dev/play/p/indZY5V2f4j)]
|
||||
@@ -1665,6 +1770,12 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>ToSlice</big>** : returns the elements in the stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
- **<big>IndexOf</big>** : returns the index of the first occurrence of the specified element in this stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/tBV5Nc-XDX2)]
|
||||
- **<big>LastIndexOf</big>** : returns the index of the last occurrence of the specified element in this stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
|
||||
|
||||
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1830,18 +1941,27 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/glNdQEA9HUi)]
|
||||
- **<big>Concat</big>** : concatenates strings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Concat)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/gD52SZHr4Kp)]
|
||||
- **<big>Ellipsis</big>** : truncates a string to a specified length and appends an ellipsis.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Ellipsis)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/i1vbdQiQVRR)]
|
||||
- **<big>Shuffle</big>** : shuffle the order of characters of given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Shuffle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/iStFwBwyGY7)]
|
||||
- **<big>Rotate</big>** : rotates the string by the specified number of characters.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Rotate)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Kf03iOeT5bd)]
|
||||
- **<big>TemplateReplace</big>** : replaces the placeholders in the template string with the corresponding values in the data map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#TemplateReplace)]
|
||||
[[play](https://go.dev/play/p/cXSuFvyZqv9)]
|
||||
- **<big>RegexMatchAllGroups</big>** : matches all subgroups in a string using a regular expression and returns the result.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
- **<big>ExtractContent</big>** : extracts the content between the start and end strings in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#ExtractContent)]
|
||||
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||
- **<big>FindAllOccurrences</big>** : Returns the positions of all occurrences of a substring in a string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#FindAllOccurrences)]
|
||||
[[play](todo)]
|
||||
|
||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||
@@ -1881,16 +2001,16 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
- **<big>StartProcess</big>** : start a new process with the specified name and arguments.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#StartProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/5GVol6ryS_X)]
|
||||
- **<big>StopProcess</big>** : stop a process by pid.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#StopProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/jJZhRYGGcmD)]
|
||||
- **<big>KillProcess</big>** : kill a new process with the specified name and arguments.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#KillProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/XKmvV-ExBWa)]
|
||||
- **<big>GetProcessInfo</big>** : retrieves detailed process information by pid.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#GetProcessInfo)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||
|
||||
|
||||
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
||||
@@ -2096,6 +2216,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsIpV6</big>** : check if the string is ipv6.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsIpPort</big>** : check if the string is ip:port.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsIpPort)]
|
||||
[[play](todo)]
|
||||
- **<big>IsStrongPassword</big>** : check if the string is strong password.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
@@ -2192,6 +2315,9 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
- **<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/en/api/packages/xerror.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
- **<big>TryCatch</big>** : simple simulation of Java-style try-catch.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/xerror.md#TryCatch)]
|
||||
[[play](https://go.dev/play/p/D5Mdb0mRj0P)]
|
||||
|
||||
## How to Contribute
|
||||
|
||||
|
||||
313
README_zh-CN.md
313
README_zh-CN.md
@@ -4,12 +4,13 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
[](https://codecov.io/gh/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||
[](https://gurubase.io/g/lancet)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -37,7 +38,7 @@
|
||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.4。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.6。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
@@ -320,13 +321,19 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
- **<big>ToStdBase64</big>** : 将值转换为StdBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToStdBase64)]
|
||||
[[play](https://go.dev/play/p/_fLJqJD3NMo)]
|
||||
- **<big>ToUrlBase64</big>** : 将值转换为url Base64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToUrlBase64)]
|
||||
[[play](https://go.dev/play/p/C_d0GlvEeUR)]
|
||||
- **<big>ToRawStdBase64</big>** : 将值转换为RawStdBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawStdBase64)]
|
||||
[[play](https://go.dev/play/p/wSAr3sfkDcv)]
|
||||
- **<big>ToRawUrlBase64</big>** : 将值转换为RawUrlBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawUrlBase64)]
|
||||
|
||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||
- **<big>ToBigInt</big>** : 将整数转为*big.Int。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
||||
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
||||
|
||||
<h3 id="cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -365,10 +372,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>AesGcmEncrypt</big>** : 使用 AES GCM 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesGcmEncrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>AesGcmDecrypt</big>** : 使用 AES GCM 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesGcmDecrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>Base64StdEncode</big>** : 将字符串 base64 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Base64StdEncode)]
|
||||
[[play](https://go.dev/play/p/VOaUyQUreoK)]
|
||||
@@ -463,10 +470,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||
- **<big>RsaEncrypt</big>** : 用公钥文件 ras 加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaEncrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
[[play](https://go.dev/play/p/7_zo6mrx-eX)]
|
||||
- **<big>RsaDecrypt</big>** : 用私钥文件 rsa 解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
[[play](https://go.dev/play/p/7_zo6mrx-eX)]
|
||||
- **<big>GenerateRsaKeyPair</big>** : 创建rsa公钥私钥和key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
@@ -476,7 +483,12 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- **<big>RsaDecryptOAEP</big>** : rsa OAEP解密。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
- **<big>RsaSign</big>** : 应用RSA算法签名数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaSign)]
|
||||
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||
- **<big>RsaVerifySign</big>** : 验证数据的签名是否符合RSA算法。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaVerifySign)]
|
||||
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||
|
||||
<h3 id="datetime"> 7. datetime日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -495,9 +507,24 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>AddMinute</big>** : 将日期加/减分钟数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMinute)]
|
||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||
- **<big>AddWeek</big>** : 将日期加/减星期数.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddWeek)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddMonth</big>** : 将日期加/减月数.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMonth)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddYear</big>** : 将日期加/减分年数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddYear)]
|
||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||
- **<big>AddDaySafe</big>** : 增加/减少指定的天数,并确保日期是有效日期。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddDaySafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddMonthSafe</big>** : 增加/减少指定的月份,并确保日期是有效日期。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMonthSafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>AddYearSafe</big>** : 增加/减少指定的年份,并确保日期是有效日期。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddYearSafe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>BeginOfMinute</big>** : 返回指定时间的分钟开始时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#BeginOfMinute)]
|
||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||
@@ -614,13 +641,22 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
- **<big>TrackFuncTime</big>** : 测试函数执行时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#TrackFuncTime)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QBSEdfXHPTp)]
|
||||
- **<big>DaysBetween</big>** : 返回两个日期之间的天数差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#DaysBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/qD6qGb3TbOy)]
|
||||
- **<big>GenerateDatetimesBetween</big>** : 生成从start到end的所有日期时间的字符串列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
- **<big>Min</big>** : 返回最早时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Min)]
|
||||
[[play](https://go.dev/play/p/MCIDvHNOGGb)]
|
||||
- **<big>Max</big>** : 返回最晚时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Max)]
|
||||
[[play](https://go.dev/play/p/9m6JMk1LB7-)]
|
||||
- **<big>MaxMin</big>** : 返回最早和最晚时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
||||
[[play](https://go.dev/play/p/rbW51cDtM_2)]
|
||||
|
||||
|
||||
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||
@@ -658,7 +694,46 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- **<big>Hashmap</big>** : 哈希映射。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datastructure/hashmap.md)]
|
||||
|
||||
<h3 id="fileutil"> 9. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="eventbus"> 9. EventbBus是一个事件总线,用于在应用程序中处理事件。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/eventbus"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>NewEventBus</big>** : 创建EventBus实例。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#NewEventBus)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Subscribe</big>** : 订阅具有特定事件主题和监听函数的事件。支持异步,事件优先级,事件过滤器。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Subscribe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Unsubscribe</big>** : 取消订阅具有特定事件主题的事件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Unsubscribe)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Publish</big>** : 发布一个带有特定事件主题和数据负载的事件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Publish)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ClearListeners</big>** : 清空所有事件监听器。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#ClearListeners)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ClearListenersByTopic</big>** : 清空特定事件监听器。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#ClearListenersByTopic)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetListenersCount</big>** : 获取特定事件的监听器数量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetListenersCount)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetAllListenersCount</big>** : 获取所有事件的监听器数量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetAllListenersCount)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>GetEvents</big>** : 获取所有事件的topic。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetEvents)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>SetErrorHandler</big>** : 设置事件的错误处理函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#SetErrorHandler)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="fileutil"> 10. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -753,10 +828,12 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ParallelChunkRead</big>** : 并行读取文件并将每个块的行发送到指定通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ParallelChunkRead)]
|
||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||
- **<big>GetExeOrDllVersion</big>** : 返回exe,dll文件版本号(仅Window平台)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||
|
||||
|
||||
|
||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="formatter"> 11. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -786,7 +863,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/formatter.md#ParseBinaryBytes)]
|
||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||
|
||||
<h3 id="function"> 11. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="function"> 12. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -814,10 +891,10 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Debounce</big>** : 创建一个函数的去抖动版本。该去抖动函数仅在上次调用后的指定延迟时间过去之后才会调用原始函数。支持取消去抖动。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Debounce)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/-dGFrYn_1Zi)]
|
||||
- **<big>Throttle</big>** : 创建一个函数的节流版本。返回的函数保证在每个时间间隔内最多只会被调用一次。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Throttle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/HpoMov-tJSN)]
|
||||
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的 channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
@@ -851,7 +928,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
|
||||
|
||||
<h3 id="maputil"> 12. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="maputil"> 13. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -939,58 +1016,58 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewOrderedMap</big>** : 创建有序映射。有序映射是键值对的集合,其中键是唯一的,并且保留键插入的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewOrderedMap)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Set</big>** : 设置给定的键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Set)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Get</big>** : 返回给定键的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Get)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Delete</big>** : 删除给定键的键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Delete)]
|
||||
[[play](todo)]
|
||||
[[play](ttps://go.dev/play/p/5bIi4yaZ3K-)]
|
||||
- **<big>OrderedMap_Clear</big>** : 清空map数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Clear)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8LwoJyEfuFr)]
|
||||
- **<big>OrderedMap_Front</big>** : 返回第一个键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Front)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/ty57XSimpoe)]
|
||||
- **<big>OrderedMap_Back</big>** : 返回最后一个键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Back)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rQMjp1yQmpa)]
|
||||
- **<big>OrderedMap_Range</big>** : 为每个键值对调用给定的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Range)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/U-KpORhc7LZ)]
|
||||
- **<big>OrderedMap_Keys</big>** : 按顺序返回键的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Keys)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Vv_y9ExKclA)]
|
||||
- **<big>OrderedMap_Values</big>** : 按顺序返回值的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Values)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/TWj5n1-PUfx)]
|
||||
- **<big>OrderedMap_Elements</big>** : 按顺序返回键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Elements)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/4BHG4kKz6bB)]
|
||||
- **<big>OrderedMap_Len</big>** : 返回键值对的数量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Len)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cLe6z2VX5N-)]
|
||||
- **<big>OrderedMap_Contains</big>** : 如果给定的键存在则返回true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Contains)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QuwqqnzwDNX)]
|
||||
- **<big>OrderedMap_Iter</big>** : 返回按顺序产生键值对的通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Iter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/tlq2tdvicPt)]
|
||||
- **<big>OrderedMap_ReverseIter</big>** : 返回以相反顺序产生键值对的通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_ReverseIter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8Q0ssg6hZzO)]
|
||||
- **<big>OrderedMap_SortByKey</big>** : 使用传入的比较函数排序map key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/N7hjD_alZPq)]
|
||||
- **<big>OrderedMap_MarshalJSON</big>** : 实现json.Marshaler接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_MarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/C-wAwydIAC7)]
|
||||
- **<big>OrderedMap_UnmarshalJSON</big>** : 实现json.Unmarshaler接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_UnmarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8C3MvJ3-mut)]
|
||||
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1017,12 +1094,12 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
- **<big>SortByKey</big>** : 对传入的map根据key进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/PVdmBSnm6P_W)]
|
||||
- **<big>GetOrDefault</big>** : 返回给定键的值,如果键不存在,则返回默认值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#GetOrDefault)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
||||
|
||||
<h3 id="mathutil"> 13. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -1120,9 +1197,20 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- **<big>Div</big>** : 除法运算。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Div)]
|
||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||
- **<big>Variance</big>** : 计算方差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Variance)]
|
||||
[[play](https://go.dev/play/p/uHuV4YgXf8F)]
|
||||
- **<big>StdDev</big>** : 计算标准差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#StdDev)]
|
||||
[[play](https://go.dev/play/p/FkNZDXvHD2l)]
|
||||
- **<big>Permutation</big>** : 计算排列数P(n, k)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Permutation)]
|
||||
[[play](https://go.dev/play/p/MgobwH_FOxj)]
|
||||
- **<big>Combination</big>** : 计算组合数C(n, k)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
||||
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
|
||||
|
||||
|
||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="netutil"> 15. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -1195,7 +1283,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#IsTelnetConnected)]
|
||||
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
|
||||
|
||||
<h3 id="pointer"> 15. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/pointer"
|
||||
@@ -1219,7 +1307,7 @@ import "github.com/duke-git/lancet/v2/pointer"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/pointer.md#UnwrapOrDefault)]
|
||||
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
|
||||
|
||||
<h3 id="random"> 16. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="random"> 17. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -1265,25 +1353,27 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
- **<big>RandStringSlice</big>** : 生成随机字符串slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandStringSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/2_-PiDv3tGn)]
|
||||
- **<big>RandBool</big>** : 生成随机bool值(true or false)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandBool)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/to6BLc26wBv)]
|
||||
- **<big>RandBoolSlice</big>** : 生成特定长度的随机bool slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandBoolSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/o-VSjPjnILI)]
|
||||
- **<big>RandIntSlice</big>** : 生成一个特定长度的随机int切片,数值范围[min, max)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandIntSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/GATTQ5xTEG8)]
|
||||
- **<big>RandFromGivenSlice</big>** : 从给定切片中随机生成元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/UrkWueF6yYo)]
|
||||
- **<big>RandSliceFromGivenSlice</big>** : 从给定切片中生成长度为 num 的随机切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
- **<big>RandNumberOfLength</big>** : 生成指定长度的随机数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
||||
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
|
||||
|
||||
|
||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="retry"> 18. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -1300,7 +1390,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
- **<big>RetryFunc</big>** : 重试执行的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryFunc)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认5。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
- **<big>BackoffStrategy</big>** : 定义计算退避间隔的方法的接口。
|
||||
@@ -1317,7 +1407,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
|
||||
|
||||
|
||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="slice"> 19. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -1385,6 +1475,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数 comparator,返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>EqualUnordered</big>** : 检查两个切片是否相等,元素数量相同,值相等,不考虑元素顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#EqualUnordered)]
|
||||
[[play](todo)]
|
||||
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
@@ -1420,7 +1513,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>ForEachConcurrent</big>** : 对slice并发执行foreach操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ForEachConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/kT4XW7DKVoV)]
|
||||
- **<big>ForEachWithBreak</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数,当 iteratee 函数返回 false 时,终止遍历。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ForEachWithBreak)]
|
||||
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||
@@ -1453,13 +1546,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>MapConcurrent</big>** : 对slice并发执行map操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#MapConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/H1ehfPkPen0)]
|
||||
- **<big>Merge</big>** : 合并多个切片(不会消除重复元素)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
- **<big>Reverse</big>** : 反转切片中的元素顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
||||
- **<big>ReverseCopy</big>** : 反转切片中的元素顺序, 不改变原slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#ReverseCopy)]
|
||||
[[play](todo)]
|
||||
- **<big>Reduce<sup>deprecated</sup></big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。(废弃:建议使用 ReduceBy)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
@@ -1471,7 +1567,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qT9dZC03A1K)]
|
||||
- **<big>ReduceConcurrent</big>** : 对切片元素执行并发reduce操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ReduceConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Tjwe6OtaG07)]
|
||||
- **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
@@ -1484,6 +1580,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Shuffle)]
|
||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||
- **<big>ShuffleCopy</big>** : 随机打乱切片中的元素顺序, 不改变原切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ShuffleCopy)]
|
||||
[[play](todo)]
|
||||
- **<big>IsAscending</big>** : 检查切片元素是否按升序排列。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#IsAscending)]
|
||||
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
||||
@@ -1525,16 +1624,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : 根据迭代函数返回的值,从输入切片中移除重复元素。此函数保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
[[play](https://go.dev/play/p/GY7JE4yikrl)]
|
||||
- **<big>UniqueByComparator</big>** : 使用提供的比较器函数从输入切片中移除重复元素。此函数保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByComparator)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rwSacr-ZHsR)]
|
||||
- **<big>UniqueByField</big>** : 根据struct字段对struct切片去重复。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByField)]
|
||||
[[play](https://go.dev/play/p/6cifcZSPIGu)]
|
||||
- **<big>UniqueByConcurrent</big>** : 并发的从输入切片中移除重复元素,结果保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/wXZ7LcYRMGL)]
|
||||
- **<big>Union</big>** : 合并多个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
@@ -1571,10 +1670,15 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
- **<big>Frequency</big>** : 计算切片中每个元素出现的频率。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Frequency)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
- **<big>JoinFunc</big>** : 将切片元素用给定的分隔符连接成一个单一的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#JoinFunc)]
|
||||
[[play](https://go.dev/play/p/55ib3SB5fM2)]
|
||||
- **<big>ConcatBy</big>** : 将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
||||
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
|
||||
|
||||
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="stream"> 20. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
@@ -1608,7 +1712,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>FilterConcurrent</big>** : 对slice并发执行filter操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#FilterConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>Map</big>** : 返回一个 stream,该 stream 由将给定函数应用于源 stream 元素的元素组成。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
@@ -1663,9 +1767,14 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>ToSlice</big>** : 返回 stream 中的元素切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
- **<big>IndexOf</big>** : 返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/tBV5Nc-XDX2)]
|
||||
- **<big>LastIndexOf</big>** : 返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
|
||||
|
||||
|
||||
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="structs"> 21. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/structs"
|
||||
@@ -1702,7 +1811,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
- **<big>IsTargetType</big>** : 判断属性是否是目标类型。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsTargetType)]
|
||||
|
||||
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="strutil"> 22. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1832,21 +1941,31 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/glNdQEA9HUi)]
|
||||
- **<big>Concat</big>** : 拼接字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Concat)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/gD52SZHr4Kp)]
|
||||
- **<big>Ellipsis</big>** : 将字符串截断到指定长度,并在末尾添加省略号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Ellipsis)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/i1vbdQiQVRR)]
|
||||
- **<big>Shuffle</big>** : 打乱给定字符串中的字符顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Shuffle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/iStFwBwyGY7)]
|
||||
- **<big>Rotate</big>** : 按指定的字符数旋转字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Rotate)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Kf03iOeT5bd)]
|
||||
- **<big>TemplateReplace</big>** : 将模板字符串中的占位符替换为map中的相应值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#TemplateReplace)]
|
||||
[[play](https://go.dev/play/p/cXSuFvyZqv9)]
|
||||
- **<big>RegexMatchAllGroups</big>** : 使用正则表达式匹配字符串中的所有子组并返回结果。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
||||
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||
- **<big>FindAllOccurrences</big>** : 返回子字符串在字符串中所有出现的位置。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#FindAllOccurrences)]
|
||||
[[play](todo)]
|
||||
|
||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
<h3 id="system"> 23. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1883,20 +2002,20 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
- **<big>StartProcess</big>** :创建进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#StartProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/5GVol6ryS_X)]
|
||||
- **<big>StopProcess</big>** : 停止进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#StopProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/jJZhRYGGcmD)]
|
||||
- **<big>KillProcess</big>** : 杀掉进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#KillProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/XKmvV-ExBWa)]
|
||||
- **<big>GetProcessInfo</big>** : 根据进程id获取进程信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#GetProcessInfo)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||
|
||||
|
||||
|
||||
<h3 id="tuple"> 23. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="tuple"> 24. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/tuple"
|
||||
@@ -2013,7 +2132,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/tuple.md#Unzip10)]
|
||||
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
|
||||
|
||||
<h3 id="validator"> 24. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="validator"> 25. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -2057,7 +2176,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsCreditCard</big>** : 验证字符串是否是信用卡号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效 dns。
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效dns。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
|
||||
@@ -2093,12 +2212,15 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsIp</big>** : 验证字符串是否是 ip 地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是 ipv4 地址。
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是ipv4地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是 ipv6 地址。
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsIpPort</big>** : 检查字符串是否是ip:port格式。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpPort)]
|
||||
[[play](todo)]
|
||||
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
@@ -2111,10 +2233,10 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsZeroValue</big>** : 判断传入的参数值是否为零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk(汉字内部代码扩展规范)。
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为gbk(汉字内部代码扩展规范)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsGBK)]
|
||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||
- **<big>IsASCII</big>** : 验证字符串全部为 ASCII 字符。
|
||||
- **<big>IsASCII</big>** : 验证字符串全部为ASCII字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsASCII)]
|
||||
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
|
||||
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
|
||||
@@ -2129,13 +2251,13 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsBase64URL</big>** : 检查字符串是否是有效的 base64 url。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsBase64URL)]
|
||||
[[play](https://go.dev/play/p/vhl4mr8GZ6S)]
|
||||
- **<big>IsJWT</big>** : 检查字符串是否是有效的 JSON Web Token (JWT)。
|
||||
- **<big>IsJWT</big>** : 检查字符串是否是有效的JSON Web Token (JWT)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsJWT)]
|
||||
[[play](https://go.dev/play/p/R6Op7heJbKI)]
|
||||
- **<big>IsVisa</big>** : 检查字符串是否是有效的 visa 卡号。
|
||||
- **<big>IsVisa</big>** : 检查字符串是否是有效的visa卡号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsVisa)]
|
||||
[[play](https://go.dev/play/p/SdS2keOyJsl)]
|
||||
- **<big>IsMasterCard</big>** : 检查字符串是否是有效的 MasterCard 卡号。
|
||||
- **<big>IsMasterCard</big>** : 检查字符串是否是有效的MasterCard卡号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsMasterCard)]
|
||||
[[play](https://go.dev/play/p/CwWBFRrG27b)]
|
||||
- **<big>IsAmericanExpress</big>** : 检查字符串是否是有效的 American Express 卡号。
|
||||
@@ -2148,7 +2270,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsChinaUnionPay)]
|
||||
[[play](https://go.dev/play/p/yafpdxLiymu)]
|
||||
|
||||
<h3 id="xerror"> 25. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
||||
<h3 id="xerror"> 26. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
@@ -2171,30 +2293,33 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
- **<big>XError_Unwrap</big>** : 解构 XEerror 为 error 对象。适配 github.com/pkg/errors。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Unwrap)
|
||||
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
|
||||
- **<big>XError_With</big>** : 添加与 XError 对象的键和值。
|
||||
- **<big>XError_With</big>** : 添加与XError对象的键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_With)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_Id</big>** : 设置 XError 对象的 id。
|
||||
- **<big>XError_Id</big>** : 设置XError对象的id。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Id)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Is</big>** : 检查目标 error 是否为 XError,两个错误中的 error.id 是否匹配。
|
||||
- **<big>XError_Is</big>** : 检查目标error是否为XError,两个错误中的error.id是否匹配。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Is)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Values</big>** : 返回由 With 设置的键和值的映射。将合并所有 XError 键和值。
|
||||
- **<big>XError_Values</big>** : 返回由With设置的键和值的映射。将合并所有XError键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Values)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_StackTrace</big>** : 返回与 pkg/error 兼容的堆栈信息。
|
||||
- **<big>XError_StackTrace</big>** : 返回与pkg/error兼容的堆栈信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_StackTrace)]
|
||||
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
|
||||
- **<big>XError_Info</big>** : 返回可打印的 XError 对象信息。
|
||||
- **<big>XError_Info</big>** : 返回可打印的XError对象信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Info)]
|
||||
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
|
||||
- **<big>XError_Error</big>** : 实现标准库的 error 接口。
|
||||
- **<big>XError_Error</big>** : 实现标准库的error接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Error)]
|
||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||
- **<big>TryUnwrap</big>** : 检查 error, 如果 err 为 nil 则展开,则它返回一个有效值,如果 err 不是 nil 则 Unwrap 使用 err 发生 panic。
|
||||
- **<big>TryUnwrap</big>** : 检查error, 如果err为nil则展开,则它返回一个有效值,如果err不是nil则Unwrap使用err发生panic。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
- **<big>TryCatch</big>** : 简单实现的java风格异常处理(try-catch-finally)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryCatch)]
|
||||
[[play](https://go.dev/play/p/D5Mdb0mRj0P)]
|
||||
|
||||
## 如何贡献代码
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
return node.value, true
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
}
|
||||
} else {
|
||||
node.value = value
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
}
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
l.length = len(l.cache)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
|
||||
return node.key
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
|
||||
func (l *LRUCache[K, V]) moveToTail(node *lruNode[K, V]) {
|
||||
if l.tail == node {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
assert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
@@ -16,19 +16,19 @@ func TestLRUCache(t *testing.T) {
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
asssert.Equal(3, cache.Len())
|
||||
assert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(1, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(1, v)
|
||||
|
||||
v, ok = cache.Get(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, v)
|
||||
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -8,34 +8,34 @@ import (
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
assert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
assert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
assert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
assert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
assert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
|
||||
func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
assert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -62,23 +62,23 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
assert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
asssert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
}
|
||||
|
||||
func TestInsertionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestInsertionSort")
|
||||
assert := internal.NewAssert(t, "TestInsertionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -93,12 +93,12 @@ func TestInsertionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestSelectionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestSelectionSort")
|
||||
assert := internal.NewAssert(t, "TestSelectionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -113,12 +113,12 @@ func TestSelectionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestShellSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestShellSort")
|
||||
assert := internal.NewAssert(t, "TestShellSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -133,12 +133,12 @@ func TestShellSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestQuickSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestQuickSort")
|
||||
assert := internal.NewAssert(t, "TestQuickSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -153,12 +153,12 @@ func TestQuickSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestHeapSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestHeapSort")
|
||||
assert := internal.NewAssert(t, "TestHeapSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -173,12 +173,12 @@ func TestHeapSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestMergeSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestMergeSort")
|
||||
assert := internal.NewAssert(t, "TestMergeSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -193,12 +193,12 @@ func TestMergeSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestCountSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestCountSort")
|
||||
assert := internal.NewAssert(t, "TestCountSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -213,5 +213,5 @@ func TestCountSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", sortedPeopleByAge)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package compare
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
@@ -24,6 +25,13 @@ func compareValue(operator string, left, right any) bool {
|
||||
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
return compareRefValue(operator, left, right, leftType.Kind())
|
||||
|
||||
case reflect.Ptr:
|
||||
if leftVal, ok := left.(*big.Int); ok {
|
||||
if rightVal, ok := right.(*big.Int); ok {
|
||||
return compareBigInt(operator, leftVal, rightVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -155,169 +163,129 @@ func compareBasicValue(operator string, leftValue, rightValue any) bool {
|
||||
}
|
||||
|
||||
switch leftVal := leftValue.(type) {
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
left, err := convertor.ToBigInt(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareBigInt(operator, left, right)
|
||||
|
||||
case float32, float64:
|
||||
left, err := convertor.ToFloat(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
case string:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case string:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return compareStrings(operator, left, right)
|
||||
}
|
||||
|
||||
case bool:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case bool:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return compareBools(operator, left, right)
|
||||
}
|
||||
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
return compareFloats(operator, left, right)
|
||||
}
|
||||
case float32, float64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
left, err := convertor.ToBigInt(left)
|
||||
return compareBigInt(operator, left, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBigInt compares two big.Int values based on the operator
|
||||
func compareBigInt(operator string, left, right *big.Int) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left.Cmp(right) == 0
|
||||
case lessThan:
|
||||
return left.Cmp(right) < 0
|
||||
case greaterThan:
|
||||
return left.Cmp(right) > 0
|
||||
case lessOrEqual:
|
||||
return left.Cmp(right) <= 0
|
||||
case greaterOrEqual:
|
||||
return left.Cmp(right) >= 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareFloats compares two float64 values based on the operator
|
||||
func compareFloats(operator string, left, right float64) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareStrings compares two string values based on the operator
|
||||
func compareStrings(operator string, left, right string) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBools compares two boolean values based on the operator
|
||||
func compareBools(operator string, left, right bool) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package compare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -12,213 +13,191 @@ func TestEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEqual")
|
||||
|
||||
// basic type
|
||||
assert.Equal(true, Equal(1, 1))
|
||||
assert.Equal(true, Equal(int64(1), int64(1)))
|
||||
assert.Equal(true, Equal("a", "a"))
|
||||
assert.Equal(true, Equal(true, true))
|
||||
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
|
||||
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
|
||||
|
||||
assert.Equal(false, Equal(1, 2))
|
||||
assert.Equal(false, Equal(1, int64(1)))
|
||||
assert.Equal(false, Equal("a", "b"))
|
||||
assert.Equal(false, Equal(true, false))
|
||||
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
|
||||
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
|
||||
|
||||
// time
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
time3 := time1.Add(time.Second)
|
||||
|
||||
assert.Equal(false, Equal(time1, time2))
|
||||
assert.Equal(true, Equal(time2, time3))
|
||||
|
||||
// struct
|
||||
st1 := struct {
|
||||
A string
|
||||
B string
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), false},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}, false},
|
||||
// {time.Now(), time.Now(), true},
|
||||
// {time.Now(), time.Now().Add(time.Second), false},
|
||||
{[]byte("hello"), []byte("hello"), true},
|
||||
{[]byte("hello"), []byte("world"), false},
|
||||
{json.Number("123"), json.Number("123"), true},
|
||||
{json.Number("123"), json.Number("124"), false},
|
||||
|
||||
{big.NewInt(123), big.NewInt(123), true},
|
||||
}
|
||||
|
||||
st2 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Equal(tt.left, tt.right))
|
||||
}
|
||||
|
||||
st3 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a1",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
assert.Equal(true, Equal(st1, st2))
|
||||
assert.Equal(false, Equal(st1, st3))
|
||||
|
||||
//byte slice
|
||||
bs1 := []byte("hello")
|
||||
bs2 := []byte("hello")
|
||||
assert.Equal(true, Equal(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, Equal(jsonNumber1, jsonNumber2))
|
||||
|
||||
}
|
||||
|
||||
func TestEqualValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEqualValue")
|
||||
|
||||
assert.Equal(true, EqualValue(1, 1))
|
||||
assert.Equal(true, EqualValue(int(1), int64(1)))
|
||||
assert.Equal(true, EqualValue(1, "1"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), true},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
}
|
||||
|
||||
assert.Equal(false, EqualValue(1, "2"))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, EqualValue(jsonNumber1, 123))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, EqualValue(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestLessThan")
|
||||
|
||||
assert.Equal(true, LessThan(1, 2))
|
||||
assert.Equal(true, LessThan(1.1, 2.2))
|
||||
assert.Equal(true, LessThan("a", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessThan(time1, time2))
|
||||
|
||||
assert.Equal(false, LessThan(1, 1))
|
||||
assert.Equal(false, LessThan(1, int64(1)))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, LessThan(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, LessThan(jsonNumber1, jsonNumber2))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessThan(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterThan(2, 1))
|
||||
assert.Equal(true, GreaterThan(2.2, 1.1))
|
||||
assert.Equal(true, GreaterThan("b", "a"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "a", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterThan(time2, time1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterThan(tt.left, tt.right))
|
||||
}
|
||||
|
||||
assert.Equal(false, GreaterThan(1, 2))
|
||||
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||
assert.Equal(false, GreaterThan("b", "c"))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, GreaterThan(bs2, bs1))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, GreaterThan(jsonNumber2, jsonNumber1))
|
||||
}
|
||||
|
||||
func TestLessOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestLessOrEqual")
|
||||
|
||||
assert.Equal(true, LessOrEqual(1, 2))
|
||||
assert.Equal(true, LessOrEqual(1, 1))
|
||||
assert.Equal(true, LessOrEqual(1.1, 2.2))
|
||||
assert.Equal(true, LessOrEqual("a", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1, 1, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{2, 1, false},
|
||||
{1, int64(2), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessOrEqual(time1, time2))
|
||||
|
||||
assert.Equal(false, LessOrEqual(2, 1))
|
||||
assert.Equal(false, LessOrEqual(1, int64(2)))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, LessOrEqual(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, LessOrEqual(jsonNumber1, jsonNumber2))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(2, 1))
|
||||
assert.Equal(true, GreaterOrEqual(1, 1))
|
||||
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
|
||||
assert.Equal(true, GreaterOrEqual("b", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{1, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "b", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 2, false},
|
||||
{int64(2), 1, false},
|
||||
{"b", "c", false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterOrEqual(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterOrEqual(1, 2))
|
||||
assert.Equal(false, GreaterOrEqual(int64(2), 1))
|
||||
assert.Equal(false, GreaterOrEqual("b", "c"))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, GreaterOrEqual(bs2, bs1))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(jsonNumber2, jsonNumber1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInDelta(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestInDelta")
|
||||
|
||||
assert.Equal(true, InDelta(1, 1, 0))
|
||||
assert.Equal(false, InDelta(1, 2, 0))
|
||||
tests := []struct {
|
||||
left float64
|
||||
right float64
|
||||
delta float64
|
||||
want bool
|
||||
}{
|
||||
{1, 1, 0, true},
|
||||
{1, 2, 0, false},
|
||||
{2.0 / 3.0, 0.66667, 0.001, true},
|
||||
{2.0 / 3.0, 0.0, 0.001, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 0, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 1e-14, true},
|
||||
{float64(float32(80.45)), float64(80.45), 0, false},
|
||||
{float64(float32(80.45)), float64(80.45), 1e-5, true},
|
||||
}
|
||||
|
||||
assert.Equal(true, InDelta(2.0/3.0, 0.66667, 0.001))
|
||||
assert.Equal(false, InDelta(2.0/3.0, 0.0, 0.001))
|
||||
|
||||
assert.Equal(false, InDelta(float64(74.96)-float64(20.48), 54.48, 0))
|
||||
assert.Equal(true, InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14))
|
||||
assert.Equal(false, InDelta(float64(float32(80.45)), float64(80.45), 0))
|
||||
assert.Equal(true, InDelta(float64(float32(80.45)), float64(80.45), 1e-5))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, InDelta(tt.left, tt.right, tt.delta))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,10 +157,10 @@ func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
// Play: https://go.dev/play/p/qmWSy1NVF-Y
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
defer wg.Wait()
|
||||
for {
|
||||
var stream <-chan T
|
||||
select {
|
||||
@@ -169,19 +169,22 @@ func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-c
|
||||
return
|
||||
}
|
||||
stream = maybeStream
|
||||
wg.Add(1)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
for val := range c.OrDone(ctx, stream) {
|
||||
select {
|
||||
case valStream <- val:
|
||||
case <-ctx.Done():
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for val := range c.OrDone(ctx, stream) {
|
||||
select {
|
||||
case valStream <- val:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
return valStream
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,8 @@ func ExampleChannel_Tee() {
|
||||
func ExampleChannel_Bridge() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
m1 := make(map[int]int)
|
||||
m2 := make(map[int]int)
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
@@ -177,6 +178,7 @@ func ExampleChannel_Bridge() {
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
m1[i]++
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
@@ -185,12 +187,15 @@ func ExampleChannel_Bridge() {
|
||||
}
|
||||
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
m2[v]++
|
||||
}
|
||||
for k, v := range m1 {
|
||||
fmt.Println(m2[k] == v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -169,7 +169,8 @@ func TestTee(t *testing.T) {
|
||||
func TestBridge(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestBridge")
|
||||
|
||||
m1 := make(map[int]int)
|
||||
m2 := make(map[int]int)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@@ -181,6 +182,7 @@ func TestBridge(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
m1[i]++
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
@@ -188,9 +190,11 @@ func TestBridge(t *testing.T) {
|
||||
return chanStream
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
assert.Equal(index, val)
|
||||
index++
|
||||
m2[val]++
|
||||
}
|
||||
|
||||
for k, v := range m1 {
|
||||
assert.Equal(m2[k], v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +72,17 @@ func Nand[T, U any](a T, b U) bool {
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
} else {
|
||||
return elseValue
|
||||
}
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
// Deprecated: Use Ternary instead.
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
return Ternary(isTrue, ifValue, elseValue)
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ func ExampleNand() {
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
func ExampleTernary() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
result1 := Ternary(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
result2 := Ternary(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
|
||||
@@ -124,13 +124,13 @@ func TestNand(t *testing.T) {
|
||||
assert.Equal(false, Nand(1, 1))
|
||||
}
|
||||
|
||||
func TestTernaryOperator(t *testing.T) {
|
||||
func TestTernary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TernaryOperator")
|
||||
assert := internal.NewAssert(t, "TestTernary")
|
||||
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
|
||||
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
|
||||
assert.Equal(trueValue, Ternary(true, trueValue, falseValue))
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -74,7 +75,7 @@ func ToBytes(value any) ([]byte, error) {
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
c := make([]string, 0, len(s))
|
||||
if len(s) == 0 {
|
||||
c = append(c, "")
|
||||
}
|
||||
@@ -107,6 +108,13 @@ func ToString(value any) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
rv := reflect.ValueOf(value)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
return ""
|
||||
}
|
||||
return ToString(rv.Elem().Interface())
|
||||
}
|
||||
|
||||
switch val := value.(type) {
|
||||
case float32:
|
||||
@@ -142,12 +150,8 @@ func ToString(value any) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
|
||||
// todo: maybe we should't supprt other type conversion
|
||||
// v := reflect.ValueOf(value)
|
||||
// log.Panicf("Unsupported data type: %s ", v.String())
|
||||
// return ""
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,3 +487,36 @@ func ToRawUrlBase64(value any) string {
|
||||
return base64.RawURLEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToBigInt converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int
|
||||
// Play: https://go.dev/play/p/X3itkCxwB_x
|
||||
func ToBigInt[T any](v T) (*big.Int, error) {
|
||||
result := new(big.Int)
|
||||
|
||||
switch v := any(v).(type) {
|
||||
case int:
|
||||
result.SetInt64(int64(v)) // Convert to int64 for big.Int
|
||||
case int8:
|
||||
result.SetInt64(int64(v))
|
||||
case int16:
|
||||
result.SetInt64(int64(v))
|
||||
case int32:
|
||||
result.SetInt64(int64(v))
|
||||
case int64:
|
||||
result.SetInt64(v)
|
||||
case uint:
|
||||
result.SetUint64(uint64(v)) // Convert to uint64 for big.Int
|
||||
case uint8:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint16:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint32:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint64:
|
||||
result.SetUint64(v)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type: %T", v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -571,3 +571,12 @@ func ExampleToRawUrlBase64() {
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToBigInt() {
|
||||
n := 9876543210
|
||||
bigInt, _ := ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -141,13 +142,24 @@ func TestToString(t *testing.T) {
|
||||
}
|
||||
aStruct := TestStruct{Name: "TestStruct"}
|
||||
|
||||
i32Val := int32(123)
|
||||
i64Val := int64(123)
|
||||
iZeroVal := 0
|
||||
fVal := 12.3
|
||||
sVal := "abc"
|
||||
var iNilPointer *int
|
||||
var sNilPointer *string
|
||||
|
||||
cases := []any{
|
||||
"", nil,
|
||||
int(0), int8(1), int16(-1), int32(123), int64(123),
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
float64(12.3), float32(12.3),
|
||||
true, false,
|
||||
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111}}
|
||||
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111},
|
||||
&i32Val, &i64Val, &fVal, &sVal, &aStruct, iNilPointer, sNilPointer,
|
||||
&iZeroVal,
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"", "",
|
||||
@@ -156,6 +168,8 @@ func TestToString(t *testing.T) {
|
||||
"12.3", "12.3",
|
||||
"true", "false",
|
||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello",
|
||||
"123", "123", "12.3", "abc", "{\"Name\":\"TestStruct\"}", "", "",
|
||||
"0",
|
||||
}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
@@ -741,3 +755,83 @@ func TestToRawUrlBase64(t *testing.T) {
|
||||
d15, _ := base64.RawURLEncoding.DecodeString(r15)
|
||||
assert.Equal("4+3/4?=", string(d15))
|
||||
}
|
||||
|
||||
func TestToBigInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToBigInt")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want *big.Int
|
||||
hasErr bool
|
||||
}{
|
||||
{
|
||||
name: "int",
|
||||
input: 42,
|
||||
want: big.NewInt(42),
|
||||
},
|
||||
{
|
||||
name: "int8",
|
||||
input: int8(127),
|
||||
want: big.NewInt(127),
|
||||
},
|
||||
{
|
||||
name: "int16",
|
||||
input: int16(32000),
|
||||
want: big.NewInt(32000),
|
||||
},
|
||||
{
|
||||
name: "int32",
|
||||
input: int32(123456),
|
||||
want: big.NewInt(123456),
|
||||
},
|
||||
{
|
||||
name: "int64",
|
||||
input: int64(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint",
|
||||
input: uint(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint8",
|
||||
input: uint8(255),
|
||||
want: big.NewInt(255),
|
||||
},
|
||||
{
|
||||
name: "uint16",
|
||||
input: uint16(65535),
|
||||
want: big.NewInt(65535),
|
||||
},
|
||||
{
|
||||
name: "uint32",
|
||||
input: uint32(4294967295),
|
||||
want: big.NewInt(4294967295),
|
||||
},
|
||||
{
|
||||
name: "uint64",
|
||||
input: uint64(18446744073709551615),
|
||||
want: new(big.Int).SetUint64(18446744073709551615),
|
||||
},
|
||||
{
|
||||
name: "unsupported type",
|
||||
input: 3.14, // Unsupported type
|
||||
hasErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ToBigInt(tt.input)
|
||||
if (err != nil) != tt.hasErr {
|
||||
t.Errorf("ToBigInt() error = %v, hasErr %v", err, tt.hasErr)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,20 @@ package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
@@ -245,7 +249,7 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
// AesGcmEncrypt encrypt data with key use AES GCM algorithm
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
@@ -268,7 +272,7 @@ func AesGcmEncrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
// AesGcmDecrypt decrypt data with key use AES GCM algorithm
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
@@ -561,7 +565,7 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
}
|
||||
|
||||
// RsaEncrypt encrypt data with ras algorithm.
|
||||
// Play: https://go.dev/play/p/rDqTT01SPkZ
|
||||
// Play: https://go.dev/play/p/7_zo6mrx-eX
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
file, err := os.Open(pubKeyFileName)
|
||||
if err != nil {
|
||||
@@ -591,11 +595,12 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return cipherText
|
||||
}
|
||||
|
||||
// RsaDecrypt decrypt data with ras algorithm.
|
||||
// Play: https://go.dev/play/p/rDqTT01SPkZ
|
||||
// Play: https://go.dev/play/p/7_zo6mrx-eX
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
file, err := os.Open(privateKeyFileName)
|
||||
if err != nil {
|
||||
@@ -624,6 +629,7 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return plainText
|
||||
}
|
||||
|
||||
@@ -655,3 +661,149 @@ func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte
|
||||
|
||||
return decryptedBytes, nil
|
||||
}
|
||||
|
||||
// RsaSign signs the data with RSA.
|
||||
// Play: https://go.dev/play/p/qhsbf8BJ6Mf
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
|
||||
privateKey, err := loadRasPrivateKey(privateKeyFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
|
||||
}
|
||||
|
||||
// RsaVerifySign verifies the signature of the data with RSA.
|
||||
// Play: https://go.dev/play/p/qhsbf8BJ6Mf
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
|
||||
publicKey, err := loadRsaPublicKey(pubKeyFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rsa.VerifyPKCS1v15(publicKey, hash, hashed, signature)
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRsaPublicKey(filename string) (*rsa.PublicKey, error) {
|
||||
pubKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(pubKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the public key")
|
||||
}
|
||||
|
||||
var pubKey *rsa.PublicKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
if blockType == "RSA PUBLIC KEY" {
|
||||
pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
}
|
||||
} else if blockType == "PUBLIC KEY" {
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRasPrivateKey(filename string) (*rsa.PrivateKey, error) {
|
||||
priKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(priKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the private key")
|
||||
}
|
||||
|
||||
var privateKey *rsa.PrivateKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
// PKCS#1 format
|
||||
if blockType == "RSA PRIVATE KEY" {
|
||||
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if blockType == "PRIVATE KEY" { // PKCS#8 format
|
||||
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ok bool
|
||||
privateKey, ok = priKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
// hashData returns the hash value of the data, using the specified hash function
|
||||
func hashData(hash crypto.Hash, data []byte) ([]byte, error) {
|
||||
if !hash.Available() {
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
var hashed []byte
|
||||
|
||||
switch hash {
|
||||
case crypto.SHA224:
|
||||
h := sha256.Sum224(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA256:
|
||||
h := sha256.Sum256(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA384:
|
||||
h := sha512.Sum384(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA512:
|
||||
h := sha512.Sum512(data)
|
||||
hashed = h[:]
|
||||
default:
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
return hashed, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -284,7 +285,7 @@ func ExampleDesOfbDecrypt() {
|
||||
|
||||
func ExampleGenerateRsaKey() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -297,14 +298,14 @@ func ExampleGenerateRsaKey() {
|
||||
|
||||
func ExampleRsaEncrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -314,14 +315,14 @@ func ExampleRsaEncrypt() {
|
||||
|
||||
func ExampleRsaDecrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -536,3 +537,49 @@ func ExampleRsaEncryptOAEP() {
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleRsaSign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRsaVerifySign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -139,13 +140,13 @@ func TestDesOfbEncrypt(t *testing.T) {
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "./rsa_private_example.pem", "./rsa_public_example.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "./rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "./rsa_private_example.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
@@ -170,7 +171,6 @@ func TestRsaEncryptOAEP(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAesGcmEncrypt(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
|
||||
data := "hello world"
|
||||
@@ -182,3 +182,53 @@ func TestAesGcmEncrypt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAesGcmEncrypt")
|
||||
assert.Equal(data, string(decrypted))
|
||||
}
|
||||
|
||||
func TestRsaSignAndVerify(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
t.Run("RSA Sign and Verify", func(t *testing.T) {
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify Invalid Signature", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
invalidSig := []byte("InvalidSignature")
|
||||
|
||||
err := RsaVerifySign(hash, data, invalidSig, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify With Different Hash", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
hashSign := crypto.SHA256
|
||||
hashVerify := crypto.SHA512
|
||||
|
||||
signature, err := RsaSign(hashSign, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hashVerify, data, signature, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
51
cryptor/rsa_private.pem
Normal file
51
cryptor/rsa_private.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
MIIJKAIBAAKCAgEA5IqWfYbW1NlTDWE2plFWqD6CTquA0Ar/1E66lY8OMtrdpxTm
|
||||
chirmoISWN0BD7r2tV9T/kHs44Sy3raAfkR5ixYF5FRkb63FdIAtoynsxS6MEE26
|
||||
fgWuDAa1xwNt+t/uivnpfJk25htpBNkKGT8ii0TPPLn1N15hMHenT6PzWVjGjQxW
|
||||
cp4dUA4gXTDuqaeu7Oy7Ku2yP90/ra+cjTV8DnBJ9enQhAfu1LivJO3FgmXeuC3u
|
||||
qhhM3t9ZbNy7tvJI5PXDCaS8iesBvCp5carTSXWLpFEgvIhXQIsXtxezKAP3gRd8
|
||||
r5JPQI9FZlxyUcyf+Htkn2A4qyKhFElnP1z9j0YLFhL/gQMdtNIY7yhSb29PyuCG
|
||||
7noz25swrfxbA7ZVppM0J19JNhlpqmusBKLBNqN+KMD8EDli7NLX17S9Dj2pQF9I
|
||||
8fVXPEhkdTb67rr7y3OUANKjh0Opnt3JLoj9u1X7BfCeUSR/qq3E8RFPeyxvP1tc
|
||||
5QVqKBG6UPBo8nLQqdzJhUd8a1YEfXIUbdHLs2q5WVFu2MDavIp634+fzfcIFRoB
|
||||
tdxf5aCdxLaLocsA/aLLyL1pK6K0rpdrSUtcEBMST26qIlU0Ht+SQtaMdE2gyjkM
|
||||
M5RpLh1q/gpow+0j3zu6f5tDsu3qwgjLIx78YCTGUuCpsVMzFK4tahYSPNkCAwEA
|
||||
AQKCAgEAuXz97X2uCW0lqjtXhp+HrN+nFUC/OJtkziTj7RUBmibnNX+SFdKOHMYr
|
||||
K/KbtO+y4rwvSLKrGHIQVxBas6DR4SALwij4p2erVgXehIo3gEZqKaVckoH7pAki
|
||||
KhdPgQmU6zkw1w7nbtWaY/Pf7WO/nrdHV+s56ilwykyi/9F6Ze7Wn43+7+ICuoHs
|
||||
pJZdblcJc4Qj2RC41nq0/zwD3NwnBvT+IlgWA8MIhaArjtZospAJtwSYq3czlMRE
|
||||
KUXyGOcGYMZS+RW6bFnPu6/hh271M67ymne6ESq7XkhGBDV5FCY8EItGiJ1AM47U
|
||||
7eJkap2gzKUhovUOqV9eyz9UTComJETl2kmcjpZeaxrZZxtPap23IzBu6PJoPuDg
|
||||
hgzRWh3BrkakLdq6Km2z+jDFEQhWeHsksozuKzln5USx9wovb9LDKKFSpKm4vzW+
|
||||
7YVLZnH4Z1m4wvWQJShvZur7kkM7aNfK+xcS81OBMtqKerjWhdHqfMRVvLvtG/ev
|
||||
ftPTwRy+u02w+FoYcassTS+lW+Pnhj0ZuOewsWoNvgWg1TpPEDBkY4UJOYQPkTrS
|
||||
bixTBVI3teSjMXmjEAif+BG2LBCl7pFY5SW9Jk6eRvmxt9rEly13C+4tcBHEJnXu
|
||||
eVUMurRuB/9BAKgj4qGHPQlG455mKHQzWJxJXBpRurh+U478xm0CggEBAOgduMra
|
||||
tPDhyhy01iIAzYsh0PW9p11AcCoJkDUE/5IUf03fVt3WKdSNauHZBKTulqaCHkvz
|
||||
+pjmSwPr4JdJKcJzwk5ncResFBYF177JmYXzJzwpIPRQFNP34heaUd9cVsFckddV
|
||||
G3jR7c1vD33VElexUM94BubZFEqF2lO3/y0sLwhd7prKhwy6mctJyvyDFk02psDc
|
||||
6XzBG/sMiZ6meWA1sP4QIM6+sYdZ9ihvTNWGb1+TGojvgOHCEQ3Hv9u/qwdkzFKj
|
||||
qo25pRMV4VNMQUvYIywSB7K5c0w1ccfOINzB8kgqpHhpimAHqZw9ix4H98YmvaXS
|
||||
rr0LP8ES9xVvelcCggEBAPwOs7pWvm/R3RAXZ8Erk9x68Fsn8wzoofsGP/BG5QCC
|
||||
r1fDJr9aJAVggXOVNDktWRKkN7Cnib+Z7ymL5br3FfYPy945cF2e8nkx2ri0VveF
|
||||
glkPCFLb3lF3iLKD8nJNtiv1rpu2v4Dj09+SzQYSIF3h55BaZGUCHLskR7Mhdd74
|
||||
iTBzPaQ3NC+n0xrv8o1EXjy9w/nBt07sZojrf82Ae3mIbEFYdEHUVDaCZKKeBT4b
|
||||
9W8Q5aAt56DIkSkaBAZZZhzbfxollmeKiwJ32+finR7LZ1Fj2cTHia19Ef85U8bE
|
||||
Ow7E2cTDZkqaqgi+pFescl518DQ47PCeXfnFP0g65E8CggEAUApHubO3J0VE06dM
|
||||
G8eZGTwc+VBf0RkyVFyd3JqPoojs6SZ1puN94yysyZpzLoiTbHF8DwbfyC/JeF2z
|
||||
QZfaDZKrUyv6ZIZTGtEC92g/R2B0jBtGoNiohft5fFgbmWEXDXBlXhKb+YqybN+6
|
||||
QNLjk1eynQgvoRUEGTqU8b+F/8a3pTP23muuLCaAeAhHNdHiM9f/oovK+9j/VA+b
|
||||
uRiAzDtXgBSBq6k4QIs2BfVzUkIcT6HDSasFD1RDWzQhJZ6vVEpe5rRHUL3OfYlS
|
||||
/M1TytqKLl09SFUIvCPFy3d5/4XljRsfQeJq8/hQdW8HdOCcgTjEttSyqr+hSWvH
|
||||
xh192wKCAQB0uSY3u2XTCH9zrTMJ/HErn+7gd76REsW4JmvDjEEOHHawkJnH8SlP
|
||||
KCKqcMTPWZWvEUcM0njytolPVw6ap0OPQD9reHP1lt64iwK7mB/R3gy/yztSi6kH
|
||||
VvCBoqLKlfwvnUUvrNBAEsER/rxc/FXqw+tlKMbnE7RUYXeml28rQzLcsfEws7PC
|
||||
Adi717QeATQWstYnObL2pHjTHSOA+ee0Hx3qoNith3M8DuQlfkH1QiNFPLDpnXhv
|
||||
N5IpU3fbrNihsm/InvFon3rCONkoKAQUt6LvyOqWusSiB5Im+9g06rhinXwvJ0Ge
|
||||
eMMW65nVU/FelwUWWeo3f08LlHE6tLL3AoIBABcc549sTCMhBmQS9prESurzhPVk
|
||||
HCFYlR/GdlfNmRtTYssk25xaG+tiaEzXi7DXBq20TGNOATgoX7l9EWIRXkDuR6hS
|
||||
aRXyn+CVU3y2dhpGZBf+EUWP0u9TNSJ/RFO0ViAriL5J9kjF9hFvG36B9kRSiMrn
|
||||
mCp9NCdtRYOHjzkvbY5uRMqP8H4/nAXNMA+odPnOPDUOIcH2ztaFOtQgZxa9x/eS
|
||||
eGmnJ/V/rLvS04uVw5d7juJstEspnM4MxPHSFEDN7NG13bN+c1jTY1/85icIeRBi
|
||||
nP47M2kDQ6RrEdgYfPbdlx1wGdTUIeAm3duptTiwpwa5Q2Js22TMJYRTnbM=
|
||||
-----END rsa private key-----
|
||||
51
cryptor/rsa_private_example.pem
Normal file
51
cryptor/rsa_private_example.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
MIIJKAIBAAKCAgEA0HaqqGWnNqwRVKoJUUjYiH/dwkSK61La4RGYkvDfcuo9pDgc
|
||||
zHVhFUb/MYWeb3bAlFAGcZLYSBh6WAGxbeMjSkaLroaXnafhKZ2oXXUy8CzyYxZw
|
||||
pLCDgJLG7Pf0jer3STZW93ZT8UJixbKwbqD6b8fkpMANwCYrTlXDWBuZVaEKuQNn
|
||||
C4XufQis4fwRxRgfrZuLMvuQVtnyYmssmnp8JHovYkr87giDjEgvlrC84Lez32Zh
|
||||
EhORRu5NGEDeZ1OewbkXGyQtbcBQYNAxgnOcO44MTTPhEdz4/A0xwzEe+yIOxWIA
|
||||
WuEM2rclXpZBW/MEK41gZ3C04KcX5R0KRdj2PTTH7vJ33yRC4hKtWetwMvsUrewr
|
||||
RKVcUgaeFykDAlgIDoSWvG0nzb70AWSoNcj7krLlwEc2WLGy/kCYWppnfYKafEJX
|
||||
pgblHrDFKlWvte68yrvGdCsWRLQ2uUF0xokQIg4u2bApyWNroxEtjHwUp1VeJuZB
|
||||
Qkfg+vIW+t3moQpMtlhy4aai/oGIxI5TIB82nv8TPVczjHmmE3hwL6nZ5OfbFyWp
|
||||
RFvKLtXcaAKMi2HqOLRkQhqjjJUCO9Wyhu1BkX8RAeKLl3S7gRyhuOB5JNUGEpQ3
|
||||
89MdbUX5S12Qp1xTDS+otbC8tYS1gu0OOOWowxbuF5+Ci2SYgSHv/3zXKoMCAwEA
|
||||
AQKCAgBASCdt0BLVABBEDD7dStpClTNbwWkZEa6e8p8ayJ4OwH6LkiYHQjbSqdbt
|
||||
fWeStYrC8T5bbU22RZ4MX1FIMl9iewh9o9FC806yV4RgdVBk0WdY+MV5c1jJn/kp
|
||||
f3hw/sCMWe5NVrah0bfFgMl5A7jWGUy/JN3Yn6yA9l9LXw9UYVl+Hbd7zSvycGdn
|
||||
NCSCo2K5VRqCeSJUNdbRVH0nkZeQZAESjU8bU5LFAklybUOBBAS6YcaTHWeR+M/b
|
||||
J72tHRL6Z8nhO7Gqg0AF6o0pzd6iWrYeZF4F9R7uEl+C8jW8eQ8W/JZhb75X/1vN
|
||||
pAW5heGGUI0muJF+KOhsZR0S1slvHbCSvwaNBQi8HEbOEPa7wVzsrGLfc+re5ysF
|
||||
X2n5GL4qBwNdMHrADnMWWVa9LEUSr3XmXfpmNDctmdv1ekWpJ44G/qrjKOuimtfk
|
||||
t9haDjhN5lx3V05k18kb53tYAdi3CqrT4syiibtqZLvTRam/yoFJgSOczO5WxNNk
|
||||
xnhnEdr/FQcFQhzuQ6gU196SBi8Bqjz1t0cNozNu3wvp8Fu0G8Rr9gjYnH8m5xXz
|
||||
xb9xevR7X/swfxd+/KUqoenYdU5ZFJpDRCmUMDKWR/3Q7s4SRxMN0+c/uBSaih3J
|
||||
I9I8urHG6mFW2qWQZTvuostmb7vVHaefx0RZOhX0efJVMZPwiQKCAQEA8BUXRw9k
|
||||
Ms3tqmBMVM4sMcPgsffJxjAJUdunUgEpaBAqrDQmZ6uBjAYq7iTzLgJJuLI1o1sv
|
||||
HtEWuGLHRRJpdoEamGweJE/o28OH2MBiiL2ezfRIHsg8RRr6os6KvlKevty6m7d9
|
||||
hAvpS6XvZGK2eCSooL6zZ8XTgnDw+Hw8Q4i+dazjb5dDRRL97eHHUqzcYH5vIsAE
|
||||
EBaNXMKrhf/NyVWCJBVRHg8PZZjGXcrj8ZMx+ejDR0AL5BXUaAX3fYnQyJf6QzrD
|
||||
t5aNDoU6vPO77CLkqBavTePTToiVeTIMZP5yHZFQuPWtP/y67e0csNA6ezwpWEh4
|
||||
4MnpLWzC2YRZ/wKCAQEA3kjpB3977IHFw90Xn8TQu3/SzBMUBqdj5yo6gPBijKNf
|
||||
4mZ1shUp6vZkFOHbAmoafjqCzOO18tW4ci+UWAQgdXQWXwsQDUM+fZsr/5Z9LoIN
|
||||
TYuq98Yh/rjKABxkFdMmkLmykuAblDRwVeMf3e4x6/55hAkwvESBRdfnSjjoNmEM
|
||||
MRVW4v5meDv0W4NS1eyohWPe/IoR09dSsmMhz311b7btBxc97NNqDD4SdxmASnOZ
|
||||
qsE2QxRHRFjpTvytpZH/lTQH6IYdh9REZgX7uvmlmTQwqLy6wX5T/oEzVPRhXgh9
|
||||
rgbPPJuoZwWF+fXipJ8c+laQ/sdzDKCxEEhRZr7HfQKCAQBKflDVtLnjZbA78Fte
|
||||
6QYffubGcdtCyn7pzl0RfdjKOFH1Us0j17x/pR5G/GIUQZN8YpdwE4gAaOJC3it0
|
||||
jCz7Hz4QU2Pa4oyfPAF3yOIKCcQvpX+HRZwl2SQxxiKYwWwOTtD8JiglA8kktt0b
|
||||
6eEyUDWegu2J4oEpdT/f6jSMw+5M9xMu+eFemnD+EdNWHNrYegKj5q6cC1Nbl+++
|
||||
yUuiEA0sgwzDZeriHFBYo+6sc37LS2TkQ8QsxnU8vbU4V73XsAhwOdimq2kjO0Wp
|
||||
gXsq3vzSBw/n/CwBrzGqBFSCNc1UzVUdvuU9+H5L+wmu9z1eJaGyifIv1ZariJbB
|
||||
BWcjAoIBACWRJPEDdqot9IJ5pzh1RuGpZLLgto25VIUI+gI4ni8unVHiBxolwYPY
|
||||
SGnPEfiCfh+/O8Ps6B82R4nkyKlnaSTwjadac0gKiVEpHHKBuH5XtG/anvZpIe2u
|
||||
xVTnd3LI0Me82pVAEuklQ6cAT65uRzmfNGJAO2BWI5LuPkSpAXXPSQQymxCZ9i9z
|
||||
0oR02VcWPBTvIAyGOSUYSv2jC1/J0EMlI0IDh4+y20VeaDiAstHiX6IgLU+A6dp/
|
||||
PE8BHUfSOOO6e2us3ujJ0xV7BWRANOCDlYWu/9EbzI5Cv64n7xy5SqRSukt/8yIW
|
||||
KOJpz/gKfBdC8hZdFvCXZ9Vco4U90PECggEBAIwy5zuWqSaJ8kom7kMZj+JYfhVz
|
||||
rdozFil1CkmWcw4E+rNcq8bKVTa9Er6/3nBTXfKX+4sYzMzbFr6xjFyrPA62wjiT
|
||||
2MRdHu9iB+Rtxn83Ilnh+Aqu/8bPFQUlYFr7nefy2t1aL76diQnsBu4xHOtEMgSv
|
||||
F6d/pDFRC+PZN0B7glrz870jRaw9LNcuIBVoKN07hGBwD76EEZhCrn6eLqMI8srH
|
||||
YESDPUR/wl/PV8ZrA/hNRvjp44PYiLMYRDSQw8kpbLMMc0QgQCvhfMbYVvGteTmG
|
||||
qdCFyy2x70wSh6Rfzb7WEWl15I4yfBTddXkJX82S+MrZu/Xq4FDtng594h0=
|
||||
-----END rsa private key-----
|
||||
14
cryptor/rsa_public.pem
Normal file
14
cryptor/rsa_public.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5IqWfYbW1NlTDWE2plFW
|
||||
qD6CTquA0Ar/1E66lY8OMtrdpxTmchirmoISWN0BD7r2tV9T/kHs44Sy3raAfkR5
|
||||
ixYF5FRkb63FdIAtoynsxS6MEE26fgWuDAa1xwNt+t/uivnpfJk25htpBNkKGT8i
|
||||
i0TPPLn1N15hMHenT6PzWVjGjQxWcp4dUA4gXTDuqaeu7Oy7Ku2yP90/ra+cjTV8
|
||||
DnBJ9enQhAfu1LivJO3FgmXeuC3uqhhM3t9ZbNy7tvJI5PXDCaS8iesBvCp5carT
|
||||
SXWLpFEgvIhXQIsXtxezKAP3gRd8r5JPQI9FZlxyUcyf+Htkn2A4qyKhFElnP1z9
|
||||
j0YLFhL/gQMdtNIY7yhSb29PyuCG7noz25swrfxbA7ZVppM0J19JNhlpqmusBKLB
|
||||
NqN+KMD8EDli7NLX17S9Dj2pQF9I8fVXPEhkdTb67rr7y3OUANKjh0Opnt3JLoj9
|
||||
u1X7BfCeUSR/qq3E8RFPeyxvP1tc5QVqKBG6UPBo8nLQqdzJhUd8a1YEfXIUbdHL
|
||||
s2q5WVFu2MDavIp634+fzfcIFRoBtdxf5aCdxLaLocsA/aLLyL1pK6K0rpdrSUtc
|
||||
EBMST26qIlU0Ht+SQtaMdE2gyjkMM5RpLh1q/gpow+0j3zu6f5tDsu3qwgjLIx78
|
||||
YCTGUuCpsVMzFK4tahYSPNkCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
14
cryptor/rsa_public_example.pem
Normal file
14
cryptor/rsa_public_example.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0HaqqGWnNqwRVKoJUUjY
|
||||
iH/dwkSK61La4RGYkvDfcuo9pDgczHVhFUb/MYWeb3bAlFAGcZLYSBh6WAGxbeMj
|
||||
SkaLroaXnafhKZ2oXXUy8CzyYxZwpLCDgJLG7Pf0jer3STZW93ZT8UJixbKwbqD6
|
||||
b8fkpMANwCYrTlXDWBuZVaEKuQNnC4XufQis4fwRxRgfrZuLMvuQVtnyYmssmnp8
|
||||
JHovYkr87giDjEgvlrC84Lez32ZhEhORRu5NGEDeZ1OewbkXGyQtbcBQYNAxgnOc
|
||||
O44MTTPhEdz4/A0xwzEe+yIOxWIAWuEM2rclXpZBW/MEK41gZ3C04KcX5R0KRdj2
|
||||
PTTH7vJ33yRC4hKtWetwMvsUrewrRKVcUgaeFykDAlgIDoSWvG0nzb70AWSoNcj7
|
||||
krLlwEc2WLGy/kCYWppnfYKafEJXpgblHrDFKlWvte68yrvGdCsWRLQ2uUF0xokQ
|
||||
Ig4u2bApyWNroxEtjHwUp1VeJuZBQkfg+vIW+t3moQpMtlhy4aai/oGIxI5TIB82
|
||||
nv8TPVczjHmmE3hwL6nZ5OfbFyWpRFvKLtXcaAKMi2HqOLRkQhqjjJUCO9Wyhu1B
|
||||
kX8RAeKLl3S7gRyhuOB5JNUGEpQ389MdbUX5S12Qp1xTDS+otbC8tYS1gu0OOOWo
|
||||
wxbuF5+Ci2SYgSHv/3zXKoMCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
@@ -209,7 +209,7 @@ func (dl *DoublyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (dl *DoublyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, dl.length)
|
||||
current := dl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
@@ -212,7 +212,7 @@ func (sl *SinglyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (sl *SinglyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, sl.length)
|
||||
current := sl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
@@ -31,7 +31,7 @@ func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *ArrayQueue[T]) Data() []T {
|
||||
items := []T{}
|
||||
items := make([]T, 0, q.tail-q.head)
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
items = append(items, q.data[i])
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewLinkedQueue[T any]() *LinkedQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *LinkedQueue[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, q.length)
|
||||
current := q.head
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewLinkedStack[T any]() *LinkedStack[T] {
|
||||
|
||||
// Data return stack data
|
||||
func (s *LinkedStack[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, s.length)
|
||||
current := s.top
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -100,12 +100,6 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
|
||||
//todo
|
||||
// bstree.DeletetNode(6, comparator)
|
||||
// bstree.Print()
|
||||
// acturl2 := bstree.InOrderTraverse()
|
||||
// assert.Equal([]int{2, 5, 7}, acturl2)
|
||||
}
|
||||
|
||||
func TestBSTree_Depth(t *testing.T) {
|
||||
|
||||
@@ -147,7 +147,7 @@ func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel i
|
||||
|
||||
printSpaces(firstSpaces)
|
||||
|
||||
newNodes := []*datastructure.TreeNode[T]{}
|
||||
newNodes := make([]*datastructure.TreeNode[T], 0, len(nodes)*2)
|
||||
for _, node := range nodes {
|
||||
if node != nil {
|
||||
fmt.Printf("%v", node.Value)
|
||||
|
||||
@@ -64,28 +64,95 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// AddMinute add or sub minute to the time.
|
||||
// AddMinute add or sub minutes to the time.
|
||||
// Play: https://go.dev/play/p/nT1heB1KUUK
|
||||
func AddMinute(t time.Time, minute int64) time.Time {
|
||||
return t.Add(time.Minute * time.Duration(minute))
|
||||
func AddMinute(t time.Time, minutes int64) time.Time {
|
||||
return t.Add(time.Minute * time.Duration(minutes))
|
||||
}
|
||||
|
||||
// AddHour add or sub hour to the time.
|
||||
// AddHour add or sub hours to the time.
|
||||
// Play: https://go.dev/play/p/rcMjd7OCsi5
|
||||
func AddHour(t time.Time, hour int64) time.Time {
|
||||
return t.Add(time.Hour * time.Duration(hour))
|
||||
func AddHour(t time.Time, hours int64) time.Time {
|
||||
return t.Add(time.Hour * time.Duration(hours))
|
||||
}
|
||||
|
||||
// AddDay add or sub day to the time.
|
||||
// AddDay add or sub days to the time.
|
||||
// Play: https://go.dev/play/p/dIGbs_uTdFa
|
||||
func AddDay(t time.Time, day int64) time.Time {
|
||||
return t.Add(24 * time.Hour * time.Duration(day))
|
||||
func AddDay(t time.Time, days int64) time.Time {
|
||||
return t.Add(24 * time.Hour * time.Duration(days))
|
||||
}
|
||||
|
||||
// AddWeek add or sub weeks to the time.
|
||||
// play: todo
|
||||
func AddWeek(t time.Time, weeks int64) time.Time {
|
||||
return t.Add(7 * 24 * time.Hour * time.Duration(weeks))
|
||||
}
|
||||
|
||||
// AddMonth add or sub months to the time.
|
||||
// Play: todo
|
||||
func AddMonth(t time.Time, months int64) time.Time {
|
||||
return t.AddDate(0, int(months), 0)
|
||||
}
|
||||
|
||||
// AddYear add or sub year to the time.
|
||||
// Play: https://go.dev/play/p/MqW2ujnBx10
|
||||
func AddYear(t time.Time, year int64) time.Time {
|
||||
return t.Add(365 * 24 * time.Hour * time.Duration(year))
|
||||
return t.AddDate(int(year), 0, 0)
|
||||
}
|
||||
|
||||
// AddDaySafe add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
// Play: todo
|
||||
func AddDaySafe(t time.Time, days int) time.Time {
|
||||
t = t.AddDate(0, 0, days)
|
||||
year, month, day := t.Date()
|
||||
|
||||
lastDayOfMonth := time.Date(year, month+1, 0, 0, 0, 0, 0, t.Location()).Day()
|
||||
|
||||
if day > lastDayOfMonth {
|
||||
t = time.Date(year, month, lastDayOfMonth, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// AddMonthSafe add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
// Play: todo
|
||||
func AddMonthSafe(t time.Time, months int) time.Time {
|
||||
year := t.Year()
|
||||
month := int(t.Month()) + months
|
||||
|
||||
for month > 12 {
|
||||
month -= 12
|
||||
year++
|
||||
}
|
||||
for month < 1 {
|
||||
month += 12
|
||||
year--
|
||||
}
|
||||
|
||||
daysInMonth := time.Date(year, time.Month(month+1), 0, 0, 0, 0, 0, time.UTC).Day()
|
||||
|
||||
day := t.Day()
|
||||
if day > daysInMonth {
|
||||
day = daysInMonth
|
||||
}
|
||||
|
||||
return time.Date(year, time.Month(month), day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||
}
|
||||
|
||||
// AddYearSafe add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||
// Play: todo
|
||||
func AddYearSafe(t time.Time, years int) time.Time {
|
||||
year, month, day := t.Date()
|
||||
year += years
|
||||
|
||||
if month == time.February && day == 29 {
|
||||
if !IsLeapYear(year) {
|
||||
day = 28
|
||||
}
|
||||
}
|
||||
|
||||
return time.Date(year, month, day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||
}
|
||||
|
||||
// GetNowDate return format yyyy-mm-dd of current date.
|
||||
@@ -385,7 +452,7 @@ func TimestampNano(timezone ...string) int64 {
|
||||
|
||||
// TrackFuncTime track the time of function execution.
|
||||
// call it at top of the func like `defer TrackFuncTime(time.Now())()`
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/QBSEdfXHPTp
|
||||
func TrackFuncTime(pre time.Time) func() {
|
||||
callerName := getCallerName()
|
||||
return func() {
|
||||
@@ -413,7 +480,7 @@ func getCallerName() string {
|
||||
}
|
||||
|
||||
// DaysBetween returns the number of days between two times.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/qD6qGb3TbOy
|
||||
func DaysBetween(start, end time.Time) int {
|
||||
duration := end.Sub(start)
|
||||
days := int(duration.Hours() / 24)
|
||||
@@ -424,7 +491,7 @@ func DaysBetween(start, end time.Time) int {
|
||||
// GenerateDatetimesBetween returns a slice of strings between two times.
|
||||
// layout: the format of the datetime string
|
||||
// interval: the interval between two datetimes
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/6kHBpAxD9ZC
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error) {
|
||||
var result []string
|
||||
|
||||
@@ -443,3 +510,50 @@ func GenerateDatetimesBetween(start, end time.Time, layout string, interval stri
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Min returns the earliest time among the given times.
|
||||
// Play: https://go.dev/play/p/MCIDvHNOGGb
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time {
|
||||
minTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return minTime
|
||||
}
|
||||
|
||||
// Max returns the latest time among the given times.
|
||||
// Play: https://go.dev/play/p/9m6JMk1LB7-
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time {
|
||||
maxTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime
|
||||
}
|
||||
|
||||
// MaxMin returns the latest and earliest time among the given times.
|
||||
// Play: https://go.dev/play/p/rbW51cDtM_2
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
||||
maxTime = t1
|
||||
minTime = t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime, minTime
|
||||
}
|
||||
|
||||
@@ -7,71 +7,141 @@ import (
|
||||
)
|
||||
|
||||
func ExampleAddDay() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
tomorrow := AddDay(now, 1)
|
||||
diff1 := tomorrow.Sub(now)
|
||||
after1Day := AddDay(date, 1)
|
||||
before1Day := AddDay(date, -1)
|
||||
|
||||
yesterday := AddDay(now, -1)
|
||||
diff2 := yesterday.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 24h0m0s
|
||||
// -24h0m0s
|
||||
// 2021-01-02 00:00:00
|
||||
// 2020-12-31 00:00:00
|
||||
}
|
||||
|
||||
func ExampleAddWeek() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Weeks := AddWeek(date, 2)
|
||||
before2Weeks := AddWeek(date, -2)
|
||||
|
||||
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-01-15
|
||||
// 2020-12-18
|
||||
}
|
||||
|
||||
func ExampleAddMonth() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Months := AddMonth(date, 2)
|
||||
before2Months := AddMonth(date, -2)
|
||||
|
||||
fmt.Println(after2Months.Format("2006-01-02"))
|
||||
fmt.Println(before2Months.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-03-01
|
||||
// 2020-11-01
|
||||
}
|
||||
|
||||
func ExampleAddHour() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Hours := AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
after2Hours := AddHour(date, 2)
|
||||
before2Hours := AddHour(date, -2)
|
||||
|
||||
before2Hours := AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2h0m0s
|
||||
// -2h0m0s
|
||||
// 2021-01-01 02:00:00
|
||||
// 2020-12-31 22:00:00
|
||||
}
|
||||
|
||||
func ExampleAddMinute() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Minutes := AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
after2Minutes := AddMinute(date, 2)
|
||||
before2Minutes := AddMinute(date, -2)
|
||||
|
||||
before2Minutes := AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2m0s
|
||||
// -2m0s
|
||||
// 2021-01-01 00:02:00
|
||||
// 2020-12-31 23:58:00
|
||||
}
|
||||
|
||||
func ExampleAddYear() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after1Year := AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
after2Years := AddYear(date, 2)
|
||||
before2Years := AddYear(date, -2)
|
||||
|
||||
before1Year := AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Years.Format("2006-01-02"))
|
||||
fmt.Println(before2Years.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
// 2023-01-01
|
||||
// 2019-01-01
|
||||
}
|
||||
|
||||
func ExampleAddDaySafe() {
|
||||
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result1 := AddDaySafe(leapYearDate1, 1)
|
||||
|
||||
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||
result2 := AddDaySafe(leapYearDate2, -1)
|
||||
|
||||
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||
result3 := AddDaySafe(nonLeapYearDate1, 1)
|
||||
|
||||
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||
result4 := AddDaySafe(nonLeaYearDate2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
fmt.Println(result3.Format("2006-01-02"))
|
||||
fmt.Println(result4.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2024-03-01
|
||||
// 2024-02-29
|
||||
// 2025-03-01
|
||||
// 2025-02-28
|
||||
}
|
||||
|
||||
func ExampleAddMonthSafe() {
|
||||
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||
result1 := AddMonthSafe(date1, 1)
|
||||
|
||||
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result2 := AddMonthSafe(date2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2025-02-28
|
||||
// 2024-01-29
|
||||
}
|
||||
|
||||
func ExampleAddYearSafe() {
|
||||
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||
|
||||
result1 := AddYearSafe(date, 1)
|
||||
result2 := AddYearSafe(date, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-02-28
|
||||
// 2019-02-28
|
||||
}
|
||||
|
||||
func ExampleGetNowDate() {
|
||||
@@ -437,3 +507,32 @@ func ExampleGenerateDatetimesBetween() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result := Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result := Max(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMaxMin() {
|
||||
max, min := MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
@@ -9,78 +9,427 @@ import (
|
||||
|
||||
func TestAddYear(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddDay")
|
||||
|
||||
now := time.Now()
|
||||
after2Years := AddYear(now, 1)
|
||||
diff1 := after2Years.Sub(now)
|
||||
assert.Equal(float64(8760), diff1.Hours())
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
years int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: 1,
|
||||
expected: "2022-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: -1,
|
||||
expected: "2020-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: 0,
|
||||
expected: "2021-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: 2,
|
||||
expected: "2023-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: 3,
|
||||
expected: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
years: 4,
|
||||
expected: "2025-01-01 00:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
before2Years := AddYear(now, -1)
|
||||
diff2 := before2Years.Sub(now)
|
||||
assert.Equal(float64(-8760), diff2.Hours())
|
||||
}
|
||||
|
||||
func TestBetweenSeconds(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||
|
||||
today := time.Now()
|
||||
tomorrow := AddDay(today, 1)
|
||||
yesterday := AddDay(today, -1)
|
||||
|
||||
result1 := BetweenSeconds(today, tomorrow)
|
||||
result2 := BetweenSeconds(today, yesterday)
|
||||
|
||||
assert.Equal(int64(86400), result1)
|
||||
assert.Equal(int64(-86400), result2)
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||
result := AddYear(date, int64(tt.years))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddDay(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddDay")
|
||||
|
||||
now := time.Now()
|
||||
after2Days := AddDay(now, 2)
|
||||
diff1 := after2Days.Sub(now)
|
||||
assert.Equal(float64(48), diff1.Hours())
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
days int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: 1,
|
||||
expected: "2021-01-02 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: -1,
|
||||
expected: "2020-12-31 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: 0,
|
||||
expected: "2021-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: 2,
|
||||
expected: "2021-01-03 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: 3,
|
||||
expected: "2021-01-04 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
days: 4,
|
||||
expected: "2021-01-05 00:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
before2Days := AddDay(now, -2)
|
||||
diff2 := before2Days.Sub(now)
|
||||
assert.Equal(float64(-48), diff2.Hours())
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||
result := AddDay(date, int64(tt.days))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddHour(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddHour")
|
||||
|
||||
now := time.Now()
|
||||
after2Hours := AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
assert.Equal(float64(2), diff1.Hours())
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
hours int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 1,
|
||||
expected: "2021-01-01 01:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: -1,
|
||||
expected: "2020-12-31 23:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 0,
|
||||
expected: "2021-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 24,
|
||||
expected: "2021-01-02 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 25,
|
||||
expected: "2021-01-02 01:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 48,
|
||||
expected: "2021-01-03 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
hours: 49,
|
||||
expected: "2021-01-03 01:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||
result := AddHour(date, int64(tt.hours))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
before2Hours := AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
assert.Equal(float64(-2), diff2.Hours())
|
||||
}
|
||||
|
||||
func TestAddMinute(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddMinute")
|
||||
|
||||
now := time.Now()
|
||||
after2Minutes := AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
assert.Equal(float64(2), diff1.Minutes())
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
minutes int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 1,
|
||||
expected: "2021-01-01 00:01:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: -1,
|
||||
expected: "2020-12-31 23:59:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 0,
|
||||
expected: "2021-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 60,
|
||||
expected: "2021-01-01 01:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 61,
|
||||
expected: "2021-01-01 01:01:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 1440,
|
||||
expected: "2021-01-02 00:00:00",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01 00:00:00",
|
||||
minutes: 1441,
|
||||
expected: "2021-01-02 00:01:00",
|
||||
},
|
||||
}
|
||||
|
||||
before2Minutes := AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
assert.Equal(float64(-2), diff2.Minutes())
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||
result := AddMinute(date, int64(tt.minutes))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddWeek(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddWeek")
|
||||
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
weeks int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: 1,
|
||||
expected: "2021-01-08",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: -1,
|
||||
expected: "2020-12-25",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: 0,
|
||||
expected: "2021-01-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: 52,
|
||||
expected: "2021-12-31",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: 53,
|
||||
expected: "2022-01-07",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
weeks: 104,
|
||||
expected: "2022-12-30",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||
result := AddWeek(date, int64(tt.weeks))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMonth(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddMonth")
|
||||
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
months int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: 1,
|
||||
expected: "2021-02-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: -1,
|
||||
expected: "2020-12-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: 0,
|
||||
expected: "2021-01-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: 12,
|
||||
expected: "2022-01-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: 13,
|
||||
expected: "2022-02-01",
|
||||
},
|
||||
{
|
||||
inputDate: "2021-01-01",
|
||||
months: 24,
|
||||
expected: "2023-01-01",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||
result := AddMonth(date, int64(tt.months))
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAddDaySafe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddDaySafe")
|
||||
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
days int
|
||||
expected string
|
||||
}{
|
||||
{"2025-01-31", 10, "2025-02-10"},
|
||||
{"2025-01-01", 30, "2025-01-31"},
|
||||
{"2025-01-31", 1, "2025-02-01"},
|
||||
{"2025-02-28", 1, "2025-03-01"},
|
||||
{"2024-02-29", 1, "2024-03-01"},
|
||||
{"2024-02-29", 365, "2025-02-28"},
|
||||
|
||||
{"2025-01-31", -10, "2025-01-21"},
|
||||
{"2025-01-01", -30, "2024-12-02"},
|
||||
{"2025-02-01", -1, "2025-01-31"},
|
||||
{"2025-03-01", -1, "2025-02-28"},
|
||||
{"2024-03-01", -1, "2024-02-29"},
|
||||
|
||||
{"2025-01-31", -31, "2024-12-31"},
|
||||
{"2025-12-31", 1, "2026-01-01"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||
result := AddDaySafe(date, tt.days)
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMonthSafe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddMonthSafe")
|
||||
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
months int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2025-01-31",
|
||||
months: 1,
|
||||
expected: "2025-02-28",
|
||||
},
|
||||
{
|
||||
inputDate: "2025-01-31",
|
||||
months: -1,
|
||||
expected: "2024-12-31",
|
||||
},
|
||||
{
|
||||
inputDate: "2025-12-31",
|
||||
months: 1,
|
||||
expected: "2026-01-31",
|
||||
},
|
||||
{
|
||||
inputDate: "2025-01-31",
|
||||
months: -1,
|
||||
expected: "2024-12-31",
|
||||
},
|
||||
{
|
||||
inputDate: "2024-02-29",
|
||||
months: 1,
|
||||
expected: "2024-03-29",
|
||||
},
|
||||
{
|
||||
inputDate: "2024-02-29",
|
||||
months: -1,
|
||||
expected: "2024-01-29",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||
result := AddMonthSafe(date, tt.months)
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAddYearSafe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestAddYearSafe")
|
||||
|
||||
tests := []struct {
|
||||
inputDate string
|
||||
years int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
inputDate: "2020-02-29",
|
||||
years: 1,
|
||||
expected: "2021-02-28",
|
||||
},
|
||||
{
|
||||
inputDate: "2020-02-29",
|
||||
years: 2,
|
||||
expected: "2022-02-28",
|
||||
},
|
||||
{
|
||||
inputDate: "2020-02-29",
|
||||
years: -1,
|
||||
expected: "2019-02-28",
|
||||
},
|
||||
{
|
||||
inputDate: "2020-02-29",
|
||||
years: -2,
|
||||
expected: "2018-02-28",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||
result := AddYearSafe(date, tt.years)
|
||||
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNowDate(t *testing.T) {
|
||||
@@ -521,3 +870,76 @@ func TestGenerateDatetimesBetween(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(zeroTime, Min(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(zeroTime, Min(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAgo, Min(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(now, Max(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMaxMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMinMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
max, min := MaxMin(zeroTime, now, oneMinuteAgo, oneMinuteAfter)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
|
||||
max, min = MaxMin(now, zeroTime)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(now, max)
|
||||
|
||||
max, min = MaxMin(oneMinuteAgo, now, oneMinuteAfter)
|
||||
assert.Equal(oneMinuteAgo, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
}
|
||||
|
||||
func TestBetweenSeconds(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||
|
||||
today := time.Now()
|
||||
tomorrow := AddDay(today, 1)
|
||||
yesterday := AddDay(today, -1)
|
||||
|
||||
result1 := BetweenSeconds(today, tomorrow)
|
||||
result2 := BetweenSeconds(today, yesterday)
|
||||
|
||||
assert.Equal(int64(86400), result1)
|
||||
assert.Equal(int64(-86400), result2)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -257,9 +258,45 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>三元运算符。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>三元运算符</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`Ternary`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [ToUrlBase64](#ToUrlBase64)
|
||||
- [ToRawStdBase64](#ToRawStdBase64)
|
||||
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||
- [ToBigInt](#ToBigInt)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -372,7 +373,7 @@ import (
|
||||
|
||||
func main() {
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result, err := ToJson(aMap)
|
||||
result, err := convertor.ToJson(aMap)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
@@ -1148,4 +1149,34 @@ func main() {
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToBigInt">ToBigInt</span>
|
||||
|
||||
<p>将整数值转换为bigInt。</p>
|
||||
|
||||
<b>函数签名:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/X3itkCxwB_x)</span></b>
|
||||
|
||||
```go
|
||||
func ToBigInt[T any](v T) (*big.Int, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 9876543210
|
||||
bigInt, _ := convertor.ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
```
|
||||
@@ -70,6 +70,9 @@ import (
|
||||
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||
- [RsaSign](#RsaSign)
|
||||
- [RsaVerifySign](#RsaVerifySign)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -391,7 +394,7 @@ func main() {
|
||||
func AesGcmEncrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -425,7 +428,7 @@ func main() {
|
||||
func AesGcmDecrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1433,7 +1436,7 @@ func main() {
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uef0q1fz53I)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7_zo6mrx-eX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1470,7 +1473,7 @@ func main() {
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uef0q1fz53I)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7_zo6mrx-eX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1607,3 +1610,81 @@ func main() {
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaSign">RsaSign</span>
|
||||
|
||||
<p>应用RSA算法签名数据。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qhsbf8BJ6Mf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := cryptor.RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = cryptor.RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaVerifySign">RsaVerifySign</span>
|
||||
|
||||
<p>验证数据的签名是否符合RSA算法。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qhsbf8BJ6Mf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := cryptor.RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = cryptor.RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -23,9 +23,14 @@ import (
|
||||
## 目录
|
||||
|
||||
- [AddDay](#AddDay)
|
||||
- [AddWeek](#AddWeek)
|
||||
- [AddMonth](#AddMonth)
|
||||
- [AddHour](#AddHour)
|
||||
- [AddMinute](#AddMinute)
|
||||
- [AddYear](#AddYear)
|
||||
- [AddDaySafe](#AddDaySafe)
|
||||
- [AddMonthSafe](#AddMonthSafe)
|
||||
- [AddYearSafe](#AddYearSafe)
|
||||
- [BeginOfMinute](#BeginOfMinute)
|
||||
- [BeginOfHour](#BeginOfHour)
|
||||
- [BeginOfDay](#BeginOfDay)
|
||||
@@ -67,6 +72,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -106,7 +114,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddDay(t time.Time, day int64) time.Time
|
||||
func AddDay(t time.Time, days int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
||||
@@ -121,20 +129,89 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
tomorrow := datetime.AddDay(now, 1)
|
||||
diff1 := tomorrow.Sub(now)
|
||||
after1Day := datetime.AddDay(date, 1)
|
||||
before1Day := datetime.AddDay(date, -1)
|
||||
|
||||
yesterday := datetime.AddDay(now, -1)
|
||||
diff2 := yesterday.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 24h0m0s
|
||||
// -24h0m0s
|
||||
// 2021-01-02 00:00:00
|
||||
// 2020-12-31 00:00:00
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddWeek">AddWeek</span>
|
||||
|
||||
<p>将日期加/减星期数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddWeek(t time.Time, weeks int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Weeks := datetime.AddWeek(date, 2)
|
||||
before2Weeks := datetime.AddWeek(date, -2)
|
||||
|
||||
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-01-15
|
||||
// 2020-12-18
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddMonth">AddMonth</span>
|
||||
|
||||
<p>将日期加/减月数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddMonth(t time.Time, months int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Months := datetime.AddMonth(date, 2)
|
||||
before2Months := datetime.AddMonth(date, -2)
|
||||
|
||||
fmt.Println(after2Months.Format("2006-01-02"))
|
||||
fmt.Println(before2Months.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-03-01
|
||||
// 2020-11-01
|
||||
}
|
||||
```
|
||||
|
||||
@@ -145,7 +222,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddHour(t time.Time, hour int64) time.Time
|
||||
func AddHour(t time.Time, hours int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rcMjd7OCsi5)</span></b>
|
||||
@@ -160,20 +237,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Hours := datetime.AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
after2Hours := datetime.AddHour(date, 2)
|
||||
before2Hours := datetime.AddHour(date, -2)
|
||||
|
||||
before2Hours := datetime.AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2h0m0s
|
||||
// -2h0m0s
|
||||
// 2021-01-01 02:00:00
|
||||
// 2020-12-31 22:00:00
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,7 +258,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddMinute(t time.Time, minute int64) time.Time
|
||||
func AddMinute(t time.Time, minutes int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nT1heB1KUUK)</span></b>
|
||||
@@ -199,20 +273,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Minutes := datetime.AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
after2Minutes := datetime.AddMinute(date, 2)
|
||||
before2Minutes := datetime.AddMinute(date, -2)
|
||||
|
||||
before2Minutes := datetime.AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2m0s
|
||||
// -2m0s
|
||||
// 2021-01-01 00:02:00
|
||||
// 2020-12-31 23:58:00
|
||||
}
|
||||
```
|
||||
|
||||
@@ -223,7 +294,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddYear(t time.Time, year int64) time.Time
|
||||
func AddYear(t time.Time, years int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MqW2ujnBx10)</span></b>
|
||||
@@ -238,20 +309,137 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after1Year := datetime.AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
after2Years := AddYear(date, 2)
|
||||
before2Years := AddYear(date, -2)
|
||||
|
||||
before1Year := datetime.AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Years.Format("2006-01-02"))
|
||||
fmt.Println(before2Years.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
// 2023-01-01
|
||||
// 2019-01-01
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddDaySafe">AddDaySafe</span>
|
||||
|
||||
<p>增加/减少指定的天数,并确保日期是有效日期。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddDaySafe(t time.Time, days int) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result1 := datetime.AddDaySafe(leapYearDate1, 1)
|
||||
|
||||
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||
result2 := datetime.AddDaySafe(leapYearDate2, -1)
|
||||
|
||||
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||
result3 := datetime.AddDaySafe(nonLeapYearDate1, 1)
|
||||
|
||||
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||
result4 := datetime.AddDaySafe(nonLeaYearDate2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
fmt.Println(result3.Format("2006-01-02"))
|
||||
fmt.Println(result4.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2024-03-01
|
||||
// 2024-02-29
|
||||
// 2025-03-01
|
||||
// 2025-02-28
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddMonthSafe">AddMonthSafe</span>
|
||||
|
||||
<p>增加/减少指定的月份,并确保日期是有效日期。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddMonthSafe(t time.Time, months int) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||
result1 := datetime.AddMonthSafe(date1, 1)
|
||||
|
||||
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result2 := datetime.AddMonthSafe(date2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2025-02-28
|
||||
// 2024-01-29
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddYearSafe">AddYearSafe</span>
|
||||
|
||||
<p>增加/减少指定的年份,并确保日期是有效日期。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AddYearSafe(t time.Time, years int) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||
|
||||
result1 := datetime.AddYearSafe(date, 1)
|
||||
result2 := datetime.AddYearSafe(date, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-02-28
|
||||
// 2019-02-28
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1479,7 +1667,7 @@ func main() {
|
||||
func TrackFuncTime(pre time.Time) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QBSEdfXHPTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1511,7 +1699,7 @@ func main() {
|
||||
func DaysBetween(start, end time.Time) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qD6qGb3TbOy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1544,7 +1732,7 @@ func main() {
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6kHBpAxD9ZC)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1570,4 +1758,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>返回最早时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MCIDvHNOGGb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>返回最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9m6JMk1LB7-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>返回最早和最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rbW51cDtM_2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
401
docs/api/packages/eventbus.md
Normal file
401
docs/api/packages/eventbus.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# EventBus
|
||||
|
||||
EventbBus是一个事件总线,用于在应用程序中处理事件。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go](https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [NewEventBus](#NewEventBus)
|
||||
- [Subscribe](#Subscribe)
|
||||
- [Unsubscribe](#Unsubscribe)
|
||||
- [Publish](#Publish)
|
||||
- [ClearListeners](#ClearListeners)
|
||||
- [ClearListenersByTopic](#ClearListenersByTopic)
|
||||
- [GetListenersCount](#GetListenersCount)
|
||||
- [GetAllListenersCount](#GetAllListenersCount)
|
||||
- [GetEvents](#GetEvents)
|
||||
- [SetErrorHandler](#SetErrorHandler)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="NewEventBus">NewEventBus</span>
|
||||
|
||||
<p>创建EventBus实例。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewEventBus[T any]() *EventBus[T]
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Subscribe">Subscribe</span>
|
||||
|
||||
<p>订阅具有特定事件主题和监听函数的事件。支持异步,事件优先级,事件过滤器。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
filter := func(eventData int) bool {
|
||||
return eventData == 1
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, filter)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Unsubscribe">Unsubscribe</span>
|
||||
|
||||
<p>取消订阅具有特定事件主题的事件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T))
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Unsubscribe("event1", listener)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Publish">Publish</span>
|
||||
|
||||
<p>发布一个带有特定事件主题和数据负载的事件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Publish(event Event[T])
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ClearListeners">ClearListeners</span>
|
||||
|
||||
<p>清空所有事件监听器。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) ClearListeners()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListeners()
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ClearListenersByTopic">ClearListenersByTopic</span>
|
||||
|
||||
<p>清空特定事件监听器。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) ClearListenersByTopic(topic string)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListenersByTopic("event1")
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetListenersCount">GetListenersCount</span>
|
||||
|
||||
<p>获取特定事件的监听器数量。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetListenersCount(topic string) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetListenersCount("event1")
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetAllListenersCount">GetAllListenersCount</span>
|
||||
|
||||
<p>获取所有事件的监听器数量。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetAllListenersCount() int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetAllListenersCount()
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetEvents">GetEvents</span>
|
||||
|
||||
<p>获取所有事件的topic。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetEvents() []string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
events := eb.GetEvents()
|
||||
|
||||
for _, event := range events {
|
||||
fmt.Println(event)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// event1
|
||||
// event2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SetErrorHandler">SetErrorHandler</span>
|
||||
|
||||
<p>设置事件的错误处理函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) SetErrorHandler(handler func(err error))
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.SetErrorHandler(func(err error) {
|
||||
fmt.Println(err)
|
||||
})
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
panic("error")
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// error
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1076,4 +1077,34 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>返回exe,dll文件版本号(仅Window平台).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iLRrDBhE38E)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -205,7 +205,7 @@ func main() {
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func())
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/-dGFrYn_1Zi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -753,7 +753,7 @@ func main() {
|
||||
func Throttle(fn func(), interval time.Duration) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HpoMov-tJSN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -1191,7 +1191,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1230,7 +1230,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1270,7 +1270,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Delete(key K)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/5bIi4yaZ3K-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1306,7 +1306,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Clear()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8LwoJyEfuFr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1345,7 +1345,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ty57XSimpoe)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1385,7 +1385,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rQMjp1yQmpa)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1402,12 +1402,12 @@ func main() {
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
frontElement, ok := om.Front()
|
||||
fmt.Println(frontElement)
|
||||
backElement, ok := om.Back()
|
||||
fmt.Println(backElement)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// {a 1}
|
||||
// {c 3}
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1422,7 +1422,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/U-KpORhc7LZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1461,7 +1461,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Keys() []K
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Vv_y9ExKclA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1497,7 +1497,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Values() []V
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TWj5n1-PUfx)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1533,7 +1533,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Elements() []struct
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4BHG4kKz6bB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1569,7 +1569,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cLe6z2VX5N-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1605,7 +1605,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QuwqqnzwDNX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1647,7 +1647,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tlq2tdvicPt)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1688,7 +1688,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8Q0ssg6hZzO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1726,7 +1726,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/N7hjD_alZPq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1737,7 +1737,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1765,7 +1765,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/C-wAwydIAC7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1776,7 +1776,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1802,7 +1802,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8C3MvJ3-mut)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1822,6 +1822,7 @@ func main() {
|
||||
fmt.Println(om.Elements())
|
||||
|
||||
// Output:
|
||||
// [{a 1} {b 2} {c 3}]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2239,7 +2240,7 @@ func main() {
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/PVdmBSnm6P_W)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -2257,7 +2258,9 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKey(m)
|
||||
result := maputil.SortByKey(m, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
@@ -2276,7 +2279,7 @@ func main() {
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [T运行cRound](#T运行cRound)
|
||||
- [CeilToFloat](#CeilToFloat)
|
||||
- [CeilToString](#CeilToString)
|
||||
- [FloorToFloat](#FloorToFloat)
|
||||
@@ -52,6 +52,10 @@ import (
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
- [Div](#Div)
|
||||
- [Variance](#Variance)
|
||||
- [StdDev](#StdDev)
|
||||
- [Permutation](#Permutation)
|
||||
- [Combination](#Combination)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -64,7 +68,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
|
||||
@@ -87,7 +91,7 @@ func main() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
@@ -462,14 +466,14 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
### <span id="T运行cRound">T运行cRound</span>
|
||||
|
||||
<p>截短n位小数(不进行四舍五入)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TruncRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||
func T运行cRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
|
||||
@@ -483,9 +487,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(0.124, 2)
|
||||
result2 := mathutil.TruncRound(0.125, 2)
|
||||
result3 := mathutil.TruncRound(0.125, 3)
|
||||
result1 := mathutil.T运行cRound(0.124, 2)
|
||||
result2 := mathutil.T运行cRound(0.125, 2)
|
||||
result3 := mathutil.T运行cRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1045,8 +1049,8 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
result2 := mathutil.T运行cRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.T运行cRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1162,4 +1166,136 @@ func main() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Variance">Variance</span>
|
||||
|
||||
<p>计算方差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[示例](https://go.dev/play/p/uHuV4YgXf8F)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := mathutil.Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StdDev">StdDev</span>
|
||||
|
||||
<p>计算标准差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/FkNZDXvHD2l)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := mathutil.TruncRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Permutation">Permutation</span>
|
||||
|
||||
<p>计算排列数P(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Permutation(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MgobwH_FOxj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Permutation(5, 3)
|
||||
result2 := mathutil.Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Combination">Combination</span>
|
||||
|
||||
<p>计算组合数C(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Combination(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ENFQRDQUFi9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Combination(5, 3)
|
||||
result2 := mathutil.Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -134,7 +135,7 @@ func main() {
|
||||
func RandFromGivenSlice[T any](slice []T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UrkWueF6yYo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -161,7 +162,7 @@ func main() {
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/68UikN9d6VT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -172,9 +173,11 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
fmt.Println(chosen3goods)
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
|
||||
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
|
||||
fmt.Println(chosen3goods)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -347,7 +350,7 @@ func main() {
|
||||
func RandIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GATTQ5xTEG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -451,7 +454,7 @@ func main() {
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2_-PiDv3tGn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -480,7 +483,7 @@ func main() {
|
||||
func RandBool() bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/to6BLc26wBv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -506,7 +509,7 @@ func main() {
|
||||
func RandBoolSlice(length int) []bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/o-VSjPjnILI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -520,4 +523,29 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>生成指定长度的随机数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/oyZbuV7bu7b)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -44,6 +44,7 @@ import (
|
||||
- [Every](#Every)
|
||||
- [Equal](#Equal)
|
||||
- [EqualWith](#EqualWith)
|
||||
- [EqualUnordered](#EqualUnordered)
|
||||
- [Filter](#Filter)
|
||||
- [FilterConcurrent](#FilterConcurrent)
|
||||
- [Find<sup>deprecated</sup>](#Find)
|
||||
@@ -69,6 +70,7 @@ import (
|
||||
- [FlatMap](#FlatMap)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [ReverseCopy](#ReverseCopy)
|
||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||
- [ReduceConcurrent](#ReduceConcurrent)
|
||||
- [ReduceBy](#ReduceBy)
|
||||
@@ -77,6 +79,7 @@ import (
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
- [Shuffle](#Shuffle)
|
||||
- [ShuffleCopy](#ShuffleCopy)
|
||||
- [IsAscending](#IsAscending)
|
||||
- [IsDescending](#IsDescending)
|
||||
- [IsSorted](#IsSorted)
|
||||
@@ -106,6 +109,9 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -871,6 +877,37 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualUnordered">EqualUnordered</span>
|
||||
|
||||
<p>检查两个切片是否相等,元素数量相同,值相等,不考虑元素顺序。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func EqualUnordered[T comparable](slice1, slice2 []T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
|
||||
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
||||
@@ -915,7 +952,7 @@ func main() {
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/t_pkwerIRVx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1192,7 +1229,7 @@ func main() {
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/kT4XW7DKVoV)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1570,7 +1607,7 @@ func main() {
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/H1ehfPkPen0)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1725,6 +1762,38 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReverseCopy">ReverseCopy</span>
|
||||
|
||||
<p>反转切片中的元素顺序, 不改变原slice。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReverseCopy[T any](slice []T) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
|
||||
reversedStrs := slice.ReverseCopy(strs)
|
||||
|
||||
fmt.Println(reversedStrs)
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// [d c b a]
|
||||
// [a b c d]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果。</p>
|
||||
@@ -1771,7 +1840,7 @@ func main() {
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Tjwe6OtaG07)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1959,7 +2028,7 @@ func main() {
|
||||
|
||||
### <span id="Shuffle">Shuffle</span>
|
||||
|
||||
<p>随机打乱切片中的元素顺序</p>
|
||||
<p>随机打乱切片中的元素顺序。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1986,6 +2055,37 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ShuffleCopy">ShuffleCopy</span>
|
||||
|
||||
<p>随机打乱切片中的元素顺序, 不改变原切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ShuffleCopy[T any](slice []T) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
result := slice.ShuffleCopy(nums)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(nums)
|
||||
|
||||
// Output:
|
||||
// [3 1 5 4 2] (random order)
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsAscending">IsAscending</span>
|
||||
|
||||
<p>检查切片元素是否按升序排列。</p>
|
||||
@@ -2449,7 +2549,7 @@ func main() {
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UR323iZLDpv)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GY7JE4yikrl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2480,7 +2580,7 @@ func main() {
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rwSacr-ZHsR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2516,7 +2616,7 @@ func main() {
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wXZ7LcYRMGL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2967,7 +3067,7 @@ func main() {
|
||||
func Frequency[T comparable](slice []T) map[T]int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CW3UVNdUZOq)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2984,4 +3084,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>将切片元素用给定的分隔符连接成一个单一的字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/55ib3SB5fM2)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6QcUpcY4UMW)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# Stream
|
||||
|
||||
Stream 流,该包仅验证简单 stream 实现,功能有限。
|
||||
Stream流,该包仅验证简单stream实现,功能有限。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -48,6 +48,8 @@ import (
|
||||
- [NoneMatch](#NoneMatch)
|
||||
- [Count](#Count)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -938,3 +940,69 @@ func main() {
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tBV5Nc-XDX2)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CjeoNw2eac_G)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,8 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#ExtractContent)
|
||||
- [FindAllOccurrences](#FindAllOccurrences)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1547,7 +1549,7 @@ func main() {
|
||||
func Concat(length int, str ...string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gD52SZHr4Kp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1556,10 +1558,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result2 := strutil.Concat(11, "Go", " ", "Language")
|
||||
result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
@@ -1581,7 +1583,7 @@ func main() {
|
||||
func Ellipsis(str string, length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/i1vbdQiQVRR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1615,7 +1617,7 @@ func main() {
|
||||
func Shuffle(str string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iStFwBwyGY7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1639,7 +1641,7 @@ func main() {
|
||||
func Rotate(str string, shift int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Kf03iOeT5bd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1648,9 +1650,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Rotate("Hello", 0)
|
||||
result2 := Rotate("Hello", 1)
|
||||
result3 := Rotate("Hello", 2)
|
||||
result1 := strutil.Rotate("Hello", 0)
|
||||
result2 := strutil.Rotate("Hello", 1)
|
||||
result3 := strutil.Rotate("Hello", 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1673,7 +1675,7 @@ func main() {
|
||||
func TemplateReplace(template string, data map[string]string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cXSuFvyZqv9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1707,7 +1709,7 @@ func main() {
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1728,4 +1730,62 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>提取两个标记之间的内容。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Ay9UIk7Rum9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindAllOccurrences">FindAllOccurrences</span>
|
||||
|
||||
<p>返回子字符串在字符串中所有出现的位置。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FindAllOccurrences(str, substr string) []int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := strutil.FindAllOccurrences("ababab", "ab")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [0 2 4]
|
||||
}
|
||||
```
|
||||
@@ -324,7 +324,7 @@ func main() {
|
||||
func StartProcess(command string, args ...string) (int, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/5GVol6ryS_X)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -352,7 +352,7 @@ func main() {
|
||||
func StopProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/jJZhRYGGcmD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -386,7 +386,7 @@ func main() {
|
||||
func KillProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/XKmvV-ExBWa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -420,7 +420,7 @@ func main() {
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/NQDVywEYYx7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
|
||||
@@ -49,6 +49,7 @@ import (
|
||||
- [IsIp](#IsIp)
|
||||
- [IsIpV4](#IsIpV4)
|
||||
- [IsIpV6](#IsIpV6)
|
||||
- [IsIpPort](#IsIpPort)
|
||||
- [IsStrongPassword](#IsStrongPassword)
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
@@ -990,6 +991,43 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIpPort">IsIpPort</span>
|
||||
|
||||
<p>检查字符串是否是ip:port格式。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsIpPort(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIpPort("127.0.0.1:8080")
|
||||
result2 := validator.IsIpPort("[0:0:0:0:0:0:0:1]:8080")
|
||||
result3 := validator.IsIpPort(":8080")
|
||||
result4 := validator.IsIpPort("::0:0:0:0:")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsStrongPassword">IsStrongPassword</span>
|
||||
|
||||
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))。</p>
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -167,12 +168,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -489,3 +490,54 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>简单实现的java风格异常处理(try-catch-finally)。try catch不符合go错误处理风格,谨慎使用。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/D5Mdb0mRj0P)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error in try block")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -269,9 +270,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
> ⚠️ This function is deprecated. use `Ternary` instead.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
@@ -307,4 +344,3 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [ToUrlBase64](#ToUrlBase64)
|
||||
- [ToRawStdBase64](#ToRawStdBase64)
|
||||
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||
- [ToBigInt](#ToBigInt)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -372,7 +373,7 @@ import (
|
||||
|
||||
func main() {
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result, err := ToJson(aMap)
|
||||
result, err := convertor.ToJson(aMap)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
@@ -1116,4 +1117,34 @@ func main() {
|
||||
// map[a:1 b:2] false
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToBigInt">ToBigInt</span>
|
||||
|
||||
<p>Converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int</p>
|
||||
|
||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/X3itkCxwB_x)</span></b>
|
||||
|
||||
```go
|
||||
func ToBigInt[T any](v T) (*big.Int, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 9876543210
|
||||
bigInt, _ := convertor.ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
```
|
||||
@@ -70,6 +70,8 @@ import (
|
||||
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||
- [RsaSign](#RsaSign)
|
||||
- [RsaVerifySign](#RsaVerifySign)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -391,7 +393,7 @@ func main() {
|
||||
func AesGcmEncrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -425,7 +427,7 @@ func main() {
|
||||
func AesGcmDecrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1061,13 +1063,13 @@ import (
|
||||
|
||||
func main() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||
// Output:
|
||||
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1124,10 +1126,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5StringWithBase64("hello")
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1153,10 +1155,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1182,10 +1184,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1268,10 +1270,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha1WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
// Output:
|
||||
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1328,10 +1330,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha256WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||
// Output:
|
||||
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1388,10 +1390,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha512WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||
// Output:
|
||||
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1433,7 +1435,7 @@ func main() {
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uef0q1fz53I)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7_zo6mrx-eX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1470,7 +1472,7 @@ func main() {
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uef0q1fz53I)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7_zo6mrx-eX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1607,3 +1609,81 @@ func main() {
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaSign">RsaSign</span>
|
||||
|
||||
<p>Signs the data with RSA algorithm.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qhsbf8BJ6Mf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaVerifySign">RsaVerifySign</span>
|
||||
|
||||
<p>Verifies the signature of the data with RSA algorithm.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qhsbf8BJ6Mf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -24,9 +24,14 @@ import (
|
||||
## Index
|
||||
|
||||
- [AddDay](#AddDay)
|
||||
- [AddWeek](#AddWeek)
|
||||
- [AddMonth](#AddMonth)
|
||||
- [AddHour](#AddHour)
|
||||
- [AddMinute](#AddMinute)
|
||||
- [AddYear](#AddYear)
|
||||
- [AddDaySafe](#AddDaySafe)
|
||||
- [AddMonthSafe](#AddMonthSafe)
|
||||
- [AddYearSafe](#AddYearSafe)
|
||||
- [BeginOfMinute](#BeginOfMinute)
|
||||
- [BeginOfHour](#BeginOfHour)
|
||||
- [BeginOfDay](#BeginOfDay)
|
||||
@@ -68,6 +73,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -108,7 +116,7 @@ import (
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddDay(t time.Time, day int64) time.Time
|
||||
func AddDay(t time.Time, days int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
||||
@@ -123,20 +131,89 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
tomorrow := datetime.AddDay(now, 1)
|
||||
diff1 := tomorrow.Sub(now)
|
||||
after1Day := datetime.AddDay(date, 1)
|
||||
before1Day := datetime.AddDay(date, -1)
|
||||
|
||||
yesterday := datetime.AddDay(now, -1)
|
||||
diff2 := yesterday.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 24h0m0s
|
||||
// -24h0m0s
|
||||
// 2021-01-02 00:00:00
|
||||
// 2020-12-31 00:00:00
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddWeek">AddWeek</span>
|
||||
|
||||
<p>Add or sub weeks to time.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddWeek(t time.Time, weeks int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Weeks := datetime.AddWeek(date, 2)
|
||||
before2Weeks := datetime.AddWeek(date, -2)
|
||||
|
||||
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-01-15
|
||||
// 2020-12-18
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddMonth">AddMonth</span>
|
||||
|
||||
<p>Add or sub months to time.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddMonth(t time.Time, months int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after2Months := datetime.AddMonth(date, 2)
|
||||
before2Months := datetime.AddMonth(date, -2)
|
||||
|
||||
fmt.Println(after2Months.Format("2006-01-02"))
|
||||
fmt.Println(before2Months.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-03-01
|
||||
// 2020-11-01
|
||||
}
|
||||
```
|
||||
|
||||
@@ -162,20 +239,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Hours := datetime.AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
after2Hours := datetime.AddHour(date, 2)
|
||||
before2Hours := datetime.AddHour(date, -2)
|
||||
|
||||
before2Hours := datetime.AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2h0m0s
|
||||
// -2h0m0s
|
||||
// 2021-01-01 02:00:00
|
||||
// 2020-12-31 22:00:00
|
||||
}
|
||||
```
|
||||
|
||||
@@ -201,20 +275,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||
|
||||
after2Minutes := datetime.AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
after2Minutes := datetime.AddMinute(date, 2)
|
||||
before2Minutes := datetime.AddMinute(date, -2)
|
||||
|
||||
before2Minutes := datetime.AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// Output:
|
||||
// 2m0s
|
||||
// -2m0s
|
||||
// 2021-01-01 00:02:00
|
||||
// 2020-12-31 23:58:00
|
||||
}
|
||||
```
|
||||
|
||||
@@ -240,20 +311,137 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||
|
||||
after1Year := datetime.AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
after2Years := AddYear(date, 2)
|
||||
before2Years := AddYear(date, -2)
|
||||
|
||||
before1Year := datetime.AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(after2Years.Format("2006-01-02"))
|
||||
fmt.Println(before2Years.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
// 2023-01-01
|
||||
// 2019-01-01
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddDaySafe">AddDaySafe</span>
|
||||
|
||||
<p>Add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddDaySafe(t time.Time, days int) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result1 := datetime.AddDaySafe(leapYearDate1, 1)
|
||||
|
||||
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||
result2 := datetime.AddDaySafe(leapYearDate2, -1)
|
||||
|
||||
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||
result3 := datetime.AddDaySafe(nonLeapYearDate1, 1)
|
||||
|
||||
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||
result4 := datetime.AddDaySafe(nonLeaYearDate2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
fmt.Println(result3.Format("2006-01-02"))
|
||||
fmt.Println(result4.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2024-03-01
|
||||
// 2024-02-29
|
||||
// 2025-03-01
|
||||
// 2025-02-28
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddMonthSafe">AddMonthSafe</span>
|
||||
|
||||
<p>Add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddMonthSafe(t time.Time, months int) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||
result1 := datetime.AddMonthSafe(date1, 1)
|
||||
|
||||
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||
result2 := datetime.AddMonthSafe(date2, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2025-02-28
|
||||
// 2024-01-29
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddYearSafe">AddYearSafe</span>
|
||||
|
||||
<p>Add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AddYearSafe(t time.Time, years int) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||
|
||||
result1 := datetime.AddYearSafe(date, 1)
|
||||
result2 := datetime.AddYearSafe(date, -1)
|
||||
|
||||
fmt.Println(result1.Format("2006-01-02"))
|
||||
fmt.Println(result2.Format("2006-01-02"))
|
||||
|
||||
// Output:
|
||||
// 2021-02-28
|
||||
// 2019-02-28
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1339,7 +1527,7 @@ import (
|
||||
func main() {
|
||||
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
||||
|
||||
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1480,7 +1668,7 @@ func main() {
|
||||
func TrackFuncTime(pre time.Time) func()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/QBSEdfXHPTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1512,7 +1700,7 @@ func main() {
|
||||
func DaysBetween(start, end time.Time) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qD6qGb3TbOy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1545,7 +1733,7 @@ func main() {
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/6kHBpAxD9ZC)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1571,4 +1759,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>Returns the earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/MCIDvHNOGGb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>Returns the latest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/9m6JMk1LB7-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>Returns the latest and earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rbW51cDtM_2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
401
docs/en/api/packages/eventbus.md
Normal file
401
docs/en/api/packages/eventbus.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# EventBus
|
||||
|
||||
EventBus is an event bus used for handling events within an application.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go](https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [NewEventBus](#NewEventBus)
|
||||
- [Subscribe](#Subscribe)
|
||||
- [Unsubscribe](#Unsubscribe)
|
||||
- [Publish](#Publish)
|
||||
- [ClearListeners](#ClearListeners)
|
||||
- [ClearListenersByTopic](#ClearListenersByTopic)
|
||||
- [GetListenersCount](#GetListenersCount)
|
||||
- [GetAllListenersCount](#GetAllListenersCount)
|
||||
- [GetEvents](#GetEvents)
|
||||
- [SetErrorHandler](#SetErrorHandler)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="NewEventBus">NewEventBus</span>
|
||||
|
||||
<p>Create an EventBus instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewEventBus[T any]() *EventBus[T]
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Subscribe">Subscribe</span>
|
||||
|
||||
<p>Subscribes to an event with a specific event topic and listener function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
filter := func(eventData int) bool {
|
||||
return eventData == 1
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, filter)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Unsubscribe">Unsubscribe</span>
|
||||
|
||||
<p>Unsubscribes from an event with a specific event topic and listener function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T))
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Unsubscribe("event1", listener)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Publish">Publish</span>
|
||||
|
||||
<p>Publishes an event with a specific event topic and data payload.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) Publish(event Event[T])
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ClearListeners">ClearListeners</span>
|
||||
|
||||
<p>Clears all the listeners.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) ClearListeners()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListeners()
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ClearListenersByTopic">ClearListenersByTopic</span>
|
||||
|
||||
<p>Clears all the listeners by topic.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) ClearListenersByTopic(topic string)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListenersByTopic("event1")
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetListenersCount">GetListenersCount</span>
|
||||
|
||||
<p>Returns the number of listeners for a specific event topic.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetListenersCount(topic string) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetListenersCount("event1")
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetAllListenersCount">GetAllListenersCount</span>
|
||||
|
||||
<p>Returns the total number of all listeners.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetAllListenersCount() int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetAllListenersCount()
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetEvents">GetEvents</span>
|
||||
|
||||
<p>Returns all the events topics.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) GetEvents() []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
events := eb.GetEvents()
|
||||
|
||||
for _, event := range events {
|
||||
fmt.Println(event)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// event1
|
||||
// event2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SetErrorHandler">SetErrorHandler</span>
|
||||
|
||||
<p>Sets the error handler function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (eb *EventBus[T]) SetErrorHandler(handler func(err error))
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/eventbus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
eb := eventbus.NewEventBus[int]()
|
||||
|
||||
eb.SetErrorHandler(func(err error) {
|
||||
fmt.Println(err)
|
||||
})
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
panic("error")
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// error
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1074,4 +1075,37 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>Get the version of exe or dll file on windows.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/iLRrDBhE38E)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(v)
|
||||
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -204,7 +204,7 @@ func main() {
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func())
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/-dGFrYn_1Zi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -752,7 +752,7 @@ func main() {
|
||||
func Throttle(fn func(), interval time.Duration) func()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/HpoMov-tJSN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -1167,7 +1167,7 @@ func main() {
|
||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V]
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1206,7 +1206,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1245,7 +1245,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1285,7 +1285,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Delete(key K)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/5bIi4yaZ3K-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1321,7 +1321,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Clear()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8LwoJyEfuFr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1360,7 +1360,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ty57XSimpoe)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1400,7 +1400,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rQMjp1yQmpa)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1417,12 +1417,12 @@ func main() {
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
frontElement, ok := om.Front()
|
||||
fmt.Println(frontElement)
|
||||
backElement, ok := om.Back()
|
||||
fmt.Println(backElement)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// {a 1}
|
||||
// {c 3}
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1437,7 +1437,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/U-KpORhc7LZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1476,7 +1476,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Keys() []K
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Vv_y9ExKclA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1512,7 +1512,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Values() []V
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/TWj5n1-PUfx)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1548,7 +1548,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Elements() []struct
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/4BHG4kKz6bB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1584,7 +1584,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/cLe6z2VX5N-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1620,7 +1620,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/QuwqqnzwDNX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1662,7 +1662,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tlq2tdvicPt)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1703,7 +1703,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8Q0ssg6hZzO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1741,7 +1741,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/N7hjD_alZPq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1752,7 +1752,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1780,7 +1780,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/C-wAwydIAC7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1791,7 +1791,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1817,7 +1817,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8C3MvJ3-mut)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1837,6 +1837,7 @@ func main() {
|
||||
fmt.Println(om.Elements())
|
||||
|
||||
// Output:
|
||||
// [{a 1} {b 2} {c 3}]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2256,7 +2257,7 @@ func main() {
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/PVdmBSnm6P_W)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -2274,7 +2275,9 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKey(m)
|
||||
result := maputil.SortByKey(m, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
@@ -2293,7 +2296,7 @@ func main() {
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -52,6 +52,10 @@ import (
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
- [Div](#Div)
|
||||
- [Variance](#Variance)
|
||||
- [StdDev](#StdDev)
|
||||
- [Permutation](#Permutation)
|
||||
- [Combination](#Combination)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -64,7 +68,7 @@ import (
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Vv7LBwER-pz)</span></b>
|
||||
@@ -87,7 +91,7 @@ func main() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
@@ -1161,4 +1165,136 @@ func main() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Variance">Variance</span>
|
||||
|
||||
<p>Returns the variance of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uHuV4YgXf8F)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := mathutil.Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StdDev">StdDev</span>
|
||||
|
||||
<p>Returns the standard deviation of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/FkNZDXvHD2l)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := mathutil.TruncRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Permutation">Permutation</span>
|
||||
|
||||
<p>Calculates P(n, k).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Permutation(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/MgobwH_FOxj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Permutation(5, 3)
|
||||
result2 := mathutil.Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Combination">Combination</span>
|
||||
|
||||
<p>Calculates C(n, k).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Combination(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ENFQRDQUFi9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Combination(5, 3)
|
||||
result2 := mathutil.Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -133,7 +134,7 @@ func main() {
|
||||
func RandFromGivenSlice[T any](slice []T) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UrkWueF6yYo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -160,7 +161,7 @@ func main() {
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/68UikN9d6VT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -171,8 +172,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange"}
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange"}
|
||||
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
|
||||
fmt.Println(chosen3goods)
|
||||
}
|
||||
```
|
||||
@@ -346,7 +349,7 @@ func main() {
|
||||
func RandIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GATTQ5xTEG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -452,7 +455,7 @@ func main() {
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/2_-PiDv3tGn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -481,7 +484,7 @@ func main() {
|
||||
func RandBool() bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/to6BLc26wBv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -507,7 +510,7 @@ func main() {
|
||||
func RandBoolSlice(length int) []bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/o-VSjPjnILI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -521,4 +524,30 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>Generates a random int number of specified length.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/oyZbuV7bu7b)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -43,6 +43,7 @@ import (
|
||||
- [DropRightWhile](#DropRightWhile)
|
||||
- [Equal](#Equal)
|
||||
- [EqualWith](#EqualWith)
|
||||
- [EqualUnordered](#EqualUnordered)
|
||||
- [Every](#Every)
|
||||
- [Filter](#Filter)
|
||||
- [FilterConcurrent](#FilterConcurrent)
|
||||
@@ -69,6 +70,7 @@ import (
|
||||
- [FlatMap](#FlatMap)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [ReverseCopy](#ReverseCopy)
|
||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||
- [ReduceConcurrent](#ReduceConcurrent)
|
||||
- [ReduceBy](#ReduceBy)
|
||||
@@ -77,6 +79,7 @@ import (
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
- [Shuffle](#Shuffle)
|
||||
- [ShuffleCopy](#ShuffleCopy)
|
||||
- [IsAscending](#IsAscending)
|
||||
- [IsDescending](#IsDescending)
|
||||
- [IsSorted](#IsSorted)
|
||||
@@ -106,6 +109,10 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -835,6 +842,37 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualUnordered">EqualUnordered</span>
|
||||
|
||||
<p>Checks if two slices are equal: the same length and all elements value are equal (unordered).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func EqualUnordered[T comparable](slice1, slice2 []T) bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Every">Every</span>
|
||||
|
||||
<p>Return true if all of the values in the slice pass the predicate function.</p>
|
||||
@@ -913,7 +951,7 @@ func main() {
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/t_pkwerIRVx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1190,7 +1228,7 @@ func main() {
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/kT4XW7DKVoV)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1567,7 +1605,7 @@ func main() {
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/H1ehfPkPen0)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1720,6 +1758,38 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReverseCopy">ReverseCopy</span>
|
||||
|
||||
<p>Return a new slice of element order is reversed to the given slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ReverseCopy[T any](slice []T) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
|
||||
reversedStrs := slice.ReverseCopy(strs)
|
||||
|
||||
fmt.Println(reversedStrs)
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// [d c b a]
|
||||
// [a b c d]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>Reduce slice.</p>
|
||||
@@ -1766,7 +1836,7 @@ func main() {
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Tjwe6OtaG07)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1982,6 +2052,37 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ShuffleCopy">ShuffleCopy</span>
|
||||
|
||||
<p>Return a new slice with elements shuffled.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ShuffleCopy[T any](slice []T) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
result := slice.ShuffleCopy(nums)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(nums)
|
||||
|
||||
// Output:
|
||||
// [3 1 5 4 2] (random order)
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsAscending">IsAscending</span>
|
||||
|
||||
<p>Checks if a slice is ascending order.</p>
|
||||
@@ -2445,7 +2546,7 @@ func main() {
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UR323iZLDpv)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GY7JE4yikrl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2476,7 +2577,7 @@ func main() {
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rwSacr-ZHsR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2512,7 +2613,7 @@ func main() {
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Runs](https://go.dev/play/p/wXZ7LcYRMGL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2962,7 +3063,7 @@ func main() {
|
||||
func Frequency[T comparable](slice []T) map[T]int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/CW3UVNdUZOq)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2979,4 +3080,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>Joins the slice elements into a single string with the given separator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/55ib3SB5fM2)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>Concats the elements of a slice into a single value using the provided separator and connector function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/6QcUpcY4UMW)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -939,3 +939,69 @@ func main() {
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>Returns the index of the first occurrence of the specified element in this stream, or -1 if this stream does not contain the element.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tBV5Nc-XDX2)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>Returns the index of the last occurrence of the specified element in this stream, or -1 if this stream does not contain the element.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/CjeoNw2eac_G)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,9 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#ExtractContent)
|
||||
- [FindAllOccurrences](#FindAllOccurrences)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1549,7 +1552,7 @@ func main() {
|
||||
func Concat(length int, str ...string) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/gD52SZHr4Kp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1561,6 +1564,7 @@ func main() {
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result2 := strutil.Concat(11, "Go", " ", "Language")
|
||||
result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
@@ -1582,7 +1586,7 @@ func main() {
|
||||
func Ellipsis(str string, length int) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/i1vbdQiQVRR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1616,7 +1620,7 @@ func main() {
|
||||
func Shuffle(str string) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/iStFwBwyGY7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1640,7 +1644,7 @@ func main() {
|
||||
func Rotate(str string, shift int) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Kf03iOeT5bd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1673,7 +1677,7 @@ func main() {
|
||||
func TemplateReplace(template string, data map[string]string string
|
||||
```
|
||||
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/cXSuFvyZqv9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1707,7 +1711,7 @@ func main() {
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1728,4 +1732,62 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>Extracts the content between the start and end strings in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Ay9UIk7Rum9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindAllOccurrences">FindAllOccurrences</span>
|
||||
|
||||
<p>Returns the positions of all occurrences of a substring in a string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FindAllOccurrences(str, substr string) []int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := strutil.FindAllOccurrences("ababab", "ab")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [0 2 4]
|
||||
}
|
||||
```
|
||||
@@ -325,7 +325,7 @@ func main() {
|
||||
func StartProcess(command string, args ...string) (int, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/5GVol6ryS_X)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -353,7 +353,7 @@ func main() {
|
||||
func StopProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/jJZhRYGGcmD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -387,7 +387,7 @@ func main() {
|
||||
func KillProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/XKmvV-ExBWa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -421,7 +421,7 @@ func main() {
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/NQDVywEYYx7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
|
||||
@@ -49,6 +49,7 @@ import (
|
||||
- [IsIp](#IsIp)
|
||||
- [IsIpV4](#IsIpV4)
|
||||
- [IsIpV6](#IsIpV6)
|
||||
- [IsIpPort](#IsIpPort)
|
||||
- [IsStrongPassword](#IsStrongPassword)
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
@@ -992,6 +993,43 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIpPort">IsIpPort</span>
|
||||
|
||||
<p>Check if the string is ip:port</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsIpPort(str string) bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIpPort("127.0.0.1:8080")
|
||||
result2 := validator.IsIpPort("[0:0:0:0:0:0:0:1]:8080")
|
||||
result3 := validator.IsIpPort(":8080")
|
||||
result4 := validator.IsIpPort("::0:0:0:0:")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsStrongPassword">IsStrongPassword</span>
|
||||
|
||||
<p>Check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?gt<)).</p>
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -166,12 +167,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -487,3 +488,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>Simple simulation of Java-style try-catch. It does not align with Go's error-handling philosophy. It is recommended to use it with caution.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/D5Mdb0mRj0P)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error message ")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
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.4.1. </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.4.6. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Sponsor me
|
||||
|
||||
<b>Hello, I am a software developer and have been engaged in development work for 13 years. Love open source software. And be willing to put in the energy for it. I am the creator of project [lancet](https://github.com/duke-git/lancet). Since Lancet was released as open source two years ago, it has been used by more than 1,000 internal and external projects. lancet will always be free for all users. Your support is a powerful encouragement for me to continue my struggle. Thanks! You can use WeChat to scans the following QR code or clicks the following sponsor button to initiate sponsorship.</b>
|
||||
<b>Hello, I am a software developer and have been engaged in development work for 15 years. Love open source software. And be willing to put in the energy for it. I am the creator of project [lancet](https://github.com/duke-git/lancet). Since Lancet was released as open source in 2021, it has been used by more than 1700 internal and external projects. lancet will always be free for all users. Your support is a powerful encouragement for me to continue my struggle. Thanks! You can use WeChat to scans the following QR code or clicks the following sponsor button to initiate sponsorship.</b>
|
||||
|
||||
<style>
|
||||
.sponsor-ctn {
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.1。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.6。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
### 赞助
|
||||
|
||||
<b>您好,我是一名软件开发者,从事开发工作 13 年。热爱软件开源。并愿意为此付出精力。是开源项目[lancet](https://github.com/duke-git/lancet)的作者。Lancet 自两年前开源发布以来,已有超过 1000 个内外部项目使用。lancet 一直会对所有用户免费。您的支持是对我继续奋斗的有力鼓励。谢谢! 微信扫描以下二维码或点击以下赞助按钮发起赞助。 </b>
|
||||
<b>您好,我是一名软件开发者,从事开发工作15年。热爱软件开源。并愿意为此付出精力。是开源项目[lancet](https://github.com/duke-git/lancet)的作者。Lancet自2021年前开源发布以来,已有超过1700个内外部项目使用。lancet一直会对所有用户免费。您的支持是对我继续奋斗的有力鼓励。谢谢! 微信扫描以下二维码或点击以下赞助按钮发起赞助。 </b>
|
||||
|
||||
<style>
|
||||
.sponsor-ctn {
|
||||
|
||||
194
eventbus/eventbus.go
Normal file
194
eventbus/eventbus.go
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright 2025 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package eventbus implements a simple event bus.
|
||||
package eventbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Event is the struct that is passed to the event listener, now it directly uses the generic Payload type.
|
||||
type Event[T any] struct {
|
||||
Topic string
|
||||
Payload T
|
||||
}
|
||||
|
||||
// EventBus is the struct that holds the listeners and the error handler.
|
||||
type EventBus[T any] struct {
|
||||
// listeners map[string][]*EventListener[T]
|
||||
listeners sync.Map
|
||||
mu sync.RWMutex
|
||||
errorHandler func(err error)
|
||||
}
|
||||
|
||||
// EventListener is the struct that holds the listener function and its priority.
|
||||
type EventListener[T any] struct {
|
||||
priority int
|
||||
listener func(eventData T)
|
||||
async bool
|
||||
filter func(eventData T) bool
|
||||
}
|
||||
|
||||
// NewEventBus creates a new EventBus.
|
||||
// Play: todo
|
||||
func NewEventBus[T any]() *EventBus[T] {
|
||||
return &EventBus[T]{
|
||||
listeners: sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe subscribes to an event with a specific event topic and listener function.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool) {
|
||||
eb.mu.Lock()
|
||||
defer eb.mu.Unlock()
|
||||
|
||||
el := &EventListener[T]{
|
||||
priority: priority,
|
||||
listener: listener,
|
||||
async: async,
|
||||
filter: filter,
|
||||
}
|
||||
|
||||
listenersInterface, _ := eb.listeners.LoadOrStore(topic, []*EventListener[T]{})
|
||||
listeners := listenersInterface.([]*EventListener[T])
|
||||
|
||||
listeners = append(listeners, el)
|
||||
sort.Slice(listeners, func(i, j int) bool {
|
||||
return listeners[i].priority > listeners[j].priority
|
||||
})
|
||||
|
||||
eb.listeners.Store(topic, listeners)
|
||||
}
|
||||
|
||||
// Unsubscribe unsubscribes from an event with a specific event topic and listener function.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T)) {
|
||||
eb.mu.Lock()
|
||||
defer eb.mu.Unlock()
|
||||
|
||||
listenersInterface, ok := eb.listeners.Load(topic)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
listeners := listenersInterface.([]*EventListener[T])
|
||||
listenerPtr := fmt.Sprintf("%p", listener)
|
||||
|
||||
var updatedListeners []*EventListener[T]
|
||||
for _, l := range listeners {
|
||||
if fmt.Sprintf("%p", l.listener) != listenerPtr {
|
||||
updatedListeners = append(updatedListeners, l)
|
||||
}
|
||||
}
|
||||
|
||||
eb.listeners.Store(topic, updatedListeners)
|
||||
}
|
||||
|
||||
// Publish publishes an event with a specific event topic and data payload.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) Publish(event Event[T]) {
|
||||
eb.mu.RLock()
|
||||
defer eb.mu.RUnlock()
|
||||
|
||||
listenersInterface, exists := eb.listeners.Load(event.Topic)
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
listeners := listenersInterface.([]*EventListener[T])
|
||||
|
||||
for _, listener := range listeners {
|
||||
if listener.filter != nil && !listener.filter(event.Payload) {
|
||||
continue
|
||||
}
|
||||
|
||||
if listener.async {
|
||||
go eb.publishToListener(listener, event)
|
||||
} else {
|
||||
eb.publishToListener(listener, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (eb *EventBus[T]) publishToListener(listener *EventListener[T], event Event[T]) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil && eb.errorHandler != nil {
|
||||
eb.errorHandler(fmt.Errorf("%v", r))
|
||||
}
|
||||
}()
|
||||
|
||||
listener.listener(event.Payload)
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the error handler function.
|
||||
func (eb *EventBus[T]) SetErrorHandler(handler func(err error)) {
|
||||
eb.errorHandler = handler
|
||||
}
|
||||
|
||||
// ClearListeners clears all the listeners.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) ClearListeners() {
|
||||
eb.mu.Lock()
|
||||
defer eb.mu.Unlock()
|
||||
|
||||
eb.listeners = sync.Map{}
|
||||
}
|
||||
|
||||
// ClearListenersByTopic clears all the listeners by topic.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) ClearListenersByTopic(topic string) {
|
||||
eb.mu.Lock()
|
||||
defer eb.mu.Unlock()
|
||||
|
||||
eb.listeners.Delete(topic)
|
||||
}
|
||||
|
||||
// GetListenersCount returns the number of listeners for a specific event topic.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) GetListenersCount(topic string) int {
|
||||
eb.mu.RLock()
|
||||
defer eb.mu.RUnlock()
|
||||
|
||||
listenersInterface, ok := eb.listeners.Load(topic)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
listeners := listenersInterface.([]*EventListener[T])
|
||||
return len(listeners)
|
||||
}
|
||||
|
||||
// GetAllListenersCount returns the total number of listeners.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) GetAllListenersCount() int {
|
||||
eb.mu.RLock()
|
||||
defer eb.mu.RUnlock()
|
||||
|
||||
count := 0
|
||||
eb.listeners.Range(func(key, value interface{}) bool {
|
||||
count += len(value.([]*EventListener[T]))
|
||||
return true
|
||||
})
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// GetEvents returns all the events topics.
|
||||
// Play: todo
|
||||
func (eb *EventBus[T]) GetEvents() []string {
|
||||
eb.mu.RLock()
|
||||
defer eb.mu.RUnlock()
|
||||
|
||||
var events []string
|
||||
|
||||
eb.listeners.Range(func(key, value interface{}) bool {
|
||||
events = append(events, key.(string))
|
||||
return true
|
||||
})
|
||||
|
||||
return events
|
||||
}
|
||||
229
eventbus/eventbus_example_test.go
Normal file
229
eventbus/eventbus_example_test.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package eventbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleEventBus_Subscribe() {
|
||||
eb := NewEventBus[string]()
|
||||
eb.Subscribe("event1", func(eventData string) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleEventBus_Unsubscribe() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Unsubscribe("event1", listener)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleEventBus_Subscribe_withFilter() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
filter := func(eventData int) bool {
|
||||
return eventData == 1
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, filter)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleEventBus_Subscribe_withPriority() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 1, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleEventBus_Subscribe_async() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(eventData)
|
||||
wg.Done()
|
||||
}, true, 1, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
wg.Wait()
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleEventBus_Publish() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
fmt.Println(eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleEventBus() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleEventBus_ClearListeners() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListeners()
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleEventBus_ClearListenersByTopic() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.ClearListenersByTopic("event1")
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
fmt.Println(receivedData)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleEventBus_GetListenersCount() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetListenersCount("event1")
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleEventBus_SetErrorHandler() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.SetErrorHandler(func(err error) {
|
||||
fmt.Println(err)
|
||||
})
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
panic("error")
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
// Output:
|
||||
// error
|
||||
}
|
||||
|
||||
func ExampleEventBus_GetAllListenersCount() {
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
count := eb.GetAllListenersCount()
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleEventBus_GetEvents() {
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
events := eb.GetEvents()
|
||||
|
||||
for _, event := range events {
|
||||
fmt.Println(event)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// event1
|
||||
// event2
|
||||
}
|
||||
219
eventbus/eventbus_test.go
Normal file
219
eventbus/eventbus_test.go
Normal file
@@ -0,0 +1,219 @@
|
||||
package eventbus
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestEventBus_Subscribe(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_Subscribe")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
assert.Equal(1, eventData)
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
}
|
||||
|
||||
func TestEventBus_Unsubscribe(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_Unsubscribe")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, nil)
|
||||
eb.Unsubscribe("event1", listener)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
assert.Equal(0, receivedData)
|
||||
}
|
||||
|
||||
func TestEventBus_Subscribe_withFilter(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_Subscribe_withFilter")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData := 0
|
||||
listener := func(eventData int) {
|
||||
receivedData = eventData
|
||||
}
|
||||
|
||||
filter := func(eventData int) bool {
|
||||
return eventData == 1
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener, false, 0, filter)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||
|
||||
assert.Equal(1, receivedData)
|
||||
}
|
||||
|
||||
func TestEventBus_Subscribe_withPriority(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_Subscribe_withPriority")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
var receivedData []int
|
||||
listener1 := func(eventData int) {
|
||||
receivedData = append(receivedData, 1)
|
||||
}
|
||||
|
||||
listener2 := func(eventData int) {
|
||||
receivedData = append(receivedData, 2)
|
||||
}
|
||||
|
||||
eb.Subscribe("event1", listener1, false, 1, nil)
|
||||
eb.Subscribe("event1", listener2, false, 2, nil)
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
|
||||
assert.Equal([]int{2, 1}, receivedData)
|
||||
}
|
||||
|
||||
func TestEventBus_Subscribe_async(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_Subscribe_async")
|
||||
|
||||
eb := NewEventBus[string]()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
eb.Subscribe("event1", func(eventData string) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
assert.Equal("hello", eventData)
|
||||
wg.Done()
|
||||
}, true, 1, nil)
|
||||
|
||||
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestEventBus_ErrorHandler(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_ErrorHandler")
|
||||
|
||||
eb := NewEventBus[string]()
|
||||
|
||||
eb.SetErrorHandler(func(err error) {
|
||||
assert.Equal("error", err.Error())
|
||||
})
|
||||
|
||||
eb.Subscribe("event1", func(eventData string) {
|
||||
panic("error")
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||
}
|
||||
|
||||
func TestEventBus_ClearListeners(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_ClearListeners")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData1 := 0
|
||||
receivedData2 := 0
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
receivedData1 = eventData
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Subscribe("event2", func(eventData int) {
|
||||
receivedData2 = eventData
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.ClearListeners()
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||
|
||||
assert.Equal(0, receivedData1)
|
||||
assert.Equal(0, receivedData2)
|
||||
}
|
||||
|
||||
func TestEventBus_ClearListenersByTopic(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_ClearListenersByTopic")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
receivedData1 := 0
|
||||
receivedData2 := 0
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {
|
||||
receivedData1 = eventData
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.Subscribe("event2", func(eventData int) {
|
||||
receivedData2 = eventData
|
||||
}, false, 0, nil)
|
||||
|
||||
eb.ClearListenersByTopic("event1")
|
||||
|
||||
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||
eb.Publish(Event[int]{Topic: "event2", Payload: 2})
|
||||
|
||||
assert.Equal(0, receivedData1)
|
||||
assert.Equal(2, receivedData2)
|
||||
}
|
||||
|
||||
func TestEventBus_GetListenersCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_GetListenersCount")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
assert.Equal(2, eb.GetListenersCount("event1"))
|
||||
assert.Equal(1, eb.GetListenersCount("event2"))
|
||||
}
|
||||
|
||||
func TestEventBus_GetAllListenersCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_GetAllListenersCount")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
assert.Equal(3, eb.GetAllListenersCount())
|
||||
}
|
||||
|
||||
func TestEventBus_GetEvents(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEventBus_GetEvents")
|
||||
|
||||
eb := NewEventBus[int]()
|
||||
|
||||
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||
|
||||
events := eb.GetEvents()
|
||||
|
||||
assert.Equal(2, len(events))
|
||||
assert.EqualValues([]string{"event1", "event2"}, events)
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// FileReader is a reader supporting offset seeking and reading one
|
||||
@@ -422,8 +424,15 @@ func UnZip(zipFile string, destPath string) error {
|
||||
defer zipReader.Close()
|
||||
|
||||
for _, f := range zipReader.File {
|
||||
decodeName := f.Name
|
||||
if f.Flags == 0 {
|
||||
i := bytes.NewReader([]byte(f.Name))
|
||||
decoder := transform.NewReader(i, simplifiedchinese.GB18030.NewDecoder())
|
||||
content, _ := io.ReadAll(decoder)
|
||||
decodeName = string(content)
|
||||
}
|
||||
// issue#62: fix ZipSlip bug
|
||||
path, err := safeFilepathJoin(destPath, f.Name)
|
||||
path, err := safeFilepathJoin(destPath, decodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -820,6 +829,7 @@ func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingF
|
||||
if len(headers) > 0 {
|
||||
columnHeaders = headers[0]
|
||||
} else {
|
||||
columnHeaders = make([]string, 0, len(records[0]))
|
||||
for key := range records[0] {
|
||||
columnHeaders = append(columnHeaders, key)
|
||||
}
|
||||
@@ -833,7 +843,7 @@ func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingF
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
var row []string
|
||||
row := make([]string, 0, len(columnHeaders))
|
||||
for _, h := range columnHeaders {
|
||||
row = append(row, fmt.Sprintf("%v", record[h]))
|
||||
}
|
||||
|
||||
@@ -192,6 +192,27 @@ func ExampleListFileNames() {
|
||||
// [assert.go assert_test.go error_join.go]
|
||||
}
|
||||
|
||||
func ExampleMiMeType() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
@@ -214,24 +235,20 @@ func ExampleZip() {
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
zipFile := "./testdata/file.go.zip"
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
err := UnZip(zipFile, "./testdata")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
exist := IsExist("./testdata/file.go")
|
||||
fmt.Println(exist)
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
os.Remove("./testdata/file.go")
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleZipAppendEntry() {
|
||||
|
||||
83
fileutil/file_windows.go
Normal file
83
fileutil/file_windows.go
Normal file
@@ -0,0 +1,83 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// tagVS_FIXEDFILEINFO 参考结构体https://learn.microsoft.com/zh-cn/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||
type tagVS_FIXEDFILEINFO struct {
|
||||
Signature uint32
|
||||
StructVersion uint32
|
||||
FileVersionMS uint32
|
||||
FileVersionLS uint32
|
||||
ProductVersionMS uint32
|
||||
ProductVersionLS uint32
|
||||
FileFlagsMask uint32
|
||||
FileFlags uint32
|
||||
FileOS uint32
|
||||
FileType uint32
|
||||
FileSubtype uint32
|
||||
FileDateMS uint32
|
||||
FileDateLS uint32
|
||||
}
|
||||
|
||||
// GetExeOrDllVersion get the version of exe or dll file on windows.
|
||||
// Play: https://go.dev/play/p/iLRrDBhE38E
|
||||
func GetExeOrDllVersion(filePath string) (string, error) {
|
||||
// 加载系统dll
|
||||
versionDLL := syscall.NewLazyDLL("version.dll")
|
||||
getFileVersionInfoSize := versionDLL.NewProc("GetFileVersionInfoSizeW")
|
||||
getFileVersionInfo := versionDLL.NewProc("GetFileVersionInfoW")
|
||||
verQueryValue := versionDLL.NewProc("VerQueryValueW")
|
||||
|
||||
// 转换路径为UTF-16
|
||||
filePathPtr, err := syscall.UTF16PtrFromString(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
|
||||
// 获取version信息大小
|
||||
size, _, err := getFileVersionInfoSize.Call(
|
||||
uintptr(unsafe.Pointer(filePathPtr)),
|
||||
0,
|
||||
)
|
||||
if size == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information size: %v", err)
|
||||
}
|
||||
|
||||
// 加载version信息
|
||||
data := make([]byte, size)
|
||||
ret, _, err := getFileVersionInfo.Call(uintptr(unsafe.Pointer(filePathPtr)), 0, size, uintptr(unsafe.Pointer(&data[0])))
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information: %v", err)
|
||||
}
|
||||
|
||||
// 查询version信息
|
||||
var fixedInfo *tagVS_FIXEDFILEINFO
|
||||
var fixedInfoLen uint32
|
||||
u16, err := syscall.UTF16PtrFromString(`\`)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
ret, _, err = verQueryValue.Call(
|
||||
uintptr(unsafe.Pointer(&data[0])),
|
||||
uintptr(unsafe.Pointer(u16)),
|
||||
uintptr(unsafe.Pointer(&fixedInfo)),
|
||||
uintptr(unsafe.Pointer(&fixedInfoLen)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to query version information: %v", err)
|
||||
}
|
||||
|
||||
// 转换结构体
|
||||
major := fixedInfo.FileVersionMS >> 16
|
||||
minor := fixedInfo.FileVersionMS & 0xFFFF
|
||||
build := fixedInfo.FileVersionLS >> 16
|
||||
revision := fixedInfo.FileVersionLS & 0xFFFF
|
||||
|
||||
return fmt.Sprintf("%d.%d.%d.%d", major, minor, build, revision), nil
|
||||
}
|
||||
13
fileutil/file_windows_test.go
Normal file
13
fileutil/file_windows_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetExeOrDllVersion(t *testing.T) {
|
||||
v, err := GetExeOrDllVersion(`C:\Windows\System32\cmd.exe`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(v)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ func Debounced(fn func(), delay time.Duration) func() {
|
||||
}
|
||||
|
||||
// Debounce creates a debounced version of the provided function.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/-dGFrYn_1Zi
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func()) {
|
||||
var (
|
||||
timer *time.Timer
|
||||
@@ -127,7 +127,7 @@ func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func
|
||||
|
||||
// Throttle creates a throttled version of the provided function.
|
||||
// The returned function guarantees that it will only be invoked at most once per interval.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/HpoMov-tJSN
|
||||
func Throttle(fn func(), interval time.Duration) func() {
|
||||
var (
|
||||
timer *time.Timer
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1,6 +1,4 @@
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
|
||||
@@ -455,7 +455,7 @@ func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V {
|
||||
}
|
||||
|
||||
// SortByKey sorts the map by its keys and returns a new map with sorted keys.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/PVdmBSnm6P_W
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V, less func(a, b K) bool) (sortedKeysMap map[K]V) {
|
||||
keys := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
@@ -659,7 +659,7 @@ func convertMap(src reflect.Value, dst reflect.Value) error {
|
||||
}
|
||||
|
||||
// GetOrDefault returns the value of the given key or a default value if the key is not present.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/99QjSYSBdiM
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V {
|
||||
if v, ok := m[key]; ok {
|
||||
return v
|
||||
|
||||
@@ -29,13 +29,13 @@ func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
||||
}
|
||||
|
||||
// Sets the given key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Y4ZJ_oOc1FU
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
if elem, ok := om.index[key]; ok {
|
||||
elem.Value = value
|
||||
om.data[key] = value
|
||||
om.order.MoveToBack(elem)
|
||||
|
||||
return
|
||||
@@ -48,7 +48,7 @@ func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||
}
|
||||
|
||||
// Get returns the value for the given key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Y4ZJ_oOc1FU
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -59,7 +59,7 @@ func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
||||
}
|
||||
|
||||
// Delete deletes the given key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/5bIi4yaZ3K-
|
||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -72,7 +72,7 @@ func (om *OrderedMap[K, V]) Delete(key K) {
|
||||
}
|
||||
|
||||
// Clear clears the map.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8LwoJyEfuFr
|
||||
func (om *OrderedMap[K, V]) Clear() {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -83,7 +83,7 @@ func (om *OrderedMap[K, V]) Clear() {
|
||||
}
|
||||
|
||||
// Front returns the first key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/ty57XSimpoe
|
||||
func (om *OrderedMap[K, V]) Front() (struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -111,7 +111,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}
|
||||
|
||||
// Back returns the last key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rQMjp1yQmpa
|
||||
func (om *OrderedMap[K, V]) Back() (struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -139,7 +139,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}
|
||||
|
||||
// Range calls the given function for each key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/U-KpORhc7LZ
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -155,7 +155,7 @@ func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool) {
|
||||
}
|
||||
|
||||
// Keys returns the keys in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Vv_y9ExKclA
|
||||
func (om *OrderedMap[K, V]) Keys() []K {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -170,7 +170,7 @@ func (om *OrderedMap[K, V]) Keys() []K {
|
||||
}
|
||||
|
||||
// Values returns the values in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/TWj5n1-PUfx
|
||||
func (om *OrderedMap[K, V]) Values() []V {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -186,7 +186,7 @@ func (om *OrderedMap[K, V]) Values() []V {
|
||||
}
|
||||
|
||||
// Len returns the number of key-value pairs.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/cLe6z2VX5N-
|
||||
func (om *OrderedMap[K, V]) Len() int {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -195,7 +195,7 @@ func (om *OrderedMap[K, V]) Len() int {
|
||||
}
|
||||
|
||||
// Contains returns true if the given key exists.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/QuwqqnzwDNX
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -206,7 +206,7 @@ func (om *OrderedMap[K, V]) Contains(key K) bool {
|
||||
}
|
||||
|
||||
// Elements returns the key-value pairs in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/4BHG4kKz6bB
|
||||
func (om *OrderedMap[K, V]) Elements() []struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -232,7 +232,7 @@ func (om *OrderedMap[K, V]) Elements() []struct {
|
||||
}
|
||||
|
||||
// Iter returns a channel that yields key-value pairs in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/tlq2tdvicPt
|
||||
func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -262,7 +262,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
|
||||
// ReverseIter returns a channel that yields key-value pairs in reverse order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8Q0ssg6hZzO
|
||||
func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -292,7 +292,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
|
||||
// SortByValue sorts the map by key given less function.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/N7hjD_alZPq
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -315,7 +315,7 @@ func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool) {
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/C-wAwydIAC7
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -334,7 +334,7 @@ func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8C3MvJ3-mut
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
@@ -19,6 +19,10 @@ func TestOrderedMap_Set_Get(t *testing.T) {
|
||||
assert.Equal(1, val)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
om.Set("a", 2)
|
||||
val, _ = om.Get("a")
|
||||
assert.Equal(2, val)
|
||||
|
||||
val, ok = om.Get("d")
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(0, val)
|
||||
|
||||
@@ -44,14 +44,19 @@ func Fibonacci(first, second, n int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// Factorial calculate x!.
|
||||
// Factorial calculate n!.
|
||||
// Play: https://go.dev/play/p/tt6LdOK67Nx
|
||||
func Factorial(x uint) uint {
|
||||
var f uint = 1
|
||||
for ; x > 1; x-- {
|
||||
f *= x
|
||||
func Factorial(n uint) uint {
|
||||
if n == 0 || n == 1 {
|
||||
return 1
|
||||
}
|
||||
return f
|
||||
|
||||
result := uint(1)
|
||||
for i := uint(2); i <= n; i++ {
|
||||
result *= i
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Percent calculate the percentage of value to total.
|
||||
@@ -140,10 +145,14 @@ func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||
|
||||
// Max return max value of numbers.
|
||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
max := numbers[0]
|
||||
func Max[T constraints.Ordered](items ...T) T {
|
||||
if len(items) < 1 {
|
||||
panic("mathutil.Max: empty list")
|
||||
}
|
||||
|
||||
for _, v := range numbers {
|
||||
max := items[0]
|
||||
|
||||
for _, v := range items {
|
||||
if max < v {
|
||||
max = v
|
||||
}
|
||||
@@ -176,10 +185,14 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
|
||||
// Min return min value of numbers.
|
||||
// Play: https://go.dev/play/p/21BER_mlGUj
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
min := numbers[0]
|
||||
func Min[T constraints.Ordered](items ...T) T {
|
||||
if len(items) < 1 {
|
||||
panic("mathutil.min: empty list")
|
||||
}
|
||||
|
||||
for _, v := range numbers {
|
||||
min := items[0]
|
||||
|
||||
for _, v := range items {
|
||||
if min > v {
|
||||
min = v
|
||||
}
|
||||
@@ -224,14 +237,12 @@ func Sum[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
|
||||
// Average return average value of numbers.
|
||||
// Play: https://go.dev/play/p/Vv7LBwER-pz
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
var sum T
|
||||
n := T(len(numbers))
|
||||
|
||||
for _, v := range numbers {
|
||||
sum += v
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64 {
|
||||
var sum float64
|
||||
for _, num := range numbers {
|
||||
sum += float64(num)
|
||||
}
|
||||
return sum / n
|
||||
return sum / float64(len(numbers))
|
||||
}
|
||||
|
||||
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||
@@ -395,3 +406,54 @@ func Abs[T constraints.Integer | constraints.Float](x T) T {
|
||||
func Div[T constraints.Float | constraints.Integer](x T, y T) float64 {
|
||||
return float64(x) / float64(y)
|
||||
}
|
||||
|
||||
// Variance returns the variance of numbers.
|
||||
// Play: https://go.dev/play/p/uHuV4YgXf8F
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||
n := len(numbers)
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
avg := Average(numbers...)
|
||||
var sum float64
|
||||
|
||||
for _, v := range numbers {
|
||||
sum += (float64(v) - avg) * (float64(v) - avg)
|
||||
}
|
||||
|
||||
return sum / float64(n)
|
||||
}
|
||||
|
||||
// StdDev returns the standard deviation of numbers.
|
||||
// Play: https://go.dev/play/p/FkNZDXvHD2l
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||
return math.Sqrt(Variance(numbers))
|
||||
}
|
||||
|
||||
// Permutation calculate P(n, k).
|
||||
// Play: https://go.dev/play/p/MgobwH_FOxj
|
||||
func Permutation(n, k uint) uint {
|
||||
if n < k {
|
||||
return 0
|
||||
}
|
||||
|
||||
nFactorial := Factorial(n)
|
||||
nMinusKFactorial := Factorial(n - k)
|
||||
|
||||
return nFactorial / nMinusKFactorial
|
||||
}
|
||||
|
||||
// Combination calculate C(n, k).
|
||||
// Play: https://go.dev/play/p/ENFQRDQUFi9
|
||||
func Combination(n, k uint) uint {
|
||||
if n < k {
|
||||
return 0
|
||||
}
|
||||
|
||||
nFactorial := Factorial(n)
|
||||
kFactorial := Factorial(k)
|
||||
nMinusKFactorial := Factorial(n - k)
|
||||
|
||||
return nFactorial / (kFactorial * nMinusKFactorial)
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func ExampleAverage() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
|
||||
@@ -478,3 +478,51 @@ func ExampleDiv() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleVariance() {
|
||||
result1 := Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
|
||||
func ExampleStdDev() {
|
||||
result1 := TruncRound(StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := TruncRound(StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
|
||||
func ExamplePermutation() {
|
||||
result1 := Permutation(5, 3)
|
||||
result2 := Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
|
||||
func ExampleCombination() {
|
||||
result1 := Combination(5, 3)
|
||||
result2 := Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
|
||||
@@ -143,11 +143,22 @@ func TestAverage(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestAverage")
|
||||
|
||||
assert.Equal(0, Average(0, 0))
|
||||
assert.Equal(1, Average(1, 1))
|
||||
tests := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 1},
|
||||
{[]int{1, 2, 3, 4}, 2.5},
|
||||
{[]int{1, 2, 3, 4, 5}, 3},
|
||||
}
|
||||
|
||||
avg := Average(1.2, 1.4)
|
||||
assert.Equal(1.3, RoundToFloat(avg, 1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Average(tt.numbers...))
|
||||
}
|
||||
|
||||
avg := Average(1.1, 1.2, 1.3, 1.4)
|
||||
assert.Equal(1.25, avg)
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
@@ -167,6 +178,7 @@ func TestMax(t *testing.T) {
|
||||
assert.Equal(0, Max(0, 0))
|
||||
assert.Equal(3, Max(1, 2, 3))
|
||||
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
||||
assert.Equal("abc", Max("a", "ab", "abc"))
|
||||
|
||||
type Integer int
|
||||
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
||||
@@ -201,6 +213,8 @@ func TestMin(t *testing.T) {
|
||||
assert.Equal(0, Min(0, 0))
|
||||
assert.Equal(1, Min(1, 2, 3))
|
||||
assert.Equal(1.1, Min(1.2, 1.4, 1.1, 1.4))
|
||||
|
||||
assert.Equal("a", Min("a", "ab", "abc"))
|
||||
}
|
||||
|
||||
func TestMinBy(t *testing.T) {
|
||||
@@ -413,3 +427,116 @@ func TestDiv(t *testing.T) {
|
||||
assert.Equal(math.Inf(-1), Div(-8, 0))
|
||||
assert.Equal(true, math.IsNaN(Div(0, 0)))
|
||||
}
|
||||
|
||||
func TestVariance(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestVariance")
|
||||
|
||||
testIntNumbers := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 0},
|
||||
{[]int{1, 2, 3, 4}, 1.25},
|
||||
{[]int{1, 2, 3, 4, 5}, 2.0},
|
||||
}
|
||||
|
||||
for _, tt := range testIntNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(Variance(tt.numbers), 2))
|
||||
}
|
||||
|
||||
testFloatNumbers := []struct {
|
||||
numbers []float64
|
||||
expected float64
|
||||
}{
|
||||
{[]float64{0}, 0},
|
||||
{[]float64{1, 1, 1}, 0},
|
||||
{[]float64{1.1, 2.2, 3.3, 4.4}, 1.51},
|
||||
}
|
||||
|
||||
for _, tt := range testFloatNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(Variance(tt.numbers), 2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdDev(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestStdDev")
|
||||
|
||||
testIntNumbers := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 0},
|
||||
{[]int{1, 2, 3, 4}, 1.118},
|
||||
{[]int{1, 2, 3, 4, 5}, 1.414},
|
||||
}
|
||||
|
||||
for _, tt := range testIntNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(StdDev(tt.numbers), 3))
|
||||
}
|
||||
|
||||
testFloatNumbers := []struct {
|
||||
numbers []float64
|
||||
expected float64
|
||||
}{
|
||||
{[]float64{0}, 0},
|
||||
{[]float64{1, 1, 1}, 0},
|
||||
{[]float64{1.1, 2.2, 3.3, 4.4}, 1.229},
|
||||
}
|
||||
|
||||
for _, tt := range testFloatNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(StdDev(tt.numbers), 3))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermutation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestPermutation")
|
||||
|
||||
tests := []struct {
|
||||
n uint
|
||||
k uint
|
||||
expected uint
|
||||
}{
|
||||
{1, 1, 1},
|
||||
{1, 0, 1},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
{3, 2, 6},
|
||||
{4, 2, 12},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Permutation(tt.n, tt.k))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCombination(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestCombination")
|
||||
|
||||
tests := []struct {
|
||||
n uint
|
||||
k uint
|
||||
expected uint
|
||||
}{
|
||||
{1, 1, 1},
|
||||
{1, 0, 1},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
{3, 2, 3},
|
||||
{4, 2, 6},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Combination(tt.n, tt.k))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func ConvertMapToQueryString(param map[string]any) string {
|
||||
if param == nil {
|
||||
return ""
|
||||
}
|
||||
var keys []string
|
||||
keys := make([]string, 0, len(param))
|
||||
for key := range param {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
@@ -221,6 +221,22 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AsyncSendRequest send http request with goroutine, pop response and error to channels
|
||||
func (client *HttpClient) AsyncSendRequest(request *HttpRequest, respChan chan *http.Response, errChan chan error) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
errChan <- fmt.Errorf("%v", err)
|
||||
}
|
||||
}()
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
respChan <- resp
|
||||
}()
|
||||
}
|
||||
|
||||
// DecodeResponse decode response into target object.
|
||||
// Play: https://go.dev/play/p/jUSgynekH7G
|
||||
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
|
||||
|
||||
@@ -373,6 +373,45 @@ func TestSendRequestWithFilePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpClient_AsyncSendRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHttpClient_Get")
|
||||
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
respCh := make(chan *http.Response, 20)
|
||||
errCh := make(chan error, 20)
|
||||
for i := 0; i < 50; i++ {
|
||||
httpClient.AsyncSendRequest(request, respCh, errCh)
|
||||
}
|
||||
for i := 0; i < 50; i++ {
|
||||
select {
|
||||
case resp := <-respCh:
|
||||
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.FailNow()
|
||||
}
|
||||
assert.Equal(1, todo.Id)
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Log("net error: ", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy(t *testing.T) {
|
||||
config := &HttpClientConfig{
|
||||
HandshakeTimeout: 20 * time.Second,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MaximumCapacity = math.MaxInt>>1 + 1
|
||||
MaximumCapacity = math.MaxInt32>>1 + 1
|
||||
Numeral = "0123456789"
|
||||
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@@ -33,13 +34,13 @@ func init() {
|
||||
}
|
||||
|
||||
// RandBool generates a random boolean value (true or false).
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/to6BLc26wBv
|
||||
func RandBool() bool {
|
||||
return rand.Intn(2) == 1
|
||||
}
|
||||
|
||||
// RandBoolSlice generates a random boolean slice of specified length.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/o-VSjPjnILI
|
||||
func RandBoolSlice(length int) []bool {
|
||||
if length <= 0 {
|
||||
return []bool{}
|
||||
@@ -73,7 +74,7 @@ func RandInt(min, max int) int {
|
||||
|
||||
// RandIntSlice generates a slice of random integers.
|
||||
// The generated integers are between min and max (exclusive).
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/GATTQ5xTEG8
|
||||
func RandIntSlice(length, min, max int) []int {
|
||||
if length <= 0 || min > max {
|
||||
return []int{}
|
||||
@@ -125,12 +126,24 @@ func RandFloat(min, max float64, precision int) float64 {
|
||||
|
||||
n := rand.Float64()*(max-min) + min
|
||||
|
||||
return mathutil.RoundToFloat(n, precision)
|
||||
return mathutil.FloorToFloat(n, precision)
|
||||
}
|
||||
|
||||
// RandFloats generate a slice of random float64 numbers of length that do not repeat.
|
||||
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
||||
func RandFloats(length int, min, max float64, precision int) []float64 {
|
||||
if max < min {
|
||||
min, max = max, min
|
||||
}
|
||||
|
||||
maxLength := int((max - min) * math.Pow10(precision))
|
||||
if maxLength == 0 {
|
||||
maxLength = 1
|
||||
}
|
||||
if length > maxLength {
|
||||
length = maxLength
|
||||
}
|
||||
|
||||
nums := make([]float64, length)
|
||||
used := make(map[float64]struct{}, length)
|
||||
for i := 0; i < length; {
|
||||
@@ -170,7 +183,7 @@ func RandString(length int) string {
|
||||
// RandString generate a slice of random string of length strLen based on charset.
|
||||
// chartset should be one of the following: random.Numeral, random.LowwerLetters, random.UpperLetters
|
||||
// random.Letters, random.SymbolChars, random.AllChars. or a combination of them.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/2_-PiDv3tGn
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string {
|
||||
if sliceLen <= 0 || strLen <= 0 {
|
||||
return []string{}
|
||||
@@ -186,7 +199,7 @@ func RandStringSlice(charset string, sliceLen, strLen int) []string {
|
||||
}
|
||||
|
||||
// RandFromGivenSlice generate a random element from given slice.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/UrkWueF6yYo
|
||||
func RandFromGivenSlice[T any](slice []T) T {
|
||||
if len(slice) == 0 {
|
||||
var zero T
|
||||
@@ -198,7 +211,7 @@ func RandFromGivenSlice[T any](slice []T) T {
|
||||
// RandSliceFromGivenSlice generate a random slice of length num from given slice.
|
||||
// - If repeatable is true, the generated slice may contain duplicate elements.
|
||||
//
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/68UikN9d6VT
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T {
|
||||
if num <= 0 || len(slice) == 0 {
|
||||
return slice
|
||||
@@ -273,6 +286,11 @@ func nearestPowerOfTwo(cap int) int {
|
||||
|
||||
// random generate a random string based on given string range.
|
||||
func random(s string, length int) string {
|
||||
// 确保随机数生成器的种子是动态的
|
||||
pid := os.Getpid()
|
||||
timestamp := time.Now().UnixNano()
|
||||
rand.Seed(int64(pid) + timestamp)
|
||||
|
||||
// 仿照strings.Builder
|
||||
// 创建一个长度为 length 的字节切片
|
||||
bytes := make([]byte, length)
|
||||
@@ -327,3 +345,13 @@ func UUIdV4() (string, error) {
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
||||
|
||||
// RandNumberOfLength 生成一个长度为len的随机数
|
||||
// Play: https://go.dev/play/p/oyZbuV7bu7b
|
||||
func RandNumberOfLength(len int) int {
|
||||
m := int(math.Pow10(len) - 1)
|
||||
i := int(math.Pow10(len - 1))
|
||||
ret := rand.Intn(m-i+1) + i
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package random
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -196,6 +197,14 @@ func TestRandFloats(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(len(numbers), 5)
|
||||
|
||||
numbers2 := RandFloats(10, 3.14, 3.2, 2)
|
||||
for _, n := range numbers2 {
|
||||
assert.GreaterOrEqual(n, 3.14)
|
||||
assert.Less(n, 3.2)
|
||||
}
|
||||
|
||||
assert.Equal(len(numbers2), 6)
|
||||
}
|
||||
|
||||
func TestRandIntSlice(t *testing.T) {
|
||||
@@ -361,3 +370,9 @@ func TestRandBoolSlice(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
func TestRandNumberOfLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
randi := RandNumberOfLength(6)
|
||||
assert := internal.NewAssert(t, "TestRandNumberOfLength")
|
||||
assert.Equal(6, len(strconv.Itoa(randi)))
|
||||
}
|
||||
|
||||
161
slice/slice.go
161
slice/slice.go
@@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
var (
|
||||
memoryHashMap = make(map[string]map[any]int)
|
||||
memoryHashCounter = make(map[string]int)
|
||||
muForMemoryHash sync.RWMutex
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not.
|
||||
@@ -218,6 +220,28 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
|
||||
return true
|
||||
}
|
||||
|
||||
// EqualUnordered checks if two slices are equal: the same length and all elements' value are equal (unordered).
|
||||
// Play: todo
|
||||
func EqualUnordered[T comparable](slice1, slice2 []T) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
}
|
||||
|
||||
seen := make(map[T]int)
|
||||
for _, v := range slice1 {
|
||||
seen[v]++
|
||||
}
|
||||
|
||||
for _, v := range slice2 {
|
||||
if seen[v] == 0 {
|
||||
return false
|
||||
}
|
||||
seen[v]--
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Every return true if all of the values in the slice pass the predicate function.
|
||||
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
@@ -789,7 +813,7 @@ func Unique[T comparable](slice []T) []T {
|
||||
|
||||
// UniqueBy removes duplicate elements from the input slice based on the values returned by the iteratee function.
|
||||
// The function maintains the order of the elements.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/GY7JE4yikrl
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
||||
result := make([]T, 0, len(slice))
|
||||
seen := make(map[U]struct{}, len(slice))
|
||||
@@ -810,7 +834,7 @@ func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
||||
|
||||
// UniqueByComparator removes duplicate elements from the input slice using the provided comparator function.
|
||||
// The function maintains the order of the elements.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rwSacr-ZHsR
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T {
|
||||
result := make([]T, 0, len(slice))
|
||||
seen := make([]T, 0, len(slice))
|
||||
@@ -919,36 +943,25 @@ func Merge[T any](slices ...[]T) []T {
|
||||
// Intersection creates a slice of unique elements that included by all slices.
|
||||
// Play: https://go.dev/play/p/anJXfB5wq_t
|
||||
func Intersection[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
}
|
||||
if len(slices) == 1 {
|
||||
return Unique(slices[0])
|
||||
}
|
||||
result := []T{}
|
||||
elementCount := make(map[T]int)
|
||||
|
||||
reducer := func(sliceA, sliceB []T) []T {
|
||||
hashMap := make(map[T]int)
|
||||
for _, v := range sliceA {
|
||||
hashMap[v] = 1
|
||||
}
|
||||
for _, slice := range slices {
|
||||
seen := make(map[T]bool)
|
||||
|
||||
out := make([]T, 0)
|
||||
for _, val := range sliceB {
|
||||
if v, ok := hashMap[val]; v == 1 && ok {
|
||||
out = append(out, val)
|
||||
hashMap[val]++
|
||||
for _, item := range slice {
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
elementCount[item]++
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
result := reducer(slices[0], slices[1])
|
||||
|
||||
reduceSlice := make([][]T, 2)
|
||||
for i := 2; i < len(slices); i++ {
|
||||
reduceSlice[0] = result
|
||||
reduceSlice[1] = slices[i]
|
||||
result = reducer(reduceSlice[0], reduceSlice[1])
|
||||
for _, item := range slices[0] {
|
||||
if elementCount[item] == len(slices) {
|
||||
result = append(result, item)
|
||||
elementCount[item] = 0
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -989,7 +1002,19 @@ func Reverse[T any](slice []T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle the slice.
|
||||
// ReverseCopy return a new slice of element order is reversed to the given slice.
|
||||
// Play: todo
|
||||
func ReverseCopy[T any](slice []T) []T {
|
||||
result := make([]T, len(slice))
|
||||
|
||||
for i, j := 0, len(slice)-1; i < len(slice); i, j = i+1, j-1 {
|
||||
result[i] = slice[j]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Shuffle return a new slice with elements shuffled.
|
||||
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
||||
func Shuffle[T any](slice []T) []T {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
@@ -1001,6 +1026,20 @@ func Shuffle[T any](slice []T) []T {
|
||||
return slice
|
||||
}
|
||||
|
||||
// ShuffleCopy return a new slice with elements shuffled.
|
||||
// Play: todo
|
||||
func ShuffleCopy[T any](slice []T) []T {
|
||||
result := make([]T, len(slice))
|
||||
copy(result, slice)
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand.Shuffle(len(result), func(i, j int) {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// IsAscending checks if a slice is ascending order.
|
||||
// Play: https://go.dev/play/p/9CtsFjet4SH
|
||||
func IsAscending[T constraints.Ordered](slice []T) bool {
|
||||
@@ -1174,23 +1213,46 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
limit := 10
|
||||
// gets the hash value of the array as the key of the hash table.
|
||||
key := fmt.Sprintf("%p", arr)
|
||||
|
||||
muForMemoryHash.RLock()
|
||||
// determines whether the hash table is empty. If so, the hash table is created.
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
|
||||
muForMemoryHash.RUnlock()
|
||||
muForMemoryHash.Lock()
|
||||
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
}
|
||||
}
|
||||
|
||||
muForMemoryHash.Unlock()
|
||||
} else {
|
||||
muForMemoryHash.RUnlock()
|
||||
}
|
||||
|
||||
muForMemoryHash.Lock()
|
||||
// update the hash table counter.
|
||||
memoryHashCounter[key]++
|
||||
muForMemoryHash.Unlock()
|
||||
|
||||
// use the hash table to find the specified value. If found, the index is returned.
|
||||
if index, ok := memoryHashMap[key][val]; ok {
|
||||
muForMemoryHash.RLock()
|
||||
index, ok := memoryHashMap[key][val]
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
if ok {
|
||||
muForMemoryHash.RLock()
|
||||
// calculate the memory usage of the hash table.
|
||||
size := len(memoryHashMap)
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
|
||||
if size > limit {
|
||||
muForMemoryHash.Lock()
|
||||
var minKey string
|
||||
var minVal int
|
||||
for k, v := range memoryHashCounter {
|
||||
@@ -1204,6 +1266,7 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
}
|
||||
delete(memoryHashMap, minKey)
|
||||
delete(memoryHashCounter, minKey)
|
||||
muForMemoryHash.Unlock()
|
||||
}
|
||||
return index
|
||||
}
|
||||
@@ -1388,7 +1451,7 @@ func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||
}
|
||||
|
||||
// Frequency counts the frequency of each element in the slice.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/CW3UVNdUZOq
|
||||
func Frequency[T comparable](slice []T) map[T]int {
|
||||
result := make(map[T]int)
|
||||
|
||||
@@ -1398,3 +1461,35 @@ func Frequency[T comparable](slice []T) map[T]int {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// JoinFunc joins the slice elements into a single string with the given separator.
|
||||
// Play: https://go.dev/play/p/55ib3SB5fM2
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
||||
var buf strings.Builder
|
||||
for i, v := range slice {
|
||||
if i > 0 {
|
||||
buf.WriteString(sep)
|
||||
}
|
||||
buf.WriteString(fmt.Sprint(transform(v)))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ConcatBy concats the elements of a slice into a single value using the provided separator and connector function.
|
||||
// Play: https://go.dev/play/p/6QcUpcY4UMW
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T {
|
||||
var result T
|
||||
|
||||
if len(slice) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
for i, v := range slice {
|
||||
result = connector(result, v)
|
||||
if i < len(slice)-1 {
|
||||
result = connector(result, sep)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// ForEachConcurrent applies the iteratee function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/kT4XW7DKVoV
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int) {
|
||||
sliceLen := len(slice)
|
||||
if sliceLen == 0 {
|
||||
@@ -50,7 +50,7 @@ func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numTh
|
||||
}
|
||||
|
||||
// MapConcurrent applies the iteratee function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/H1ehfPkPen0
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U {
|
||||
result := make([]U, len(slice))
|
||||
var wg sync.WaitGroup
|
||||
@@ -77,7 +77,7 @@ func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U,
|
||||
}
|
||||
|
||||
// ReduceConcurrent reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Tjwe6OtaG07
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T {
|
||||
if numThreads <= 0 {
|
||||
numThreads = 1
|
||||
@@ -121,7 +121,7 @@ func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item
|
||||
}
|
||||
|
||||
// FilterConcurrent applies the provided filter function `predicate` to each element of the input slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/t_pkwerIRVx
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
|
||||
result := make([]T, 0)
|
||||
var wg sync.WaitGroup
|
||||
@@ -149,12 +149,12 @@ func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool,
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqueByParallel removes duplicate elements from the slice by parallel
|
||||
// UniqueByConcurrent removes duplicate elements from the slice by parallel
|
||||
// The comparator function is used to compare the elements
|
||||
// The numThreads parameter specifies the number of threads to use
|
||||
// If numThreads is less than or equal to 0, it will be set to 1
|
||||
// The comparator function should return true if the two elements are equal
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/wXZ7LcYRMGL
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T {
|
||||
if numThreads <= 0 {
|
||||
numThreads = 1
|
||||
@@ -195,18 +195,14 @@ func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T
|
||||
chunks = append(chunks, slice[i:end])
|
||||
}
|
||||
|
||||
type resultChunk struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
resultCh := make(chan resultChunk, numThreads)
|
||||
resultCh := make(chan resultChunk[T], numThreads)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i, chunk := range chunks {
|
||||
wg.Add(1)
|
||||
go func(index int, chunk []T) {
|
||||
defer wg.Done()
|
||||
resultCh <- resultChunk{index, removeDuplicate(chunk, comparator)}
|
||||
resultCh <- resultChunk[T]{index, removeDuplicate(chunk, comparator)}
|
||||
}(i, chunk)
|
||||
}
|
||||
|
||||
|
||||
@@ -937,6 +937,41 @@ func ExampleReverse() {
|
||||
// [d c b a]
|
||||
}
|
||||
|
||||
func ExampleReverseCopy() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
|
||||
reversedStrs := ReverseCopy(strs)
|
||||
|
||||
fmt.Println(reversedStrs)
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// [d c b a]
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleShuffle() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
Shuffle(strs)
|
||||
|
||||
fmt.Println(len(strs))
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
func ExampleShuffleCopy() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
shuffledStrs := ShuffleCopy(strs)
|
||||
|
||||
fmt.Println(len(shuffledStrs))
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleIsAscending() {
|
||||
|
||||
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
||||
@@ -1261,3 +1296,54 @@ func ExampleFrequency() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
|
||||
func ExampleJoinFunc() {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
|
||||
func ExampleConcatBy() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
|
||||
func ExampleEqualUnordered() {
|
||||
result1 := EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||
result2 := EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ import (
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// resultChunk is used to store the intermediate results of UniqueByConcurrent.
|
||||
// It is defined separately to be compatible with versions of go up to 1.20.
|
||||
type resultChunk[T comparable] struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
|
||||
// sliceValue return the reflect value of a slice
|
||||
func sliceValue(slice any) reflect.Value {
|
||||
v := reflect.ValueOf(slice)
|
||||
|
||||
@@ -4,8 +4,10 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -1113,6 +1115,17 @@ func TestReverse(t *testing.T) {
|
||||
assert.Equal([]string{"e", "d", "c", "b", "a"}, s2)
|
||||
}
|
||||
|
||||
func TestReverseCopy(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestReverseCopy")
|
||||
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
reversedNumbers := ReverseCopy(numbers)
|
||||
|
||||
assert.Equal([]int{5, 4, 3, 2, 1}, reversedNumbers)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, numbers)
|
||||
}
|
||||
|
||||
func TestDifference(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1328,6 +1341,18 @@ func TestShuffle(t *testing.T) {
|
||||
assert.Equal(5, len(result))
|
||||
}
|
||||
|
||||
func TestShuffleCopy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestShuffleCopy")
|
||||
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
result := ShuffleCopy(numbers)
|
||||
|
||||
assert.Equal(5, len(result))
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, numbers)
|
||||
}
|
||||
|
||||
func TestIndexOf(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1367,6 +1392,37 @@ func TestIndexOf(t *testing.T) {
|
||||
assert.Equal(-1, IndexOf(arr3, "r"))
|
||||
assert.Equal(2, memoryHashCounter[key3])
|
||||
assert.Equal(0, memoryHashCounter[minKey])
|
||||
|
||||
arr4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
const numGoroutines = 100
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
index := IndexOf(arr4, i%10+1)
|
||||
assert.Equal(i%10, index)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkIndexOfDifferentSizes(b *testing.B) {
|
||||
sizes := []int{10, 100, 1000, 10000, 100000}
|
||||
for _, size := range sizes {
|
||||
arr := make([]int, size)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arr[i] = i
|
||||
}
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_ = IndexOf(arr, size/2) // 查找数组中间的元素
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastIndexOf(t *testing.T) {
|
||||
@@ -1762,6 +1818,8 @@ func TestFilterConcurrent(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
expected := []int{4, 5, 6}
|
||||
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
|
||||
sort.Ints(actual)
|
||||
sort.Ints(expected)
|
||||
assert.Equal(expected, actual)
|
||||
})
|
||||
}
|
||||
@@ -1816,3 +1874,103 @@ func TestFrequency(t *testing.T) {
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestJoinFunc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestJoinFunc")
|
||||
|
||||
t.Run("basic case", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1, 2, 3}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
expected := "2, 4, 6"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("empty slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("", result)
|
||||
})
|
||||
|
||||
t.Run("single element slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("2", result)
|
||||
})
|
||||
|
||||
t.Run("string slice", func(t *testing.T) {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
expected := "A, B, C"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConcatBy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestConcatBy")
|
||||
|
||||
t.Run("Join strings", func(t *testing.T) {
|
||||
result := ConcatBy([]string{"Hello", "World"}, ", ", func(a, b string) string {
|
||||
return a + b
|
||||
})
|
||||
|
||||
expected := "Hello, World"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("Join Person struct", func(t *testing.T) {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
assert.Equal("Alice | Bob | Charlie", result.Name)
|
||||
assert.Equal(90, result.Age)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEqualUnordered(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestEqualUnordered")
|
||||
|
||||
tests := []struct {
|
||||
slice1, slice2 []int
|
||||
expected bool
|
||||
}{
|
||||
{[]int{}, []int{}, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{[]int{1, 2, 3}, []int{3, 2, 1}, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3, 4}, false},
|
||||
{[]int{1, 2, 3}, []int{1, 2}, false},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 4}, false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
assert.Equal(test.expected, EqualUnordered(test.slice1, test.slice2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ func (s Stream[T]) Distinct() Stream[T] {
|
||||
distinct := map[string]bool{}
|
||||
|
||||
for _, v := range s.source {
|
||||
// todo: performance issue
|
||||
k := hashKey(v)
|
||||
if _, ok := distinct[k]; !ok {
|
||||
distinct[k] = true
|
||||
@@ -202,6 +201,7 @@ func (s Stream[T]) Skip(n int) Stream[T] {
|
||||
return FromSlice(source)
|
||||
}
|
||||
|
||||
source = make([]T, 0, l-n)
|
||||
for i := n; i < l; i++ {
|
||||
source = append(source, s.source[i])
|
||||
}
|
||||
@@ -393,6 +393,28 @@ func (s Stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
||||
return min, true
|
||||
}
|
||||
|
||||
// IndexOf returns the index of the first occurrence of the specified element in this stream, or -1 if this stream does not contain the element.
|
||||
// Play: https://go.dev/play/p/tBV5Nc-XDX2
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int {
|
||||
for i, v := range s.source {
|
||||
if equal(v, target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index of the last occurrence of the specified element in this stream, or -1 if this stream does not contain the element.
|
||||
// Play: https://go.dev/play/p/CjeoNw2eac_G
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int {
|
||||
for i := len(s.source) - 1; i >= 0; i-- {
|
||||
if equal(s.source[i], target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ToSlice return the elements in the stream.
|
||||
// Play: https://go.dev/play/p/jI6_iZZuVFE
|
||||
func (s Stream[T]) ToSlice() []T {
|
||||
|
||||
@@ -384,3 +384,31 @@ func ExampleStream_Count() {
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStream_IndexOf() {
|
||||
s := FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleStream_LastIndexOf() {
|
||||
s := FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
|
||||
@@ -381,3 +381,22 @@ func TestStream_Min(t *testing.T) {
|
||||
assert.Equal(1, max)
|
||||
assert.Equal(true, ok)
|
||||
}
|
||||
|
||||
func TestStream_IndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_IndexOf")
|
||||
|
||||
s := FromSlice([]int{4, 2, 1, 3, 4})
|
||||
|
||||
assert.Equal(-1, s.IndexOf(0, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(0, s.IndexOf(4, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(3, s.IndexOf(3, func(a, b int) bool { return a == b }))
|
||||
}
|
||||
|
||||
func TestStream_LastIndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_LastIndexOf")
|
||||
|
||||
s := FromSlice([]int{4, 2, 1, 3, 2})
|
||||
|
||||
assert.Equal(-1, s.LastIndexOf(0, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(4, s.LastIndexOf(2, func(a, b int) bool { return a == b }))
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ func (s *Struct) ToMap() (map[string]any, error) {
|
||||
|
||||
// Fields returns all the struct fields within a slice
|
||||
func (s *Struct) Fields() []*Field {
|
||||
var fields []*Field
|
||||
fieldNum := s.rvalue.NumField()
|
||||
fields := make([]*Field, 0, fieldNum)
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
v := s.rvalue.Field(i)
|
||||
sf := s.rtype.Field(i)
|
||||
|
||||
@@ -627,7 +627,7 @@ func HammingDistance(a, b string) (int, error) {
|
||||
// - `length` is the expected length of the concatenated string.
|
||||
// - if you are unsure about the length of the string to be concatenated, please pass 0 or a negative number.
|
||||
//
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/gD52SZHr4Kp
|
||||
func Concat(length int, str ...string) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
@@ -647,7 +647,7 @@ func Concat(length int, str ...string) string {
|
||||
}
|
||||
|
||||
// Ellipsis truncates a string to a specified length and appends an ellipsis.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/i1vbdQiQVRR
|
||||
func Ellipsis(str string, length int) string {
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
@@ -665,7 +665,7 @@ func Ellipsis(str string, length int) string {
|
||||
}
|
||||
|
||||
// Shuffle the order of characters of given string.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/iStFwBwyGY7
|
||||
func Shuffle(str string) string {
|
||||
runes := []rune(str)
|
||||
|
||||
@@ -678,7 +678,7 @@ func Shuffle(str string) string {
|
||||
}
|
||||
|
||||
// Rotate rotates the string by the specified number of characters.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Kf03iOeT5bd
|
||||
func Rotate(str string, shift int) string {
|
||||
if shift == 0 {
|
||||
return str
|
||||
@@ -709,7 +709,7 @@ func Rotate(str string, shift int) string {
|
||||
// The placeholders are enclosed in curly braces, e.g. {key}.
|
||||
// for example, the template string is "Hello, {name}!", and the data map is {"name": "world"},
|
||||
// the result will be "Hello, world!".
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/cXSuFvyZqv9
|
||||
func TemplateReplace(template string, data map[string]string) string {
|
||||
re := regexp.MustCompile(`\{(\w+)\}`)
|
||||
|
||||
@@ -729,9 +729,47 @@ func TemplateReplace(template string, data map[string]string) string {
|
||||
}
|
||||
|
||||
// RegexMatchAllGroups Matches all subgroups in a string using a regular expression and returns the result.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/JZiu0RXpgN-
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string {
|
||||
re := regexp.MustCompile(pattern)
|
||||
matches := re.FindAllStringSubmatch(str, -1)
|
||||
return matches
|
||||
}
|
||||
|
||||
// ExtractContent extracts the content between the start and end strings in the source string.
|
||||
// Play: https://go.dev/play/p/Ay9UIk7Rum9
|
||||
func ExtractContent(str, start, end string) []string {
|
||||
result := []string{}
|
||||
|
||||
for {
|
||||
if _, after, ok := strings.Cut(str, start); ok {
|
||||
if before, _, ok := strings.Cut(after, end); ok {
|
||||
result = append(result, before)
|
||||
str = after
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindAllOccurrences returns the positions of all occurrences of a substring in a string.
|
||||
// Play: todo
|
||||
func FindAllOccurrences(str, substr string) []int {
|
||||
var positions []int
|
||||
|
||||
for i := 0; i < len(str); {
|
||||
index := strings.Index(str[i:], substr)
|
||||
if index == -1 {
|
||||
break
|
||||
}
|
||||
positions = append(positions, i+index)
|
||||
i += index + 1
|
||||
}
|
||||
|
||||
return positions
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user