mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
20 Commits
v2.3.4
...
db479ef1bc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db479ef1bc | ||
|
|
df8121fbbd | ||
|
|
0e7297cb97 | ||
|
|
2e619e48a3 | ||
|
|
3069acba4a | ||
|
|
fc43138a0e | ||
|
|
1e56e9964c | ||
|
|
f861e18bc3 | ||
|
|
e27df00fa8 | ||
|
|
23e61f1acf | ||
|
|
cb308f628c | ||
|
|
7653afa919 | ||
|
|
a0d97cf38e | ||
|
|
1f6bab467c | ||
|
|
2e5b9bc200 | ||
|
|
ab89f0aee1 | ||
|
|
1f64e02df4 | ||
|
|
d4b425e39c | ||
|
|
a1652c7523 | ||
|
|
ecafed511c |
42
README.md
42
README.md
@@ -39,7 +39,7 @@
|
|||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.5. </b>
|
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.6. </b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||||
@@ -333,7 +333,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||||
- **<big>ToBigInt</big>** : converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToBigInt)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="cryptor"> 6. Cryptor package is for data encryption and decryption. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -469,10 +469,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||||
- **<big>RsaEncrypt</big>** : encrypt data with ras algorithm.
|
- **<big>RsaEncrypt</big>** : encrypt data with ras algorithm.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaEncrypt)]
|
[[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.
|
- **<big>RsaDecrypt</big>** : decrypt data with ras algorithm.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecrypt)]
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||||
@@ -484,10 +484,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||||
- **<big>RsaSign</big>** : signs the data with RSA.
|
- **<big>RsaSign</big>** : signs the data with RSA.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaSign)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaSign)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||||
- **<big>RsaVerifySign</big>** : verifies the signature of the data with RSA.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaVerifySign)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -633,13 +633,13 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||||
- **<big>Min</big>** : returns the earliest time among the given times.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Min)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/MCIDvHNOGGb)]
|
||||||
- **<big>Max</big>** : returns the latest time among the given times.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Max)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/9m6JMk1LB7-)]
|
||||||
- **<big>MaxMin</big>** : returns the latest and earliest time among the given times.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#MaxMin)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<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>
|
||||||
|
|
||||||
@@ -777,7 +777,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||||
- **<big>GetExeOrDllVersion</big>** : Get the version of exe or dll file on windows os.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||||
|
|
||||||
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1145,16 +1145,16 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||||
- **<big>Variance</big>** : returns the variance of numbers.
|
- **<big>Variance</big>** : returns the variance of numbers.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Variance)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Variance)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/uHuV4YgXf8F)]
|
||||||
- **<big>StdDev</big>** : returns the standard deviation of numbers.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#StdDev)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/FkNZDXvHD2l)]
|
||||||
- **<big>Permutation</big>** : calculates P(n, k).
|
- **<big>Permutation</big>** : calculates P(n, k).
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Permutation)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Permutation)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/MgobwH_FOxj)]
|
||||||
- **<big>Combination</big>** : calculates C(n, k).
|
- **<big>Combination</big>** : calculates C(n, k).
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Combination)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Combination)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1317,7 +1317,7 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||||
- **<big>RandNumberOfLength</big>** : generates a random int number of specified length.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandNumberOfLength)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<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>
|
||||||
|
|
||||||
@@ -1613,10 +1613,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||||
- **<big>JoinFunc</big>** : joins the slice elements into a single string with the given separator.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#JoinFunc)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ConcatBy)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<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>
|
||||||
|
|
||||||
@@ -1709,10 +1709,10 @@ import "github.com/duke-git/lancet/v2/stream"
|
|||||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#IndexOf)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#LastIndexOf)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1896,7 +1896,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||||
- **<big>ExtractContent</big>** : extracts the content between the start and end strings in the source string.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#ExtractContent)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||||
@@ -2249,7 +2249,7 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
- **<big>TryCatch</big>** : simple simulation of Java-style try-catch.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/xerror.md#TryCatch)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/D5Mdb0mRj0P)]
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.5。</b>
|
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.6。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||||
@@ -333,7 +333,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||||
- **<big>ToBigInt</big>** : 将整数转为*big.Int。
|
- **<big>ToBigInt</big>** : 将整数转为*big.Int。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -470,10 +470,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||||
- **<big>RsaEncrypt</big>** : 用公钥文件 ras 加密数据。
|
- **<big>RsaEncrypt</big>** : 用公钥文件 ras 加密数据。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaEncrypt)]
|
[[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 解密数据。
|
- **<big>RsaDecrypt</big>** : 用私钥文件 rsa 解密数据。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecrypt)]
|
[[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。
|
- **<big>GenerateRsaKeyPair</big>** : 创建rsa公钥私钥和key。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||||
@@ -485,10 +485,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||||
- **<big>RsaSign</big>** : 应用RSA算法签名数据。
|
- **<big>RsaSign</big>** : 应用RSA算法签名数据。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaSign)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaSign)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||||
- **<big>RsaVerifySign</big>** : 验证数据的签名是否符合RSA算法。
|
- **<big>RsaVerifySign</big>** : 验证数据的签名是否符合RSA算法。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaVerifySign)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaVerifySign)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
|
||||||
|
|
||||||
<h3 id="datetime"> 7. datetime日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
<h3 id="datetime"> 7. datetime日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -635,13 +635,13 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||||
- **<big>Min</big>** : 返回最早时间。
|
- **<big>Min</big>** : 返回最早时间。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Min)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Min)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/MCIDvHNOGGb)]
|
||||||
- **<big>Max</big>** : 返回最晚时间。
|
- **<big>Max</big>** : 返回最晚时间。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Max)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Max)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/9m6JMk1LB7-)]
|
||||||
- **<big>MaxMin</big>** : 返回最早和最晚时间。
|
- **<big>MaxMin</big>** : 返回最早和最晚时间。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[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>
|
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||||
@@ -776,7 +776,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||||
- **<big>GetExeOrDllVersion</big>** : 返回exe,dll文件版本号(仅Window平台)。
|
- **<big>GetExeOrDllVersion</big>** : 返回exe,dll文件版本号(仅Window平台)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||||
@@ -1145,16 +1145,16 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||||
- **<big>Variance</big>** : 计算方差。
|
- **<big>Variance</big>** : 计算方差。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Variance)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Variance)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/uHuV4YgXf8F)]
|
||||||
- **<big>StdDev</big>** : 计算标准差。
|
- **<big>StdDev</big>** : 计算标准差。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#StdDev)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#StdDev)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/FkNZDXvHD2l)]
|
||||||
- **<big>Permutation</big>** : 计算排列数P(n, k)。
|
- **<big>Permutation</big>** : 计算排列数P(n, k)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Permutation)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Permutation)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/MgobwH_FOxj)]
|
||||||
- **<big>Combination</big>** : 计算组合数C(n, k)。
|
- **<big>Combination</big>** : 计算组合数C(n, k)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
|
||||||
|
|
||||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1317,7 +1317,7 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||||
- **<big>RandNumberOfLength</big>** : 生成指定长度的随机数。
|
- **<big>RandNumberOfLength</big>** : 生成指定长度的随机数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
|
||||||
|
|
||||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1610,10 +1610,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||||
- **<big>JoinFunc</big>** : 将切片元素用给定的分隔符连接成一个单一的字符串。
|
- **<big>JoinFunc</big>** : 将切片元素用给定的分隔符连接成一个单一的字符串。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#JoinFunc)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#JoinFunc)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/55ib3SB5fM2)]
|
||||||
- **<big>ConcatBy</big>** : 将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。
|
- **<big>ConcatBy</big>** : 将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
|
||||||
|
|
||||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1706,10 +1706,10 @@ import "github.com/duke-git/lancet/v2/stream"
|
|||||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||||
- **<big>IndexOf</big>** : 返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。
|
- **<big>IndexOf</big>** : 返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#IndexOf)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#IndexOf)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/tBV5Nc-XDX2)]
|
||||||
- **<big>LastIndexOf</big>** : 返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。
|
- **<big>LastIndexOf</big>** : 返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
|
||||||
|
|
||||||
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1896,7 +1896,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||||
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||||
|
|
||||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -2249,7 +2249,7 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
- **<big>TryCatch</big>** : 简单实现的java风格异常处理(try-catch-finally)。
|
- **<big>TryCatch</big>** : 简单实现的java风格异常处理(try-catch-finally)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryCatch)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryCatch)]
|
||||||
[[play](https://go.dev/play/p/todo)]
|
[[play](https://go.dev/play/p/D5Mdb0mRj0P)]
|
||||||
|
|
||||||
## 如何贡献代码
|
## 如何贡献代码
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
// Play: https://go.dev/play/p/qmWSy1NVF-Y
|
||||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||||
valStream := make(chan T)
|
valStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(valStream)
|
defer close(valStream)
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
defer wg.Wait()
|
||||||
for {
|
for {
|
||||||
var stream <-chan T
|
var stream <-chan T
|
||||||
select {
|
select {
|
||||||
@@ -169,19 +169,22 @@ func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
stream = maybeStream
|
stream = maybeStream
|
||||||
|
wg.Add(1)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for val := range c.OrDone(ctx, stream) {
|
go func() {
|
||||||
select {
|
defer wg.Done()
|
||||||
case valStream <- val:
|
for val := range c.OrDone(ctx, stream) {
|
||||||
case <-ctx.Done():
|
select {
|
||||||
|
case valStream <- val:
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return valStream
|
return valStream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,8 @@ func ExampleChannel_Tee() {
|
|||||||
func ExampleChannel_Bridge() {
|
func ExampleChannel_Bridge() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
m1 := make(map[int]int)
|
||||||
|
m2 := make(map[int]int)
|
||||||
c := NewChannel[int]()
|
c := NewChannel[int]()
|
||||||
genVals := func() <-chan <-chan int {
|
genVals := func() <-chan <-chan int {
|
||||||
out := make(chan (<-chan int))
|
out := make(chan (<-chan int))
|
||||||
@@ -177,6 +178,7 @@ func ExampleChannel_Bridge() {
|
|||||||
for i := 1; i <= 5; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
stream := make(chan int, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
|
m1[i]++
|
||||||
close(stream)
|
close(stream)
|
||||||
out <- stream
|
out <- stream
|
||||||
}
|
}
|
||||||
@@ -185,12 +187,15 @@ func ExampleChannel_Bridge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for v := range c.Bridge(ctx, genVals()) {
|
for v := range c.Bridge(ctx, genVals()) {
|
||||||
fmt.Println(v)
|
m2[v]++
|
||||||
|
}
|
||||||
|
for k, v := range m1 {
|
||||||
|
fmt.Println(m2[k] == v)
|
||||||
}
|
}
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// true
|
||||||
// 2
|
// true
|
||||||
// 3
|
// true
|
||||||
// 4
|
// true
|
||||||
// 5
|
// true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ func TestTee(t *testing.T) {
|
|||||||
func TestBridge(t *testing.T) {
|
func TestBridge(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
assert := internal.NewAssert(t, "TestBridge")
|
assert := internal.NewAssert(t, "TestBridge")
|
||||||
|
m1 := make(map[int]int)
|
||||||
|
m2 := make(map[int]int)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -181,6 +182,7 @@ func TestBridge(t *testing.T) {
|
|||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
stream := make(chan int, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
|
m1[i]++
|
||||||
close(stream)
|
close(stream)
|
||||||
chanStream <- stream
|
chanStream <- stream
|
||||||
}
|
}
|
||||||
@@ -188,9 +190,11 @@ func TestBridge(t *testing.T) {
|
|||||||
return chanStream
|
return chanStream
|
||||||
}
|
}
|
||||||
|
|
||||||
index := 0
|
|
||||||
for val := range c.Bridge(ctx, genVals()) {
|
for val := range c.Bridge(ctx, genVals()) {
|
||||||
assert.Equal(index, val)
|
m2[val]++
|
||||||
index++
|
}
|
||||||
|
|
||||||
|
for k, v := range m1 {
|
||||||
|
assert.Equal(m2[k], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ func ToString(value any) string {
|
|||||||
if value == nil {
|
if value == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
rv := reflect.ValueOf(value)
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
if rv.IsNil() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ToString(rv.Elem().Interface())
|
||||||
|
}
|
||||||
|
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case float32:
|
case float32:
|
||||||
@@ -143,12 +150,8 @@ func ToString(value any) string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return string(b)
|
|
||||||
|
|
||||||
// todo: maybe we should't supprt other type conversion
|
return string(b)
|
||||||
// v := reflect.ValueOf(value)
|
|
||||||
// log.Panicf("Unsupported data type: %s ", v.String())
|
|
||||||
// return ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +489,7 @@ func ToRawUrlBase64(value any) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToBigInt converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int
|
// ToBigInt converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/X3itkCxwB_x
|
||||||
func ToBigInt[T any](v T) (*big.Int, error) {
|
func ToBigInt[T any](v T) (*big.Int, error) {
|
||||||
result := new(big.Int)
|
result := new(big.Int)
|
||||||
|
|
||||||
|
|||||||
@@ -142,13 +142,24 @@ func TestToString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
aStruct := TestStruct{Name: "TestStruct"}
|
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{
|
cases := []any{
|
||||||
"", nil,
|
"", nil,
|
||||||
int(0), int8(1), int16(-1), int32(123), int64(123),
|
int(0), int8(1), int16(-1), int32(123), int64(123),
|
||||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||||
float64(12.3), float32(12.3),
|
float64(12.3), float32(12.3),
|
||||||
true, false,
|
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{
|
expected := []string{
|
||||||
"", "",
|
"", "",
|
||||||
@@ -157,6 +168,8 @@ func TestToString(t *testing.T) {
|
|||||||
"12.3", "12.3",
|
"12.3", "12.3",
|
||||||
"true", "false",
|
"true", "false",
|
||||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello",
|
"[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++ {
|
for i := 0; i < len(cases); i++ {
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RsaEncrypt encrypt data with ras algorithm.
|
// 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 {
|
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||||
file, err := os.Open(pubKeyFileName)
|
file, err := os.Open(pubKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -600,7 +600,7 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RsaDecrypt decrypt data with ras algorithm.
|
// 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 {
|
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||||
file, err := os.Open(privateKeyFileName)
|
file, err := os.Open(privateKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -663,7 +663,7 @@ func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RsaSign signs the data with RSA.
|
// RsaSign signs the data with RSA.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/qhsbf8BJ6Mf
|
||||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
|
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
|
||||||
privateKey, err := loadRasPrivateKey(privateKeyFileName)
|
privateKey, err := loadRasPrivateKey(privateKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -679,7 +679,7 @@ func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RsaVerifySign verifies the signature of the data with RSA.
|
// RsaVerifySign verifies the signature of the data with RSA.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/qhsbf8BJ6Mf
|
||||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
|
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
|
||||||
publicKey, err := loadRsaPublicKey(pubKeyFileName)
|
publicKey, err := loadRsaPublicKey(pubKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -712,7 +712,6 @@ func loadRsaPublicKey(filename string) (*rsa.PublicKey, error) {
|
|||||||
if blockType == "RSA PUBLIC KEY" {
|
if blockType == "RSA PUBLIC KEY" {
|
||||||
pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// todo: here should be a bug, should return nil, err
|
|
||||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
-----BEGIN rsa private key-----
|
-----BEGIN rsa private key-----
|
||||||
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
|
||||||
-----END rsa private key-----
|
-----END rsa private key-----
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
-----BEGIN rsa public key-----
|
-----BEGIN rsa public key-----
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwGdN8KE2NTK41cVN7i6m
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAof7+5KVH6s/ID7onVeuC
|
||||||
ZZS5J86gjNs0LJDHylb2GG+K4O8sfq98EMKMJ2xGnKoVRJXucVohr5Eiuf5zgxQe
|
PVGPIW6TiHHjDlxbYLdA/CyhTvR2Pk8JvX9BjBXLI/+jTWsyTUucwszu3MaVhIS/
|
||||||
9mpYDyDQ0vnpBkoNkfzJNZQvcQFaIllUeH+eN4hSBhMegPspCr2BcmC/m/N40+Pj
|
gzoLKjr5meVp+HEcFe98s4XRYhob2cdpDo+Jty8Vuodz5T2nYkIZP/oyJNmQCBYD
|
||||||
BMDaHSzeNE2SyIuyflLC7GhQvHnkcQXkqJVNC1yesV7zYKDV/xYPI0NxN0kE+4eR
|
e20nBwmjjFfworEvwNy2fSucs8wrlJT2Xqy4oHZqERWvnIJZtBshX9//9Pw3m/Gu
|
||||||
650A77jso4gloRUek0cpU4ztpe6Zz4za7AEKHmZO8pVHpQJihbNMhItbo6BcgeOF
|
pHeBFBNW2omWCQm4aTEbeepkXloTgVQ75FEpyyjNjDi+OG/Om2v5l+XCvOcV39Hc
|
||||||
WImXyJfcbCtu1ayciaJ0Q45Z1btuF2wFwQjwZGt7DAvbzYwMBBiTpGxig/8kzibm
|
7sBovDFNX6w39zQSIKiMpFkxciKP9SPbqZz+Vv0iyUPKxi2gXwbgy0+k2aTQlsPS
|
||||||
7bL1Td7huW6Knqbfh4/v+2m+2aNK1u0TfncFUr17wDDfeVj/xeNOSbPu2X/AppjV
|
976+2/4QgLReU3Ujeh8Q6oRwB8HRfPlD7aY+dGPMT16o1R3nhs2jwsGId812lw5q
|
||||||
X0rxmvWN+AByFfAuw7/kqMK7QZlA+5nNjmOojvryGOSu1he4PUnhRyJ7jofOIrLZ
|
gjaYZJCXCBhQcZFs+1IM7c6GmIGXYIAcFDWiVsENqqesQO5tCA1UTTGtIa9kMYD/
|
||||||
9YYBXpRiY/WB8t+xWIlaoPXFmsOxSgMwzQFGMlnSFy7nK9T4znE0QFknOQNbELPE
|
pwFK1ANVvrr2c6Qu/0UuBneawok76vDHTQCWmVcF0QIe5RaTj8YK9TaNAcQDPy9j
|
||||||
B4UGLOEa5Tg6YD2ORDDSqCzMRdkE1kAgoMRC9DkRXE45KEcQlhMX9Pahwx3mPS4l
|
M0jWxJE1EBuRpDtIymQIcgMpXwguerh9NuXNoGEVPn4mvlVfy+1TVGzws8WsZwY/
|
||||||
MWABVudiEWyhGaR279OWjezqvtoLLBJ5GD9QL1XqaqCaJjp+qsHmX8re+MTA3ZJu
|
LH07afdfIeDc1YwLadwq5S+wxuzwNuSCM9t2rIzfbRhorlg/lVDWqP8H6d9vF5MJ
|
||||||
yUtRoPXPsKCe2nZ6Ma87DlUCAwEAAQ==
|
Y9kSiO3KgCSJLYfVl+Q+8asCAwEAAQ==
|
||||||
-----END rsa public key-----
|
-----END rsa public key-----
|
||||||
|
|||||||
@@ -445,7 +445,7 @@ func GenerateDatetimesBetween(start, end time.Time, layout string, interval stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Min returns the earliest time among the given times.
|
// Min returns the earliest time among the given times.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/MCIDvHNOGGb
|
||||||
func Min(t1 time.Time, times ...time.Time) time.Time {
|
func Min(t1 time.Time, times ...time.Time) time.Time {
|
||||||
minTime := t1
|
minTime := t1
|
||||||
|
|
||||||
@@ -459,7 +459,7 @@ func Min(t1 time.Time, times ...time.Time) time.Time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Max returns the latest time among the given times.
|
// Max returns the latest time among the given times.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/9m6JMk1LB7-
|
||||||
func Max(t1 time.Time, times ...time.Time) time.Time {
|
func Max(t1 time.Time, times ...time.Time) time.Time {
|
||||||
maxTime := t1
|
maxTime := t1
|
||||||
|
|
||||||
@@ -473,7 +473,7 @@ func Max(t1 time.Time, times ...time.Time) time.Time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MaxMin returns the latest and earliest time among the given times.
|
// MaxMin returns the latest and earliest time among the given times.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/rbW51cDtM_2
|
||||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
||||||
maxTime = t1
|
maxTime = t1
|
||||||
minTime = t1
|
minTime = t1
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||||
result, err := ToJson(aMap)
|
result, err := convertor.ToJson(aMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%v", err)
|
fmt.Printf("%v", err)
|
||||||
@@ -1155,7 +1155,7 @@ func main() {
|
|||||||
|
|
||||||
<p>将整数值转换为bigInt。</p>
|
<p>将整数值转换为bigInt。</p>
|
||||||
|
|
||||||
<b>函数签名:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>函数签名:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/X3itkCxwB_x)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func ToBigInt[T any](v T) (*big.Int, error)
|
func ToBigInt[T any](v T) (*big.Int, error)
|
||||||
|
|||||||
@@ -1436,7 +1436,7 @@ func main() {
|
|||||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1473,7 +1473,7 @@ func main() {
|
|||||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1621,7 +1621,7 @@ func main() {
|
|||||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, 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/qhsbf8BJ6Mf)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1638,12 +1638,12 @@ func main() {
|
|||||||
privateKey := "./rsa_private.pem"
|
privateKey := "./rsa_private.pem"
|
||||||
publicKey := "./rsa_public.pem"
|
publicKey := "./rsa_public.pem"
|
||||||
|
|
||||||
signature, err := RsaSign(hash, data, privateKey)
|
signature, err := cryptor.RsaSign(hash, data, privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
err = cryptor.RsaVerifySign(hash, data, signature, publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1660,7 +1660,7 @@ func main() {
|
|||||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName 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/qhsbf8BJ6Mf)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1677,12 +1677,12 @@ func main() {
|
|||||||
privateKey := "./rsa_private.pem"
|
privateKey := "./rsa_private.pem"
|
||||||
publicKey := "./rsa_public.pem"
|
publicKey := "./rsa_public.pem"
|
||||||
|
|
||||||
signature, err := RsaSign(hash, data, privateKey)
|
signature, err := cryptor.RsaSign(hash, data, privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
err = cryptor.RsaVerifySign(hash, data, signature, publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1585,7 +1585,7 @@ func main() {
|
|||||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MCIDvHNOGGb)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1615,7 +1615,7 @@ func main() {
|
|||||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9m6JMk1LB7-)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1645,7 +1645,7 @@ func main() {
|
|||||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rbW51cDtM_2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1088,7 +1088,7 @@ func main() {
|
|||||||
func GetExeOrDllVersion(filePath string) (string, error)
|
func GetExeOrDllVersion(filePath 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/iLRrDBhE38E)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1178,7 +1178,7 @@ func main() {
|
|||||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[示例](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[示例](https://go.dev/play/p/uHuV4YgXf8F)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1211,7 +1211,7 @@ func main() {
|
|||||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/FkNZDXvHD2l)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1222,8 +1222,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
result1 := mathutil.T运行cRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
result1 := mathutil.TruncRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||||
result2 := mathutil.T运行cRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
result2 := mathutil.TruncRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
@@ -1244,7 +1244,7 @@ func main() {
|
|||||||
func Permutation(n, k uint) uint
|
func Permutation(n, k uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MgobwH_FOxj)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1277,7 +1277,7 @@ func main() {
|
|||||||
func Combination(n, k uint) uint
|
func Combination(n, k uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ENFQRDQUFi9)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ func main() {
|
|||||||
func RandNumberOfLength(len int) int
|
func RandNumberOfLength(len int) 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/oyZbuV7bu7b)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import (
|
|||||||
- [Every](#Every)
|
- [Every](#Every)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [EqualWith](#EqualWith)
|
- [EqualWith](#EqualWith)
|
||||||
|
- [EqualUnordered](#EqualUnordered)
|
||||||
- [Filter](#Filter)
|
- [Filter](#Filter)
|
||||||
- [FilterConcurrent](#FilterConcurrent)
|
- [FilterConcurrent](#FilterConcurrent)
|
||||||
- [Find<sup>deprecated</sup>](#Find)
|
- [Find<sup>deprecated</sup>](#Find)
|
||||||
@@ -69,6 +70,7 @@ import (
|
|||||||
- [FlatMap](#FlatMap)
|
- [FlatMap](#FlatMap)
|
||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
|
- [ReverseCopy](#ReverseCopy)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
- [ReduceConcurrent](#ReduceConcurrent)
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
@@ -77,6 +79,7 @@ import (
|
|||||||
- [ReplaceAll](#ReplaceAll)
|
- [ReplaceAll](#ReplaceAll)
|
||||||
- [Repeat](#Repeat)
|
- [Repeat](#Repeat)
|
||||||
- [Shuffle](#Shuffle)
|
- [Shuffle](#Shuffle)
|
||||||
|
- [ShuffleCopy](#ShuffleCopy)
|
||||||
- [IsAscending](#IsAscending)
|
- [IsAscending](#IsAscending)
|
||||||
- [IsDescending](#IsDescending)
|
- [IsDescending](#IsDescending)
|
||||||
- [IsSorted](#IsSorted)
|
- [IsSorted](#IsSorted)
|
||||||
@@ -874,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>
|
### <span id="Filter">Filter</span>
|
||||||
|
|
||||||
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
||||||
@@ -1728,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>
|
### <span id="Reduce">Reduce</span>
|
||||||
|
|
||||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果。</p>
|
<p>将切片中的元素依次运行iteratee函数,返回运行结果。</p>
|
||||||
@@ -1962,7 +2028,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Shuffle">Shuffle</span>
|
### <span id="Shuffle">Shuffle</span>
|
||||||
|
|
||||||
<p>随机打乱切片中的元素顺序</p>
|
<p>随机打乱切片中的元素顺序。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -1989,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>
|
### <span id="IsAscending">IsAscending</span>
|
||||||
|
|
||||||
<p>检查切片元素是否按升序排列。</p>
|
<p>检查切片元素是否按升序排列。</p>
|
||||||
@@ -2999,7 +3096,7 @@ func main() {
|
|||||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
func JoinFunc[T any](slice []T, sep string, transform func(T) T) 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/55ib3SB5fM2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -3029,7 +3126,7 @@ func main() {
|
|||||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
func ConcatBy[T any](slice []T, sep T, connector func(T, T) 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/6QcUpcY4UMW)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -951,7 +951,7 @@ func main() {
|
|||||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) 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/tBV5Nc-XDX2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -984,7 +984,7 @@ func main() {
|
|||||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) 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/CjeoNw2eac_G)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import (
|
|||||||
- [TemplateReplace](#TemplateReplace)
|
- [TemplateReplace](#TemplateReplace)
|
||||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||||
- [ExtractContent](#ExtractContent)
|
- [ExtractContent](#ExtractContent)
|
||||||
|
- [FindAllOccurrences](#FindAllOccurrences)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -1708,7 +1709,7 @@ func main() {
|
|||||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -1741,7 +1742,7 @@ func main() {
|
|||||||
func ExtractContent(s, start, end string) []string
|
func ExtractContent(s, start, end 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/Ay9UIk7Rum9)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -1759,4 +1760,32 @@ func main() {
|
|||||||
// Output:
|
// Output:
|
||||||
// [content1 content2 content1]
|
// [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]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -509,7 +509,7 @@ func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
|||||||
func (tc *TryCatch) Do()
|
func (tc *TryCatch) Do()
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/D5Mdb0mRj0P)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -529,8 +529,6 @@ func main() {
|
|||||||
return errors.New("error in try block")
|
return errors.New("error in try block")
|
||||||
}).Catch(func(ctx context.Context, err error) {
|
}).Catch(func(ctx context.Context, err error) {
|
||||||
calledCatch = true
|
calledCatch = true
|
||||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
|
||||||
// fmt.Println(err.Error())
|
|
||||||
}).Finally(func(ctx context.Context) {
|
}).Finally(func(ctx context.Context) {
|
||||||
calledFinally = true
|
calledFinally = true
|
||||||
}).Do()
|
}).Do()
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||||
result, err := ToJson(aMap)
|
result, err := convertor.ToJson(aMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%v", err)
|
fmt.Printf("%v", err)
|
||||||
@@ -1123,7 +1123,7 @@ func main() {
|
|||||||
|
|
||||||
<p>Converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int</p>
|
<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](todo)</span></b>
|
<b>Signature:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/X3itkCxwB_x)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func ToBigInt[T any](v T) (*big.Int, error)
|
func ToBigInt[T any](v T) (*big.Int, error)
|
||||||
|
|||||||
@@ -1435,7 +1435,7 @@ func main() {
|
|||||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1472,7 +1472,7 @@ func main() {
|
|||||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1620,7 +1620,7 @@ func main() {
|
|||||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]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/qhsbf8BJ6Mf)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1659,7 +1659,7 @@ func main() {
|
|||||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName 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/qhsbf8BJ6Mf)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1586,7 +1586,7 @@ func main() {
|
|||||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/MCIDvHNOGGb)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1616,7 +1616,7 @@ func main() {
|
|||||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/9m6JMk1LB7-)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1646,7 +1646,7 @@ func main() {
|
|||||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/rbW51cDtM_2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1087,7 +1087,7 @@ func main() {
|
|||||||
func GetExeOrDllVersion(filePath string) (string, error)
|
func GetExeOrDllVersion(filePath 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/iLRrDBhE38E)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -1177,7 +1177,7 @@ func main() {
|
|||||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/uHuV4YgXf8F)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1210,7 +1210,7 @@ func main() {
|
|||||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/FkNZDXvHD2l)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1243,7 +1243,7 @@ func main() {
|
|||||||
func Permutation(n, k uint) uint
|
func Permutation(n, k uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/MgobwH_FOxj)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1276,7 +1276,7 @@ func main() {
|
|||||||
func Combination(n, k uint) uint
|
func Combination(n, k uint) uint
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/ENFQRDQUFi9)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ func main() {
|
|||||||
func RandNumberOfLength(len int) int
|
func RandNumberOfLength(len int) int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
<b>Signature:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/oyZbuV7bu7b)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import (
|
|||||||
- [DropRightWhile](#DropRightWhile)
|
- [DropRightWhile](#DropRightWhile)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [EqualWith](#EqualWith)
|
- [EqualWith](#EqualWith)
|
||||||
|
- [EqualUnordered](#EqualUnordered)
|
||||||
- [Every](#Every)
|
- [Every](#Every)
|
||||||
- [Filter](#Filter)
|
- [Filter](#Filter)
|
||||||
- [FilterConcurrent](#FilterConcurrent)
|
- [FilterConcurrent](#FilterConcurrent)
|
||||||
@@ -69,6 +70,7 @@ import (
|
|||||||
- [FlatMap](#FlatMap)
|
- [FlatMap](#FlatMap)
|
||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
|
- [ReverseCopy](#ReverseCopy)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
- [ReduceConcurrent](#ReduceConcurrent)
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
@@ -77,6 +79,7 @@ import (
|
|||||||
- [ReplaceAll](#ReplaceAll)
|
- [ReplaceAll](#ReplaceAll)
|
||||||
- [Repeat](#Repeat)
|
- [Repeat](#Repeat)
|
||||||
- [Shuffle](#Shuffle)
|
- [Shuffle](#Shuffle)
|
||||||
|
- [ShuffleCopy](#ShuffleCopy)
|
||||||
- [IsAscending](#IsAscending)
|
- [IsAscending](#IsAscending)
|
||||||
- [IsDescending](#IsDescending)
|
- [IsDescending](#IsDescending)
|
||||||
- [IsSorted](#IsSorted)
|
- [IsSorted](#IsSorted)
|
||||||
@@ -839,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>
|
### <span id="Every">Every</span>
|
||||||
|
|
||||||
<p>Return true if all of the values in the slice pass the predicate function.</p>
|
<p>Return true if all of the values in the slice pass the predicate function.</p>
|
||||||
@@ -1724,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>
|
### <span id="Reduce">Reduce</span>
|
||||||
|
|
||||||
<p>Reduce slice.</p>
|
<p>Reduce slice.</p>
|
||||||
@@ -1986,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>
|
### <span id="IsAscending">IsAscending</span>
|
||||||
|
|
||||||
<p>Checks if a slice is ascending order.</p>
|
<p>Checks if a slice is ascending order.</p>
|
||||||
@@ -2995,7 +3092,7 @@ func main() {
|
|||||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
func JoinFunc[T any](slice []T, sep string, transform func(T) T) 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/55ib3SB5fM2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -3025,7 +3122,7 @@ func main() {
|
|||||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
func ConcatBy[T any](slice []T, sep T, connector func(T, T) 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/6QcUpcY4UMW)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -950,7 +950,7 @@ func main() {
|
|||||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) 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/tBV5Nc-XDX2)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -983,7 +983,7 @@ func main() {
|
|||||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) 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/CjeoNw2eac_G)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ import (
|
|||||||
- [Rotate](#Rotate)
|
- [Rotate](#Rotate)
|
||||||
- [TemplateReplace](#TemplateReplace)
|
- [TemplateReplace](#TemplateReplace)
|
||||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||||
- [ExtractContent](#RegexMatchAllGroups)
|
- [ExtractContent](#ExtractContent)
|
||||||
|
- [FindAllOccurrences](#FindAllOccurrences)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -1743,7 +1744,7 @@ func main() {
|
|||||||
func ExtractContent(s, start, end string) []string
|
func ExtractContent(s, start, end 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/Ay9UIk7Rum9)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -1761,4 +1762,32 @@ func main() {
|
|||||||
// Output:
|
// Output:
|
||||||
// [content1 content2 content1]
|
// [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]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -507,7 +507,7 @@ func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
|||||||
func (tc *TryCatch) Do()
|
func (tc *TryCatch) Do()
|
||||||
```
|
```
|
||||||
|
|
||||||
<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/D5Mdb0mRj0P)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ outline: deep
|
|||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.5. </b>
|
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.6. </b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ outline: deep
|
|||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.5。</b>
|
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.6。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||||
|
|||||||
185
eventbus/eventbus.go
Normal file
185
eventbus/eventbus.go
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// 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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
func (eb *EventBus[T]) ClearListeners() {
|
||||||
|
eb.mu.Lock()
|
||||||
|
defer eb.mu.Unlock()
|
||||||
|
|
||||||
|
eb.listeners = sync.Map{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearListenersByTopic clears all the listeners by topic.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
}
|
||||||
220
eventbus/eventbus_test.go
Normal file
220
eventbus/eventbus_test.go
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
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.Equal("event1", events[0])
|
||||||
|
assert.Equal("event2", events[1])
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/validator"
|
"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
|
// FileReader is a reader supporting offset seeking and reading one
|
||||||
@@ -422,8 +424,15 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
defer zipReader.Close()
|
defer zipReader.Close()
|
||||||
|
|
||||||
for _, f := range zipReader.File {
|
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
|
// issue#62: fix ZipSlip bug
|
||||||
path, err := safeFilepathJoin(destPath, f.Name)
|
path, err := safeFilepathJoin(destPath, decodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type tagVS_FIXEDFILEINFO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExeOrDllVersion get the version of exe or dll file on windows.
|
// GetExeOrDllVersion get the version of exe or dll file on windows.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/iLRrDBhE38E
|
||||||
func GetExeOrDllVersion(filePath string) (string, error) {
|
func GetExeOrDllVersion(filePath string) (string, error) {
|
||||||
// 加载系统dll
|
// 加载系统dll
|
||||||
versionDLL := syscall.NewLazyDLL("version.dll")
|
versionDLL := syscall.NewLazyDLL("version.dll")
|
||||||
|
|||||||
@@ -145,10 +145,14 @@ func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
|||||||
|
|
||||||
// Max return max value of numbers.
|
// Max return max value of numbers.
|
||||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
func Max[T constraints.Ordered](items ...T) T {
|
||||||
max := numbers[0]
|
if len(items) < 1 {
|
||||||
|
panic("mathutil.Max: empty list")
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range numbers {
|
max := items[0]
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
if max < v {
|
if max < v {
|
||||||
max = v
|
max = v
|
||||||
}
|
}
|
||||||
@@ -181,10 +185,14 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
|||||||
|
|
||||||
// Min return min value of numbers.
|
// Min return min value of numbers.
|
||||||
// Play: https://go.dev/play/p/21BER_mlGUj
|
// Play: https://go.dev/play/p/21BER_mlGUj
|
||||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
func Min[T constraints.Ordered](items ...T) T {
|
||||||
min := numbers[0]
|
if len(items) < 1 {
|
||||||
|
panic("mathutil.min: empty list")
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range numbers {
|
min := items[0]
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
if min > v {
|
if min > v {
|
||||||
min = v
|
min = v
|
||||||
}
|
}
|
||||||
@@ -400,7 +408,7 @@ func Div[T constraints.Float | constraints.Integer](x T, y T) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Variance returns the variance of numbers.
|
// Variance returns the variance of numbers.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/uHuV4YgXf8F
|
||||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||||
n := len(numbers)
|
n := len(numbers)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@@ -418,13 +426,13 @@ func Variance[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StdDev returns the standard deviation of numbers.
|
// StdDev returns the standard deviation of numbers.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/FkNZDXvHD2l
|
||||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||||
return math.Sqrt(Variance(numbers))
|
return math.Sqrt(Variance(numbers))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permutation calculate P(n, k).
|
// Permutation calculate P(n, k).
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/MgobwH_FOxj
|
||||||
func Permutation(n, k uint) uint {
|
func Permutation(n, k uint) uint {
|
||||||
if n < k {
|
if n < k {
|
||||||
return 0
|
return 0
|
||||||
@@ -437,7 +445,7 @@ func Permutation(n, k uint) uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Combination calculate C(n, k).
|
// Combination calculate C(n, k).
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/ENFQRDQUFi9
|
||||||
func Combination(n, k uint) uint {
|
func Combination(n, k uint) uint {
|
||||||
if n < k {
|
if n < k {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ func TestMax(t *testing.T) {
|
|||||||
assert.Equal(0, Max(0, 0))
|
assert.Equal(0, Max(0, 0))
|
||||||
assert.Equal(3, Max(1, 2, 3))
|
assert.Equal(3, Max(1, 2, 3))
|
||||||
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
||||||
|
assert.Equal("abc", Max("a", "ab", "abc"))
|
||||||
|
|
||||||
type Integer int
|
type Integer int
|
||||||
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
||||||
@@ -212,6 +213,8 @@ func TestMin(t *testing.T) {
|
|||||||
assert.Equal(0, Min(0, 0))
|
assert.Equal(0, Min(0, 0))
|
||||||
assert.Equal(1, Min(1, 2, 3))
|
assert.Equal(1, Min(1, 2, 3))
|
||||||
assert.Equal(1.1, Min(1.2, 1.4, 1.1, 1.4))
|
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) {
|
func TestMinBy(t *testing.T) {
|
||||||
|
|||||||
@@ -126,12 +126,24 @@ func RandFloat(min, max float64, precision int) float64 {
|
|||||||
|
|
||||||
n := rand.Float64()*(max-min) + min
|
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.
|
// RandFloats generate a slice of random float64 numbers of length that do not repeat.
|
||||||
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
||||||
func RandFloats(length int, min, max float64, precision int) []float64 {
|
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)
|
nums := make([]float64, length)
|
||||||
used := make(map[float64]struct{}, length)
|
used := make(map[float64]struct{}, length)
|
||||||
for i := 0; i < length; {
|
for i := 0; i < length; {
|
||||||
@@ -335,7 +347,7 @@ func UUIdV4() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RandNumberOfLength 生成一个长度为len的随机数
|
// RandNumberOfLength 生成一个长度为len的随机数
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/oyZbuV7bu7b
|
||||||
func RandNumberOfLength(len int) int {
|
func RandNumberOfLength(len int) int {
|
||||||
m := int(math.Pow10(len) - 1)
|
m := int(math.Pow10(len) - 1)
|
||||||
i := int(math.Pow10(len - 1))
|
i := int(math.Pow10(len - 1))
|
||||||
|
|||||||
@@ -197,6 +197,14 @@ func TestRandFloats(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(len(numbers), 5)
|
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) {
|
func TestRandIntSlice(t *testing.T) {
|
||||||
|
|||||||
@@ -220,6 +220,28 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
|
|||||||
return true
|
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.
|
// Every return true if all of the values in the slice pass the predicate function.
|
||||||
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
||||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||||
@@ -980,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
|
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
||||||
func Shuffle[T any](slice []T) []T {
|
func Shuffle[T any](slice []T) []T {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
@@ -992,6 +1026,20 @@ func Shuffle[T any](slice []T) []T {
|
|||||||
return slice
|
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.
|
// IsAscending checks if a slice is ascending order.
|
||||||
// Play: https://go.dev/play/p/9CtsFjet4SH
|
// Play: https://go.dev/play/p/9CtsFjet4SH
|
||||||
func IsAscending[T constraints.Ordered](slice []T) bool {
|
func IsAscending[T constraints.Ordered](slice []T) bool {
|
||||||
@@ -1415,7 +1463,7 @@ func Frequency[T comparable](slice []T) map[T]int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JoinFunc joins the slice elements into a single string with the given separator.
|
// JoinFunc joins the slice elements into a single string with the given separator.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/55ib3SB5fM2
|
||||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
for i, v := range slice {
|
for i, v := range slice {
|
||||||
@@ -1428,7 +1476,7 @@ func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConcatBy concats the elements of a slice into a single value using the provided separator and connector function.
|
// ConcatBy concats the elements of a slice into a single value using the provided separator and connector function.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/6QcUpcY4UMW
|
||||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T {
|
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T {
|
||||||
var result T
|
var result T
|
||||||
|
|
||||||
|
|||||||
@@ -937,6 +937,41 @@ func ExampleReverse() {
|
|||||||
// [d c b a]
|
// [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() {
|
func ExampleIsAscending() {
|
||||||
|
|
||||||
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
||||||
@@ -1300,3 +1335,15 @@ func ExampleConcatBy() {
|
|||||||
// Alice | Bob | Charlie
|
// Alice | Bob | Charlie
|
||||||
// 90
|
// 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -1114,6 +1115,17 @@ func TestReverse(t *testing.T) {
|
|||||||
assert.Equal([]string{"e", "d", "c", "b", "a"}, s2)
|
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) {
|
func TestDifference(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1329,6 +1341,18 @@ func TestShuffle(t *testing.T) {
|
|||||||
assert.Equal(5, len(result))
|
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) {
|
func TestIndexOf(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1794,6 +1818,8 @@ func TestFilterConcurrent(t *testing.T) {
|
|||||||
nums := []int{1, 2, 3, 4, 5, 6}
|
nums := []int{1, 2, 3, 4, 5, 6}
|
||||||
expected := []int{4, 5, 6}
|
expected := []int{4, 5, 6}
|
||||||
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
|
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
|
||||||
|
sort.Ints(actual)
|
||||||
|
sort.Ints(expected)
|
||||||
assert.Equal(expected, actual)
|
assert.Equal(expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1926,3 +1952,25 @@ func TestConcatBy(t *testing.T) {
|
|||||||
assert.Equal(90, result.Age)
|
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{}
|
distinct := map[string]bool{}
|
||||||
|
|
||||||
for _, v := range s.source {
|
for _, v := range s.source {
|
||||||
// todo: performance issue
|
|
||||||
k := hashKey(v)
|
k := hashKey(v)
|
||||||
if _, ok := distinct[k]; !ok {
|
if _, ok := distinct[k]; !ok {
|
||||||
distinct[k] = true
|
distinct[k] = true
|
||||||
@@ -395,6 +394,7 @@ func (s Stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// 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 {
|
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int {
|
||||||
for i, v := range s.source {
|
for i, v := range s.source {
|
||||||
if equal(v, target) {
|
if equal(v, target) {
|
||||||
@@ -405,6 +405,7 @@ func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// 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 {
|
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int {
|
||||||
for i := len(s.source) - 1; i >= 0; i-- {
|
for i := len(s.source) - 1; i >= 0; i-- {
|
||||||
if equal(s.source[i], target) {
|
if equal(s.source[i], target) {
|
||||||
|
|||||||
@@ -737,15 +737,15 @@ func RegexMatchAllGroups(pattern, str string) [][]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExtractContent extracts the content between the start and end strings in the source string.
|
// ExtractContent extracts the content between the start and end strings in the source string.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/Ay9UIk7Rum9
|
||||||
func ExtractContent(s, start, end string) []string {
|
func ExtractContent(str, start, end string) []string {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if _, after, ok := strings.Cut(s, start); ok {
|
if _, after, ok := strings.Cut(str, start); ok {
|
||||||
if before, _, ok := strings.Cut(after, end); ok {
|
if before, _, ok := strings.Cut(after, end); ok {
|
||||||
result = append(result, before)
|
result = append(result, before)
|
||||||
s = after
|
str = after
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -756,3 +756,20 @@ func ExtractContent(s, start, end string) []string {
|
|||||||
|
|
||||||
return result
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -763,5 +763,13 @@ func ExampleExtractContent() {
|
|||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [content1 content2 content1]
|
// [content1 content2 content1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFindAllOccurrences() {
|
||||||
|
result := FindAllOccurrences("ababab", "ab")
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [0 2 4]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -937,3 +937,32 @@ func TestExtractContent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindAllOccurrences(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFindAllOccurrences")
|
||||||
|
|
||||||
|
var empty []int
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
substr string
|
||||||
|
expected []int
|
||||||
|
}{
|
||||||
|
{"", "", empty},
|
||||||
|
{"", "a", empty},
|
||||||
|
{"a", "", []int{0}},
|
||||||
|
{"a", "a", []int{0}},
|
||||||
|
{"aa", "a", []int{0, 1}},
|
||||||
|
{"ababab", "ab", []int{0, 2, 4}},
|
||||||
|
{"ababab", "ba", []int{1, 3}},
|
||||||
|
{"ababab", "c", empty},
|
||||||
|
{"ababab", "ababab", []int{0}},
|
||||||
|
{"ababab", "abababc", empty},
|
||||||
|
{"ababab", "abababa", empty},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
assert.Equal(tt.expected, FindAllOccurrences(tt.input, tt.substr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user