mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-18 03:32:26 +08:00
Compare commits
35 Commits
a254ebdc8e
...
v2.3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ffff0e3f3 | ||
|
|
8ebb8a028e | ||
|
|
995ffb799f | ||
|
|
3cd546d7f2 | ||
|
|
7fb49515ce | ||
|
|
8f3ea60636 | ||
|
|
58a37b7e8d | ||
|
|
6bd61460d3 | ||
|
|
05b85a2131 | ||
|
|
1eb793420e | ||
|
|
05f9854945 | ||
|
|
3be706e23f | ||
|
|
b5e7312353 | ||
|
|
95a894e53f | ||
|
|
8322951475 | ||
|
|
6b2c91b0f6 | ||
|
|
ec161f335d | ||
|
|
d1a8f37a71 | ||
|
|
a769257017 | ||
|
|
f3579fc142 | ||
|
|
de877e5278 | ||
|
|
08f14d2b08 | ||
|
|
0ed2b11ba1 | ||
|
|
643edc1468 | ||
|
|
e2ff83649a | ||
|
|
a7fecfc73b | ||
|
|
8bbae69175 | ||
|
|
840ea8f3c5 | ||
|
|
a4e89bd7c1 | ||
|
|
2015d36b08 | ||
|
|
921f218ef7 | ||
|
|
0a2cc9c928 | ||
|
|
ed93aae970 | ||
|
|
1671f7856a | ||
|
|
1008dd4956 |
68
README.md
68
README.md
@@ -4,12 +4,13 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
[](https://codecov.io/gh/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||
[](https://gurubase.io/g/lancet)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.4. </b>
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.5. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
@@ -320,12 +321,19 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
- **<big>ToStdBase64</big>** : converts a value to a string encoded in standard Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToStdBase64)]
|
||||
[[play](https://go.dev/play/p/_fLJqJD3NMo)]
|
||||
- **<big>ToUrlBase64</big>** : converts a value to a string encoded in url Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToUrlBase64)]
|
||||
[[play](https://go.dev/play/p/C_d0GlvEeUR)]
|
||||
- **<big>ToRawStdBase64</big>** : converts a value to a string encoded in raw standard Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawStdBase64)]
|
||||
[[play](https://go.dev/play/p/wSAr3sfkDcv)]
|
||||
- **<big>ToRawUrlBase64</big>** : converts a value to a string encoded in raw url Base64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawUrlBase64)]
|
||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||
- **<big>ToBigInt</big>** : converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToBigInt)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="cryptor"> 6. Cryptor package is for data encryption and decryption. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -474,7 +482,12 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- **<big>RsaDecryptOAEP</big>** : decrypts the data with RSA-OAEP
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
- **<big>RsaSign</big>** : signs the data with RSA.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaSign)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>RsaVerifySign</big>** : verifies the signature of the data with RSA.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaVerifySign)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -618,7 +631,15 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>GenerateDatetimesBetween</big>** : returns a slice of strings between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
|
||||
- **<big>Min</big>** : returns the earliest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Min)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Max</big>** : returns the latest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#Max)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>MaxMin</big>** : returns the latest and earliest time among the given times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#MaxMin)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<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>
|
||||
|
||||
@@ -754,6 +775,9 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ParallelChunkRead</big>** : reads the file in parallel and send each chunk of lines to the specified channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ParallelChunkRead)]
|
||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||
- **<big>GetExeOrDllVersion</big>** : Get the version of exe or dll file on windows os.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1119,7 +1143,18 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- **<big>Div</big>** : returns the result of x divided by y.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Div)]
|
||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||
|
||||
- **<big>Variance</big>** : returns the variance of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Variance)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>StdDev</big>** : returns the standard deviation of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#StdDev)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Permutation</big>** : calculates P(n, k).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Permutation)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Combination</big>** : calculates C(n, k).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Combination)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1280,7 +1315,9 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandSliceFromGivenSlice</big>** : generate a random slice of length num from given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
|
||||
- **<big>RandNumberOfLength</big>** : generates a random int number of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandNumberOfLength)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<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>
|
||||
|
||||
@@ -1574,7 +1611,12 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Frequency</big>** : counts the frequency of each element in the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Frequency)]
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
|
||||
- **<big>JoinFunc</big>** : joins the slice elements into a single string with the given separator.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#JoinFunc)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ConcatBy</big>** : concats the elements of a slice into a single value using the provided separator and connector function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ConcatBy)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<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>
|
||||
|
||||
@@ -1665,6 +1707,12 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>ToSlice</big>** : returns the elements in the stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
- **<big>IndexOf</big>** : returns the index of the first occurrence of the specified element in this stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>LastIndexOf</big>** : returns the index of the last occurrence of the specified element in this stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1846,6 +1894,9 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>RegexMatchAllGroups</big>** : matches all subgroups in a string using a regular expression and returns the result.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
- **<big>ExtractContent</big>** : extracts the content between the start and end strings in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#ExtractContent)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
|
||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||
@@ -2196,6 +2247,9 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
- **<big>TryUnwrap</big>** : check if err is nil then it returns a valid value. If err is not nil, TryUnwrap panics with err.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/xerror.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
- **<big>TryCatch</big>** : simple simulation of Java-style try-catch.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/xerror.md#TryCatch)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
## How to Contribute
|
||||
|
||||
|
||||
104
README_zh-CN.md
104
README_zh-CN.md
@@ -4,12 +4,13 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
[](https://codecov.io/gh/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||
[](https://gurubase.io/g/lancet)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -37,7 +38,7 @@
|
||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.4。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.5。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
@@ -320,13 +321,19 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
- **<big>ToStdBase64</big>** : 将值转换为StdBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToStdBase64)]
|
||||
[[play](https://go.dev/play/p/_fLJqJD3NMo)]
|
||||
- **<big>ToUrlBase64</big>** : 将值转换为url Base64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToUrlBase64)]
|
||||
[[play](https://go.dev/play/p/C_d0GlvEeUR)]
|
||||
- **<big>ToRawStdBase64</big>** : 将值转换为RawStdBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawStdBase64)]
|
||||
[[play](https://go.dev/play/p/wSAr3sfkDcv)]
|
||||
- **<big>ToRawUrlBase64</big>** : 将值转换为RawUrlBase64编码的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawUrlBase64)]
|
||||
|
||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||
- **<big>ToBigInt</big>** : 将整数转为*big.Int。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -476,7 +483,12 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
- **<big>RsaDecryptOAEP</big>** : rsa OAEP解密。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
- **<big>RsaSign</big>** : 应用RSA算法签名数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaSign)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>RsaVerifySign</big>** : 验证数据的签名是否符合RSA算法。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaVerifySign)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="datetime"> 7. datetime日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -621,6 +633,15 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>GenerateDatetimesBetween</big>** : 生成从start到end的所有日期时间的字符串列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
- **<big>Min</big>** : 返回最早时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Min)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Max</big>** : 返回最晚时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#Max)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>MaxMin</big>** : 返回最早和最晚时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
|
||||
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||
@@ -753,7 +774,9 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ParallelChunkRead</big>** : 并行读取文件并将每个块的行发送到指定通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ParallelChunkRead)]
|
||||
[[play](https://go.dev/play/p/teMXnCsdSEw)]
|
||||
|
||||
- **<big>GetExeOrDllVersion</big>** : 返回exe,dll文件版本号(仅Window平台)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
|
||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||
@@ -1120,7 +1143,18 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- **<big>Div</big>** : 除法运算。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Div)]
|
||||
[[play](https://go.dev/play/p/WLxDdGXXYat)]
|
||||
|
||||
- **<big>Variance</big>** : 计算方差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Variance)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>StdDev</big>** : 计算标准差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#StdDev)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Permutation</big>** : 计算排列数P(n, k)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Permutation)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>Combination</big>** : 计算组合数C(n, k)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1281,7 +1315,9 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandSliceFromGivenSlice</big>** : 从给定切片中生成长度为 num 的随机切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
|
||||
- **<big>RandNumberOfLength</big>** : 生成指定长度的随机数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1300,7 +1336,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
- **<big>RetryFunc</big>** : 重试执行的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryFunc)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认5。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
- **<big>BackoffStrategy</big>** : 定义计算退避间隔的方法的接口。
|
||||
@@ -1572,7 +1608,12 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Frequency</big>** : 计算切片中每个元素出现的频率。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Frequency)]
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
|
||||
- **<big>JoinFunc</big>** : 将切片元素用给定的分隔符连接成一个单一的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#JoinFunc)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>ConcatBy</big>** : 将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1663,7 +1704,12 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>ToSlice</big>** : 返回 stream 中的元素切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
|
||||
- **<big>IndexOf</big>** : 返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
- **<big>LastIndexOf</big>** : 返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1848,6 +1894,9 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>RegexMatchAllGroups</big>** : 使用正则表达式匹配字符串中的所有子组并返回结果。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -2060,7 +2109,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsCreditCard</big>** : 验证字符串是否是信用卡号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效 dns。
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效dns。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
|
||||
@@ -2096,10 +2145,10 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsIp</big>** : 验证字符串是否是 ip 地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是 ipv4 地址。
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是ipv4地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是 ipv6 地址。
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
||||
@@ -2114,10 +2163,10 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsZeroValue</big>** : 判断传入的参数值是否为零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk(汉字内部代码扩展规范)。
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为gbk(汉字内部代码扩展规范)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsGBK)]
|
||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||
- **<big>IsASCII</big>** : 验证字符串全部为 ASCII 字符。
|
||||
- **<big>IsASCII</big>** : 验证字符串全部为ASCII字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsASCII)]
|
||||
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
|
||||
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
|
||||
@@ -2132,13 +2181,13 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsBase64URL</big>** : 检查字符串是否是有效的 base64 url。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsBase64URL)]
|
||||
[[play](https://go.dev/play/p/vhl4mr8GZ6S)]
|
||||
- **<big>IsJWT</big>** : 检查字符串是否是有效的 JSON Web Token (JWT)。
|
||||
- **<big>IsJWT</big>** : 检查字符串是否是有效的JSON Web Token (JWT)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsJWT)]
|
||||
[[play](https://go.dev/play/p/R6Op7heJbKI)]
|
||||
- **<big>IsVisa</big>** : 检查字符串是否是有效的 visa 卡号。
|
||||
- **<big>IsVisa</big>** : 检查字符串是否是有效的visa卡号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsVisa)]
|
||||
[[play](https://go.dev/play/p/SdS2keOyJsl)]
|
||||
- **<big>IsMasterCard</big>** : 检查字符串是否是有效的 MasterCard 卡号。
|
||||
- **<big>IsMasterCard</big>** : 检查字符串是否是有效的MasterCard卡号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsMasterCard)]
|
||||
[[play](https://go.dev/play/p/CwWBFRrG27b)]
|
||||
- **<big>IsAmericanExpress</big>** : 检查字符串是否是有效的 American Express 卡号。
|
||||
@@ -2174,30 +2223,33 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
- **<big>XError_Unwrap</big>** : 解构 XEerror 为 error 对象。适配 github.com/pkg/errors。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Unwrap)
|
||||
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
|
||||
- **<big>XError_With</big>** : 添加与 XError 对象的键和值。
|
||||
- **<big>XError_With</big>** : 添加与XError对象的键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_With)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_Id</big>** : 设置 XError 对象的 id。
|
||||
- **<big>XError_Id</big>** : 设置XError对象的id。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Id)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Is</big>** : 检查目标 error 是否为 XError,两个错误中的 error.id 是否匹配。
|
||||
- **<big>XError_Is</big>** : 检查目标error是否为XError,两个错误中的error.id是否匹配。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Is)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Values</big>** : 返回由 With 设置的键和值的映射。将合并所有 XError 键和值。
|
||||
- **<big>XError_Values</big>** : 返回由With设置的键和值的映射。将合并所有XError键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Values)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_StackTrace</big>** : 返回与 pkg/error 兼容的堆栈信息。
|
||||
- **<big>XError_StackTrace</big>** : 返回与pkg/error兼容的堆栈信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_StackTrace)]
|
||||
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
|
||||
- **<big>XError_Info</big>** : 返回可打印的 XError 对象信息。
|
||||
- **<big>XError_Info</big>** : 返回可打印的XError对象信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Info)]
|
||||
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
|
||||
- **<big>XError_Error</big>** : 实现标准库的 error 接口。
|
||||
- **<big>XError_Error</big>** : 实现标准库的error接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#XError_Error)]
|
||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||
- **<big>TryUnwrap</big>** : 检查 error, 如果 err 为 nil 则展开,则它返回一个有效值,如果 err 不是 nil 则 Unwrap 使用 err 发生 panic。
|
||||
- **<big>TryUnwrap</big>** : 检查error, 如果err为nil则展开,则它返回一个有效值,如果err不是nil则Unwrap使用err发生panic。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
- **<big>TryCatch</big>** : 简单实现的java风格异常处理(try-catch-finally)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/xerror.md#TryCatch)]
|
||||
[[play](https://go.dev/play/p/todo)]
|
||||
|
||||
## 如何贡献代码
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
assert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
@@ -16,19 +16,19 @@ func TestLRUCache(t *testing.T) {
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
asssert.Equal(3, cache.Len())
|
||||
assert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(1, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(1, v)
|
||||
|
||||
v, ok = cache.Get(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, v)
|
||||
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -8,34 +8,34 @@ import (
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
assert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
assert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
assert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
assert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
assert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
|
||||
func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
assert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -62,23 +62,23 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
assert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
asssert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
}
|
||||
|
||||
func TestInsertionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestInsertionSort")
|
||||
assert := internal.NewAssert(t, "TestInsertionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -93,12 +93,12 @@ func TestInsertionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestSelectionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestSelectionSort")
|
||||
assert := internal.NewAssert(t, "TestSelectionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -113,12 +113,12 @@ func TestSelectionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestShellSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestShellSort")
|
||||
assert := internal.NewAssert(t, "TestShellSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -133,12 +133,12 @@ func TestShellSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestQuickSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestQuickSort")
|
||||
assert := internal.NewAssert(t, "TestQuickSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -153,12 +153,12 @@ func TestQuickSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestHeapSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestHeapSort")
|
||||
assert := internal.NewAssert(t, "TestHeapSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -173,12 +173,12 @@ func TestHeapSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestMergeSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestMergeSort")
|
||||
assert := internal.NewAssert(t, "TestMergeSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -193,12 +193,12 @@ func TestMergeSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestCountSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestCountSort")
|
||||
assert := internal.NewAssert(t, "TestCountSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -213,5 +213,5 @@ func TestCountSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", sortedPeopleByAge)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package compare
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
@@ -24,6 +25,13 @@ func compareValue(operator string, left, right any) bool {
|
||||
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
return compareRefValue(operator, left, right, leftType.Kind())
|
||||
|
||||
case reflect.Ptr:
|
||||
if leftVal, ok := left.(*big.Int); ok {
|
||||
if rightVal, ok := right.(*big.Int); ok {
|
||||
return compareBigInt(operator, leftVal, rightVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -155,169 +163,129 @@ func compareBasicValue(operator string, leftValue, rightValue any) bool {
|
||||
}
|
||||
|
||||
switch leftVal := leftValue.(type) {
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
left, err := convertor.ToBigInt(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareBigInt(operator, left, right)
|
||||
|
||||
case float32, float64:
|
||||
left, err := convertor.ToFloat(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
case string:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case string:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return compareStrings(operator, left, right)
|
||||
}
|
||||
|
||||
case bool:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case bool:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return compareBools(operator, left, right)
|
||||
}
|
||||
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
return compareFloats(operator, left, right)
|
||||
}
|
||||
case float32, float64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
left, err := convertor.ToBigInt(left)
|
||||
return compareBigInt(operator, left, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBigInt compares two big.Int values based on the operator
|
||||
func compareBigInt(operator string, left, right *big.Int) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left.Cmp(right) == 0
|
||||
case lessThan:
|
||||
return left.Cmp(right) < 0
|
||||
case greaterThan:
|
||||
return left.Cmp(right) > 0
|
||||
case lessOrEqual:
|
||||
return left.Cmp(right) <= 0
|
||||
case greaterOrEqual:
|
||||
return left.Cmp(right) >= 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareFloats compares two float64 values based on the operator
|
||||
func compareFloats(operator string, left, right float64) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareStrings compares two string values based on the operator
|
||||
func compareStrings(operator string, left, right string) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBools compares two boolean values based on the operator
|
||||
func compareBools(operator string, left, right bool) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package compare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -12,213 +13,191 @@ func TestEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEqual")
|
||||
|
||||
// basic type
|
||||
assert.Equal(true, Equal(1, 1))
|
||||
assert.Equal(true, Equal(int64(1), int64(1)))
|
||||
assert.Equal(true, Equal("a", "a"))
|
||||
assert.Equal(true, Equal(true, true))
|
||||
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
|
||||
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
|
||||
|
||||
assert.Equal(false, Equal(1, 2))
|
||||
assert.Equal(false, Equal(1, int64(1)))
|
||||
assert.Equal(false, Equal("a", "b"))
|
||||
assert.Equal(false, Equal(true, false))
|
||||
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
|
||||
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
|
||||
|
||||
// time
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
time3 := time1.Add(time.Second)
|
||||
|
||||
assert.Equal(false, Equal(time1, time2))
|
||||
assert.Equal(true, Equal(time2, time3))
|
||||
|
||||
// struct
|
||||
st1 := struct {
|
||||
A string
|
||||
B string
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), false},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}, false},
|
||||
// {time.Now(), time.Now(), true},
|
||||
// {time.Now(), time.Now().Add(time.Second), false},
|
||||
{[]byte("hello"), []byte("hello"), true},
|
||||
{[]byte("hello"), []byte("world"), false},
|
||||
{json.Number("123"), json.Number("123"), true},
|
||||
{json.Number("123"), json.Number("124"), false},
|
||||
|
||||
{big.NewInt(123), big.NewInt(123), true},
|
||||
}
|
||||
|
||||
st2 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Equal(tt.left, tt.right))
|
||||
}
|
||||
|
||||
st3 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a1",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
assert.Equal(true, Equal(st1, st2))
|
||||
assert.Equal(false, Equal(st1, st3))
|
||||
|
||||
//byte slice
|
||||
bs1 := []byte("hello")
|
||||
bs2 := []byte("hello")
|
||||
assert.Equal(true, Equal(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, Equal(jsonNumber1, jsonNumber2))
|
||||
|
||||
}
|
||||
|
||||
func TestEqualValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestEqualValue")
|
||||
|
||||
assert.Equal(true, EqualValue(1, 1))
|
||||
assert.Equal(true, EqualValue(int(1), int64(1)))
|
||||
assert.Equal(true, EqualValue(1, "1"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), true},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
}
|
||||
|
||||
assert.Equal(false, EqualValue(1, "2"))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, EqualValue(jsonNumber1, 123))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, EqualValue(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestLessThan")
|
||||
|
||||
assert.Equal(true, LessThan(1, 2))
|
||||
assert.Equal(true, LessThan(1.1, 2.2))
|
||||
assert.Equal(true, LessThan("a", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessThan(time1, time2))
|
||||
|
||||
assert.Equal(false, LessThan(1, 1))
|
||||
assert.Equal(false, LessThan(1, int64(1)))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, LessThan(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, LessThan(jsonNumber1, jsonNumber2))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessThan(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterThan(2, 1))
|
||||
assert.Equal(true, GreaterThan(2.2, 1.1))
|
||||
assert.Equal(true, GreaterThan("b", "a"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "a", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterThan(time2, time1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterThan(tt.left, tt.right))
|
||||
}
|
||||
|
||||
assert.Equal(false, GreaterThan(1, 2))
|
||||
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||
assert.Equal(false, GreaterThan("b", "c"))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, GreaterThan(bs2, bs1))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, GreaterThan(jsonNumber2, jsonNumber1))
|
||||
}
|
||||
|
||||
func TestLessOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestLessOrEqual")
|
||||
|
||||
assert.Equal(true, LessOrEqual(1, 2))
|
||||
assert.Equal(true, LessOrEqual(1, 1))
|
||||
assert.Equal(true, LessOrEqual(1.1, 2.2))
|
||||
assert.Equal(true, LessOrEqual("a", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1, 1, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{2, 1, false},
|
||||
{1, int64(2), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessOrEqual(time1, time2))
|
||||
|
||||
assert.Equal(false, LessOrEqual(2, 1))
|
||||
assert.Equal(false, LessOrEqual(1, int64(2)))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, LessOrEqual(bs1, bs2))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, LessOrEqual(jsonNumber1, jsonNumber2))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(2, 1))
|
||||
assert.Equal(true, GreaterOrEqual(1, 1))
|
||||
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
|
||||
assert.Equal(true, GreaterOrEqual("b", "b"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{1, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "b", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 2, false},
|
||||
{int64(2), 1, false},
|
||||
{"b", "c", false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterOrEqual(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterOrEqual(1, 2))
|
||||
assert.Equal(false, GreaterOrEqual(int64(2), 1))
|
||||
assert.Equal(false, GreaterOrEqual("b", "c"))
|
||||
|
||||
bs1 := []byte("hello1")
|
||||
bs2 := []byte("hello2")
|
||||
assert.Equal(true, GreaterOrEqual(bs2, bs1))
|
||||
|
||||
// json.Number
|
||||
var jsonNumber1, jsonNumber2 json.Number
|
||||
json.Unmarshal([]byte(`123`), &jsonNumber1)
|
||||
json.Unmarshal([]byte(`124`), &jsonNumber2)
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(jsonNumber2, jsonNumber1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInDelta(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestInDelta")
|
||||
|
||||
assert.Equal(true, InDelta(1, 1, 0))
|
||||
assert.Equal(false, InDelta(1, 2, 0))
|
||||
tests := []struct {
|
||||
left float64
|
||||
right float64
|
||||
delta float64
|
||||
want bool
|
||||
}{
|
||||
{1, 1, 0, true},
|
||||
{1, 2, 0, false},
|
||||
{2.0 / 3.0, 0.66667, 0.001, true},
|
||||
{2.0 / 3.0, 0.0, 0.001, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 0, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 1e-14, true},
|
||||
{float64(float32(80.45)), float64(80.45), 0, false},
|
||||
{float64(float32(80.45)), float64(80.45), 1e-5, true},
|
||||
}
|
||||
|
||||
assert.Equal(true, InDelta(2.0/3.0, 0.66667, 0.001))
|
||||
assert.Equal(false, InDelta(2.0/3.0, 0.0, 0.001))
|
||||
|
||||
assert.Equal(false, InDelta(float64(74.96)-float64(20.48), 54.48, 0))
|
||||
assert.Equal(true, InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14))
|
||||
assert.Equal(false, InDelta(float64(float32(80.45)), float64(80.45), 0))
|
||||
assert.Equal(true, InDelta(float64(float32(80.45)), float64(80.45), 1e-5))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, InDelta(tt.left, tt.right, tt.delta))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +72,17 @@ func Nand[T, U any](a T, b U) bool {
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
} else {
|
||||
return elseValue
|
||||
}
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
// Deprecated: Use Ternary instead.
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
return Ternary(isTrue, ifValue, elseValue)
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ func ExampleNand() {
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
func ExampleTernary() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
result1 := Ternary(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
result2 := Ternary(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
|
||||
@@ -124,13 +124,13 @@ func TestNand(t *testing.T) {
|
||||
assert.Equal(false, Nand(1, 1))
|
||||
}
|
||||
|
||||
func TestTernaryOperator(t *testing.T) {
|
||||
func TestTernary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TernaryOperator")
|
||||
assert := internal.NewAssert(t, "TestTernary")
|
||||
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
|
||||
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
|
||||
assert.Equal(trueValue, Ternary(true, trueValue, falseValue))
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -74,7 +75,7 @@ func ToBytes(value any) ([]byte, error) {
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
c := make([]string, 0, len(s))
|
||||
if len(s) == 0 {
|
||||
c = append(c, "")
|
||||
}
|
||||
@@ -483,3 +484,36 @@ func ToRawUrlBase64(value any) string {
|
||||
return base64.RawURLEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToBigInt converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int
|
||||
// Play: todo
|
||||
func ToBigInt[T any](v T) (*big.Int, error) {
|
||||
result := new(big.Int)
|
||||
|
||||
switch v := any(v).(type) {
|
||||
case int:
|
||||
result.SetInt64(int64(v)) // Convert to int64 for big.Int
|
||||
case int8:
|
||||
result.SetInt64(int64(v))
|
||||
case int16:
|
||||
result.SetInt64(int64(v))
|
||||
case int32:
|
||||
result.SetInt64(int64(v))
|
||||
case int64:
|
||||
result.SetInt64(v)
|
||||
case uint:
|
||||
result.SetUint64(uint64(v)) // Convert to uint64 for big.Int
|
||||
case uint8:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint16:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint32:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint64:
|
||||
result.SetUint64(v)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type: %T", v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -571,3 +571,12 @@ func ExampleToRawUrlBase64() {
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToBigInt() {
|
||||
n := 9876543210
|
||||
bigInt, _ := ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -741,3 +742,83 @@ func TestToRawUrlBase64(t *testing.T) {
|
||||
d15, _ := base64.RawURLEncoding.DecodeString(r15)
|
||||
assert.Equal("4+3/4?=", string(d15))
|
||||
}
|
||||
|
||||
func TestToBigInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToBigInt")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want *big.Int
|
||||
hasErr bool
|
||||
}{
|
||||
{
|
||||
name: "int",
|
||||
input: 42,
|
||||
want: big.NewInt(42),
|
||||
},
|
||||
{
|
||||
name: "int8",
|
||||
input: int8(127),
|
||||
want: big.NewInt(127),
|
||||
},
|
||||
{
|
||||
name: "int16",
|
||||
input: int16(32000),
|
||||
want: big.NewInt(32000),
|
||||
},
|
||||
{
|
||||
name: "int32",
|
||||
input: int32(123456),
|
||||
want: big.NewInt(123456),
|
||||
},
|
||||
{
|
||||
name: "int64",
|
||||
input: int64(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint",
|
||||
input: uint(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint8",
|
||||
input: uint8(255),
|
||||
want: big.NewInt(255),
|
||||
},
|
||||
{
|
||||
name: "uint16",
|
||||
input: uint16(65535),
|
||||
want: big.NewInt(65535),
|
||||
},
|
||||
{
|
||||
name: "uint32",
|
||||
input: uint32(4294967295),
|
||||
want: big.NewInt(4294967295),
|
||||
},
|
||||
{
|
||||
name: "uint64",
|
||||
input: uint64(18446744073709551615),
|
||||
want: new(big.Int).SetUint64(18446744073709551615),
|
||||
},
|
||||
{
|
||||
name: "unsupported type",
|
||||
input: 3.14, // Unsupported type
|
||||
hasErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ToBigInt(tt.input)
|
||||
if (err != nil) != tt.hasErr {
|
||||
t.Errorf("ToBigInt() error = %v, hasErr %v", err, tt.hasErr)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
51
cryptor/rsa_private.pem
Normal file
51
cryptor/rsa_private.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
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
|
||||
-----END rsa private key-----
|
||||
@@ -1,51 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
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
|
||||
-----END rsa private key-----
|
||||
|
||||
14
cryptor/rsa_public.pem
Normal file
14
cryptor/rsa_public.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5IqWfYbW1NlTDWE2plFW
|
||||
qD6CTquA0Ar/1E66lY8OMtrdpxTmchirmoISWN0BD7r2tV9T/kHs44Sy3raAfkR5
|
||||
ixYF5FRkb63FdIAtoynsxS6MEE26fgWuDAa1xwNt+t/uivnpfJk25htpBNkKGT8i
|
||||
i0TPPLn1N15hMHenT6PzWVjGjQxWcp4dUA4gXTDuqaeu7Oy7Ku2yP90/ra+cjTV8
|
||||
DnBJ9enQhAfu1LivJO3FgmXeuC3uqhhM3t9ZbNy7tvJI5PXDCaS8iesBvCp5carT
|
||||
SXWLpFEgvIhXQIsXtxezKAP3gRd8r5JPQI9FZlxyUcyf+Htkn2A4qyKhFElnP1z9
|
||||
j0YLFhL/gQMdtNIY7yhSb29PyuCG7noz25swrfxbA7ZVppM0J19JNhlpqmusBKLB
|
||||
NqN+KMD8EDli7NLX17S9Dj2pQF9I8fVXPEhkdTb67rr7y3OUANKjh0Opnt3JLoj9
|
||||
u1X7BfCeUSR/qq3E8RFPeyxvP1tc5QVqKBG6UPBo8nLQqdzJhUd8a1YEfXIUbdHL
|
||||
s2q5WVFu2MDavIp634+fzfcIFRoBtdxf5aCdxLaLocsA/aLLyL1pK6K0rpdrSUtc
|
||||
EBMST26qIlU0Ht+SQtaMdE2gyjkMM5RpLh1q/gpow+0j3zu6f5tDsu3qwgjLIx78
|
||||
YCTGUuCpsVMzFK4tahYSPNkCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
@@ -1,14 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs+rfCwwvBb9JplwDAaNt
|
||||
pEPCm1DoS8PkqzwSSxfA7JHSMYdYUMq92vbSqEKomNgyksaGIiqDHop+9pHjYI1A
|
||||
ftd6mbZJwRtQxo+5eYGh88FzPqemmNubZk7SxGq0MEz1XmZ9viQyp3GxAJjeSdAG
|
||||
9GRdstNcczSy9Ij9YGJ8ehLhL/png4ZsLUtwDbYsilJDx28qDX/jJ/nbopaHWk2X
|
||||
TSu8KK3zXBjppTU4uKKicOswaJ6kfk9J6ItkQ15uS+z2eHsxpa8K++gIt2swJkiE
|
||||
RlqUzwiC75w92JH1nQPXqEqaaEx0izdHUmFF33cgGb6gw5tJePzOmYs8KLJcOhfJ
|
||||
QcqjW4MjCfnaw4tB/cpi3zYKzDoC7mzwitrkBO1MG11luzR1m9uMfWczL2hK2zMH
|
||||
I51vayC1d1T0gc56vS/SAdicl5OqcD6oc6Dmym3rguF/pauTIOrvGtipeYk/Mbb4
|
||||
qj2CI33QFTZc3G55yHVB6vDWIpMSWF60HHHqv7Ens4MIPIev0WS893vsNscg4Ph3
|
||||
QxXDNjOc3kEK17TnDGXmL7C+Ykfq9brm32IrOMZ4KR3NJ+aO83yLewPoQAy8QCC3
|
||||
2b1O3c1nAgSY9sIwJV8ikAdNDBhLnkXFrYE2ZFl/Kl5HXd0LCz/BQu3Ey0RsZfXI
|
||||
pD7KUcdNq3QRloTATntE9U0CAwEAAQ==
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwGdN8KE2NTK41cVN7i6m
|
||||
ZZS5J86gjNs0LJDHylb2GG+K4O8sfq98EMKMJ2xGnKoVRJXucVohr5Eiuf5zgxQe
|
||||
9mpYDyDQ0vnpBkoNkfzJNZQvcQFaIllUeH+eN4hSBhMegPspCr2BcmC/m/N40+Pj
|
||||
BMDaHSzeNE2SyIuyflLC7GhQvHnkcQXkqJVNC1yesV7zYKDV/xYPI0NxN0kE+4eR
|
||||
650A77jso4gloRUek0cpU4ztpe6Zz4za7AEKHmZO8pVHpQJihbNMhItbo6BcgeOF
|
||||
WImXyJfcbCtu1ayciaJ0Q45Z1btuF2wFwQjwZGt7DAvbzYwMBBiTpGxig/8kzibm
|
||||
7bL1Td7huW6Knqbfh4/v+2m+2aNK1u0TfncFUr17wDDfeVj/xeNOSbPu2X/AppjV
|
||||
X0rxmvWN+AByFfAuw7/kqMK7QZlA+5nNjmOojvryGOSu1he4PUnhRyJ7jofOIrLZ
|
||||
9YYBXpRiY/WB8t+xWIlaoPXFmsOxSgMwzQFGMlnSFy7nK9T4znE0QFknOQNbELPE
|
||||
B4UGLOEa5Tg6YD2ORDDSqCzMRdkE1kAgoMRC9DkRXE45KEcQlhMX9Pahwx3mPS4l
|
||||
MWABVudiEWyhGaR279OWjezqvtoLLBJ5GD9QL1XqaqCaJjp+qsHmX8re+MTA3ZJu
|
||||
yUtRoPXPsKCe2nZ6Ma87DlUCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
|
||||
@@ -209,7 +209,7 @@ func (dl *DoublyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (dl *DoublyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, dl.length)
|
||||
current := dl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
@@ -212,7 +212,7 @@ func (sl *SinglyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (sl *SinglyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, sl.length)
|
||||
current := sl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
@@ -31,7 +31,7 @@ func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *ArrayQueue[T]) Data() []T {
|
||||
items := []T{}
|
||||
items := make([]T, 0, q.tail-q.head)
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
items = append(items, q.data[i])
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewLinkedQueue[T any]() *LinkedQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *LinkedQueue[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, q.length)
|
||||
current := q.head
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewLinkedStack[T any]() *LinkedStack[T] {
|
||||
|
||||
// Data return stack data
|
||||
func (s *LinkedStack[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, s.length)
|
||||
current := s.top
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -100,12 +100,6 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
|
||||
//todo
|
||||
// bstree.DeletetNode(6, comparator)
|
||||
// bstree.Print()
|
||||
// acturl2 := bstree.InOrderTraverse()
|
||||
// assert.Equal([]int{2, 5, 7}, acturl2)
|
||||
}
|
||||
|
||||
func TestBSTree_Depth(t *testing.T) {
|
||||
|
||||
@@ -147,7 +147,7 @@ func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel i
|
||||
|
||||
printSpaces(firstSpaces)
|
||||
|
||||
newNodes := []*datastructure.TreeNode[T]{}
|
||||
newNodes := make([]*datastructure.TreeNode[T], 0, len(nodes)*2)
|
||||
for _, node := range nodes {
|
||||
if node != nil {
|
||||
fmt.Printf("%v", node.Value)
|
||||
|
||||
@@ -443,3 +443,50 @@ func GenerateDatetimesBetween(start, end time.Time, layout string, interval stri
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Min returns the earliest time among the given times.
|
||||
// Play: todo
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time {
|
||||
minTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return minTime
|
||||
}
|
||||
|
||||
// Max returns the latest time among the given times.
|
||||
// Play: todo
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time {
|
||||
maxTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime
|
||||
}
|
||||
|
||||
// MaxMin returns the latest and earliest time among the given times.
|
||||
// Play: todo
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
||||
maxTime = t1
|
||||
minTime = t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime, minTime
|
||||
}
|
||||
|
||||
@@ -437,3 +437,32 @@ func ExampleGenerateDatetimesBetween() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result := Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result := Max(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMaxMin() {
|
||||
max, min := MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
@@ -521,3 +521,60 @@ func TestGenerateDatetimesBetween(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(zeroTime, Min(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(zeroTime, Min(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAgo, Min(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(now, Max(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMaxMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMinMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
max, min := MaxMin(zeroTime, now, oneMinuteAgo, oneMinuteAfter)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
|
||||
max, min = MaxMin(now, zeroTime)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(now, max)
|
||||
|
||||
max, min = MaxMin(oneMinuteAgo, now, oneMinuteAfter)
|
||||
assert.Equal(oneMinuteAgo, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -257,9 +258,45 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>三元运算符。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>三元运算符</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`Ternary`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [ToUrlBase64](#ToUrlBase64)
|
||||
- [ToRawStdBase64](#ToRawStdBase64)
|
||||
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||
- [ToBigInt](#ToBigInt)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1148,4 +1149,34 @@ func main() {
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToBigInt">ToBigInt</span>
|
||||
|
||||
<p>将整数值转换为bigInt。</p>
|
||||
|
||||
<b>函数签名:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
func ToBigInt[T any](v T) (*big.Int, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 9876543210
|
||||
bigInt, _ := convertor.ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
```
|
||||
@@ -67,6 +67,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1570,4 +1573,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>返回最早时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>返回最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>返回最早和最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1076,4 +1077,34 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>返回exe,dll文件版本号(仅Window平台).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [T运行cRound](#T运行cRound)
|
||||
- [CeilToFloat](#CeilToFloat)
|
||||
- [CeilToString](#CeilToString)
|
||||
- [FloorToFloat](#FloorToFloat)
|
||||
@@ -52,6 +52,10 @@ import (
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
- [Div](#Div)
|
||||
- [Variance](#Variance)
|
||||
- [StdDev](#StdDev)
|
||||
- [Permutation](#Permutation)
|
||||
- [Combination](#Combination)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -64,7 +68,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
|
||||
@@ -87,7 +91,7 @@ func main() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
@@ -462,14 +466,14 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
### <span id="T运行cRound">T运行cRound</span>
|
||||
|
||||
<p>截短n位小数(不进行四舍五入)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TruncRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||
func T运行cRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
|
||||
@@ -483,9 +487,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(0.124, 2)
|
||||
result2 := mathutil.TruncRound(0.125, 2)
|
||||
result3 := mathutil.TruncRound(0.125, 3)
|
||||
result1 := mathutil.T运行cRound(0.124, 2)
|
||||
result2 := mathutil.T运行cRound(0.125, 2)
|
||||
result3 := mathutil.T运行cRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1045,8 +1049,8 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
result2 := mathutil.T运行cRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.T运行cRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1162,4 +1166,136 @@ func main() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Variance">Variance</span>
|
||||
|
||||
<p>计算方差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[示例](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := mathutil.Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StdDev">StdDev</span>
|
||||
|
||||
<p>计算标准差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.T运行cRound(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)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Permutation">Permutation</span>
|
||||
|
||||
<p>计算排列数P(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Permutation(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Permutation(5, 3)
|
||||
result2 := mathutil.Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Combination">Combination</span>
|
||||
|
||||
<p>计算组合数C(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Combination(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Combination(5, 3)
|
||||
result2 := mathutil.Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -522,4 +523,29 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>生成指定长度的随机数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -106,6 +106,9 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -2984,4 +2987,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>将切片元素用给定的分隔符连接成一个单一的字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# Stream
|
||||
|
||||
Stream 流,该包仅验证简单 stream 实现,功能有限。
|
||||
Stream流,该包仅验证简单stream实现,功能有限。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -48,6 +48,8 @@ import (
|
||||
- [NoneMatch](#NoneMatch)
|
||||
- [Count](#Count)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -938,3 +940,69 @@ func main() {
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,7 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#ExtractContent)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1728,4 +1729,34 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>提取两个标记之间的内容。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -167,12 +168,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -489,3 +490,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>简单实现的java风格异常处理(try-catch-finally)。try catch不符合go错误处理风格,谨慎使用。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error in try block")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -269,9 +270,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
> ⚠️ This function is deprecated. use `Ternary` instead.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
@@ -307,4 +344,3 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
- [ToUrlBase64](#ToUrlBase64)
|
||||
- [ToRawStdBase64](#ToRawStdBase64)
|
||||
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||
- [ToBigInt](#ToBigInt)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1116,4 +1117,34 @@ func main() {
|
||||
// map[a:1 b:2] false
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToBigInt">ToBigInt</span>
|
||||
|
||||
<p>Converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int</p>
|
||||
|
||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
func ToBigInt[T any](v T) (*big.Int, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 9876543210
|
||||
bigInt, _ := convertor.ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1571,4 +1574,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>Returns the earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>Returns the latest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>Returns the latest and earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1074,4 +1075,37 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>Get the version of exe or dll file on windows.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(v)
|
||||
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,10 @@ import (
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
- [Div](#Div)
|
||||
- [Variance](#Variance)
|
||||
- [StdDev](#StdDev)
|
||||
- [Permutation](#Permutation)
|
||||
- [Combination](#Combination)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -64,7 +68,7 @@ import (
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Vv7LBwER-pz)</span></b>
|
||||
@@ -87,7 +91,7 @@ func main() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
@@ -1161,4 +1165,136 @@ func main() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Variance">Variance</span>
|
||||
|
||||
<p>Returns the variance of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := mathutil.Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StdDev">StdDev</span>
|
||||
|
||||
<p>Returns the standard deviation of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := mathutil.TruncRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Permutation">Permutation</span>
|
||||
|
||||
<p>Calculates P(n, k).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Permutation(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Permutation(5, 3)
|
||||
result2 := mathutil.Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Combination">Combination</span>
|
||||
|
||||
<p>Calculates C(n, k).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Combination(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Combination(5, 3)
|
||||
result2 := mathutil.Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -523,4 +524,30 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>Generates a random int number of specified length.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -106,6 +106,10 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -2979,4 +2983,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>Joins the slice elements into a single string with the given separator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>Concats the elements of a slice into a single value using the provided separator and connector function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -939,3 +939,69 @@ func main() {
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>Returns the index of the first occurrence of the specified element in this stream, or -1 if this stream does not contain the element.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>Returns the index of the last occurrence of the specified element in this stream, or -1 if this stream does not contain the element.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,8 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#RegexMatchAllGroups)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1708,7 +1710,7 @@ func main() {
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1729,4 +1731,34 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>Extracts the content between the start and end strings in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -166,12 +167,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -487,3 +488,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>Simple simulation of Java-style try-catch. It does not align with Go's error-handling philosophy. It is recommended to use it with caution.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error message ")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.4. </b>
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.5. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Sponsor me
|
||||
|
||||
<b>Hello, I am a software developer and have been engaged in development work for 13 years. Love open source software. And be willing to put in the energy for it. I am the creator of project [lancet](https://github.com/duke-git/lancet). Since Lancet was released as open source two years ago, it has been used by more than 1,000 internal and external projects. lancet will always be free for all users. Your support is a powerful encouragement for me to continue my struggle. Thanks! You can use WeChat to scans the following QR code or clicks the following sponsor button to initiate sponsorship.</b>
|
||||
<b>Hello, I am a software developer and have been engaged in development work for 15 years. Love open source software. And be willing to put in the energy for it. I am the creator of project [lancet](https://github.com/duke-git/lancet). Since Lancet was released as open source in 2021, it has been used by more than 1700 internal and external projects. lancet will always be free for all users. Your support is a powerful encouragement for me to continue my struggle. Thanks! You can use WeChat to scans the following QR code or clicks the following sponsor button to initiate sponsorship.</b>
|
||||
|
||||
<style>
|
||||
.sponsor-ctn {
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.4。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.5。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
### 赞助
|
||||
|
||||
<b>您好,我是一名软件开发者,从事开发工作 13 年。热爱软件开源。并愿意为此付出精力。是开源项目[lancet](https://github.com/duke-git/lancet)的作者。Lancet 自两年前开源发布以来,已有超过 1000 个内外部项目使用。lancet 一直会对所有用户免费。您的支持是对我继续奋斗的有力鼓励。谢谢! 微信扫描以下二维码或点击以下赞助按钮发起赞助。 </b>
|
||||
<b>您好,我是一名软件开发者,从事开发工作15年。热爱软件开源。并愿意为此付出精力。是开源项目[lancet](https://github.com/duke-git/lancet)的作者。Lancet自2021年前开源发布以来,已有超过1700个内外部项目使用。lancet一直会对所有用户免费。您的支持是对我继续奋斗的有力鼓励。谢谢! 微信扫描以下二维码或点击以下赞助按钮发起赞助。 </b>
|
||||
|
||||
<style>
|
||||
.sponsor-ctn {
|
||||
|
||||
@@ -820,6 +820,7 @@ func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingF
|
||||
if len(headers) > 0 {
|
||||
columnHeaders = headers[0]
|
||||
} else {
|
||||
columnHeaders = make([]string, 0, len(records[0]))
|
||||
for key := range records[0] {
|
||||
columnHeaders = append(columnHeaders, key)
|
||||
}
|
||||
@@ -833,7 +834,7 @@ func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingF
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
var row []string
|
||||
row := make([]string, 0, len(columnHeaders))
|
||||
for _, h := range columnHeaders {
|
||||
row = append(row, fmt.Sprintf("%v", record[h]))
|
||||
}
|
||||
|
||||
@@ -192,6 +192,27 @@ func ExampleListFileNames() {
|
||||
// [assert.go assert_test.go error_join.go]
|
||||
}
|
||||
|
||||
func ExampleMiMeType() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
@@ -214,24 +235,20 @@ func ExampleZip() {
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
zipFile := "./testdata/file.go.zip"
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
err := UnZip(zipFile, "./testdata")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
exist := IsExist("./testdata/file.go")
|
||||
fmt.Println(exist)
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
os.Remove("./testdata/file.go")
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleZipAppendEntry() {
|
||||
|
||||
83
fileutil/file_windows.go
Normal file
83
fileutil/file_windows.go
Normal file
@@ -0,0 +1,83 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// tagVS_FIXEDFILEINFO 参考结构体https://learn.microsoft.com/zh-cn/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||
type tagVS_FIXEDFILEINFO struct {
|
||||
Signature uint32
|
||||
StructVersion uint32
|
||||
FileVersionMS uint32
|
||||
FileVersionLS uint32
|
||||
ProductVersionMS uint32
|
||||
ProductVersionLS uint32
|
||||
FileFlagsMask uint32
|
||||
FileFlags uint32
|
||||
FileOS uint32
|
||||
FileType uint32
|
||||
FileSubtype uint32
|
||||
FileDateMS uint32
|
||||
FileDateLS uint32
|
||||
}
|
||||
|
||||
// GetExeOrDllVersion get the version of exe or dll file on windows.
|
||||
// Play: todo
|
||||
func GetExeOrDllVersion(filePath string) (string, error) {
|
||||
// 加载系统dll
|
||||
versionDLL := syscall.NewLazyDLL("version.dll")
|
||||
getFileVersionInfoSize := versionDLL.NewProc("GetFileVersionInfoSizeW")
|
||||
getFileVersionInfo := versionDLL.NewProc("GetFileVersionInfoW")
|
||||
verQueryValue := versionDLL.NewProc("VerQueryValueW")
|
||||
|
||||
// 转换路径为UTF-16
|
||||
filePathPtr, err := syscall.UTF16PtrFromString(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
|
||||
// 获取version信息大小
|
||||
size, _, err := getFileVersionInfoSize.Call(
|
||||
uintptr(unsafe.Pointer(filePathPtr)),
|
||||
0,
|
||||
)
|
||||
if size == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information size: %v", err)
|
||||
}
|
||||
|
||||
// 加载version信息
|
||||
data := make([]byte, size)
|
||||
ret, _, err := getFileVersionInfo.Call(uintptr(unsafe.Pointer(filePathPtr)), 0, size, uintptr(unsafe.Pointer(&data[0])))
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information: %v", err)
|
||||
}
|
||||
|
||||
// 查询version信息
|
||||
var fixedInfo *tagVS_FIXEDFILEINFO
|
||||
var fixedInfoLen uint32
|
||||
u16, err := syscall.UTF16PtrFromString(`\`)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
ret, _, err = verQueryValue.Call(
|
||||
uintptr(unsafe.Pointer(&data[0])),
|
||||
uintptr(unsafe.Pointer(u16)),
|
||||
uintptr(unsafe.Pointer(&fixedInfo)),
|
||||
uintptr(unsafe.Pointer(&fixedInfoLen)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to query version information: %v", err)
|
||||
}
|
||||
|
||||
// 转换结构体
|
||||
major := fixedInfo.FileVersionMS >> 16
|
||||
minor := fixedInfo.FileVersionMS & 0xFFFF
|
||||
build := fixedInfo.FileVersionLS >> 16
|
||||
revision := fixedInfo.FileVersionLS & 0xFFFF
|
||||
|
||||
return fmt.Sprintf("%d.%d.%d.%d", major, minor, build, revision), nil
|
||||
}
|
||||
13
fileutil/file_windows_test.go
Normal file
13
fileutil/file_windows_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetExeOrDllVersion(t *testing.T) {
|
||||
v, err := GetExeOrDllVersion(`C:\Windows\System32\cmd.exe`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(v)
|
||||
}
|
||||
2
go.sum
2
go.sum
@@ -1,6 +1,4 @@
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
|
||||
@@ -44,14 +44,19 @@ func Fibonacci(first, second, n int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// Factorial calculate x!.
|
||||
// Factorial calculate n!.
|
||||
// Play: https://go.dev/play/p/tt6LdOK67Nx
|
||||
func Factorial(x uint) uint {
|
||||
var f uint = 1
|
||||
for ; x > 1; x-- {
|
||||
f *= x
|
||||
func Factorial(n uint) uint {
|
||||
if n == 0 || n == 1 {
|
||||
return 1
|
||||
}
|
||||
return f
|
||||
|
||||
result := uint(1)
|
||||
for i := uint(2); i <= n; i++ {
|
||||
result *= i
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Percent calculate the percentage of value to total.
|
||||
@@ -224,14 +229,12 @@ func Sum[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
|
||||
// Average return average value of numbers.
|
||||
// Play: https://go.dev/play/p/Vv7LBwER-pz
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
var sum T
|
||||
n := T(len(numbers))
|
||||
|
||||
for _, v := range numbers {
|
||||
sum += v
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64 {
|
||||
var sum float64
|
||||
for _, num := range numbers {
|
||||
sum += float64(num)
|
||||
}
|
||||
return sum / n
|
||||
return sum / float64(len(numbers))
|
||||
}
|
||||
|
||||
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||
@@ -395,3 +398,54 @@ func Abs[T constraints.Integer | constraints.Float](x T) T {
|
||||
func Div[T constraints.Float | constraints.Integer](x T, y T) float64 {
|
||||
return float64(x) / float64(y)
|
||||
}
|
||||
|
||||
// Variance returns the variance of numbers.
|
||||
// Play: todo
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||
n := len(numbers)
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
avg := Average(numbers...)
|
||||
var sum float64
|
||||
|
||||
for _, v := range numbers {
|
||||
sum += (float64(v) - avg) * (float64(v) - avg)
|
||||
}
|
||||
|
||||
return sum / float64(n)
|
||||
}
|
||||
|
||||
// StdDev returns the standard deviation of numbers.
|
||||
// Play: todo
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64 {
|
||||
return math.Sqrt(Variance(numbers))
|
||||
}
|
||||
|
||||
// Permutation calculate P(n, k).
|
||||
// Play: todo
|
||||
func Permutation(n, k uint) uint {
|
||||
if n < k {
|
||||
return 0
|
||||
}
|
||||
|
||||
nFactorial := Factorial(n)
|
||||
nMinusKFactorial := Factorial(n - k)
|
||||
|
||||
return nFactorial / nMinusKFactorial
|
||||
}
|
||||
|
||||
// Combination calculate C(n, k).
|
||||
// Play: todo
|
||||
func Combination(n, k uint) uint {
|
||||
if n < k {
|
||||
return 0
|
||||
}
|
||||
|
||||
nFactorial := Factorial(n)
|
||||
kFactorial := Factorial(k)
|
||||
nMinusKFactorial := Factorial(n - k)
|
||||
|
||||
return nFactorial / (kFactorial * nMinusKFactorial)
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func ExampleAverage() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
|
||||
@@ -478,3 +478,51 @@ func ExampleDiv() {
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleVariance() {
|
||||
result1 := Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
|
||||
func ExampleStdDev() {
|
||||
result1 := TruncRound(StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := TruncRound(StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
|
||||
func ExamplePermutation() {
|
||||
result1 := Permutation(5, 3)
|
||||
result2 := Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
|
||||
func ExampleCombination() {
|
||||
result1 := Combination(5, 3)
|
||||
result2 := Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
|
||||
@@ -143,11 +143,22 @@ func TestAverage(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestAverage")
|
||||
|
||||
assert.Equal(0, Average(0, 0))
|
||||
assert.Equal(1, Average(1, 1))
|
||||
tests := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 1},
|
||||
{[]int{1, 2, 3, 4}, 2.5},
|
||||
{[]int{1, 2, 3, 4, 5}, 3},
|
||||
}
|
||||
|
||||
avg := Average(1.2, 1.4)
|
||||
assert.Equal(1.3, RoundToFloat(avg, 1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Average(tt.numbers...))
|
||||
}
|
||||
|
||||
avg := Average(1.1, 1.2, 1.3, 1.4)
|
||||
assert.Equal(1.25, avg)
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
@@ -413,3 +424,116 @@ func TestDiv(t *testing.T) {
|
||||
assert.Equal(math.Inf(-1), Div(-8, 0))
|
||||
assert.Equal(true, math.IsNaN(Div(0, 0)))
|
||||
}
|
||||
|
||||
func TestVariance(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestVariance")
|
||||
|
||||
testIntNumbers := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 0},
|
||||
{[]int{1, 2, 3, 4}, 1.25},
|
||||
{[]int{1, 2, 3, 4, 5}, 2.0},
|
||||
}
|
||||
|
||||
for _, tt := range testIntNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(Variance(tt.numbers), 2))
|
||||
}
|
||||
|
||||
testFloatNumbers := []struct {
|
||||
numbers []float64
|
||||
expected float64
|
||||
}{
|
||||
{[]float64{0}, 0},
|
||||
{[]float64{1, 1, 1}, 0},
|
||||
{[]float64{1.1, 2.2, 3.3, 4.4}, 1.51},
|
||||
}
|
||||
|
||||
for _, tt := range testFloatNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(Variance(tt.numbers), 2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdDev(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestStdDev")
|
||||
|
||||
testIntNumbers := []struct {
|
||||
numbers []int
|
||||
expected float64
|
||||
}{
|
||||
{[]int{0}, 0},
|
||||
{[]int{1, 1, 1}, 0},
|
||||
{[]int{1, 2, 3, 4}, 1.118},
|
||||
{[]int{1, 2, 3, 4, 5}, 1.414},
|
||||
}
|
||||
|
||||
for _, tt := range testIntNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(StdDev(tt.numbers), 3))
|
||||
}
|
||||
|
||||
testFloatNumbers := []struct {
|
||||
numbers []float64
|
||||
expected float64
|
||||
}{
|
||||
{[]float64{0}, 0},
|
||||
{[]float64{1, 1, 1}, 0},
|
||||
{[]float64{1.1, 2.2, 3.3, 4.4}, 1.229},
|
||||
}
|
||||
|
||||
for _, tt := range testFloatNumbers {
|
||||
assert.Equal(tt.expected, TruncRound(StdDev(tt.numbers), 3))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermutation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestPermutation")
|
||||
|
||||
tests := []struct {
|
||||
n uint
|
||||
k uint
|
||||
expected uint
|
||||
}{
|
||||
{1, 1, 1},
|
||||
{1, 0, 1},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
{3, 2, 6},
|
||||
{4, 2, 12},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Permutation(tt.n, tt.k))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCombination(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestCombination")
|
||||
|
||||
tests := []struct {
|
||||
n uint
|
||||
k uint
|
||||
expected uint
|
||||
}{
|
||||
{1, 1, 1},
|
||||
{1, 0, 1},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
{3, 2, 3},
|
||||
{4, 2, 6},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.expected, Combination(tt.n, tt.k))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func ConvertMapToQueryString(param map[string]any) string {
|
||||
if param == nil {
|
||||
return ""
|
||||
}
|
||||
var keys []string
|
||||
keys := make([]string, 0, len(param))
|
||||
for key := range param {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
@@ -221,6 +221,22 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AsyncSendRequest send http request with goroutine, pop response and error to channels
|
||||
func (client *HttpClient) AsyncSendRequest(request *HttpRequest, respChan chan *http.Response, errChan chan error) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
errChan <- fmt.Errorf("%v", err)
|
||||
}
|
||||
}()
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
respChan <- resp
|
||||
}()
|
||||
}
|
||||
|
||||
// DecodeResponse decode response into target object.
|
||||
// Play: https://go.dev/play/p/jUSgynekH7G
|
||||
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
|
||||
|
||||
@@ -373,6 +373,45 @@ func TestSendRequestWithFilePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpClient_AsyncSendRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHttpClient_Get")
|
||||
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
respCh := make(chan *http.Response, 20)
|
||||
errCh := make(chan error, 20)
|
||||
for i := 0; i < 50; i++ {
|
||||
httpClient.AsyncSendRequest(request, respCh, errCh)
|
||||
}
|
||||
for i := 0; i < 50; i++ {
|
||||
select {
|
||||
case resp := <-respCh:
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Id int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
var todo Todo
|
||||
err := httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
assert.Equal(1, todo.Id)
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Log("net error: ", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy(t *testing.T) {
|
||||
config := &HttpClientConfig{
|
||||
HandshakeTimeout: 20 * time.Second,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MaximumCapacity = math.MaxInt>>1 + 1
|
||||
MaximumCapacity = math.MaxInt32>>1 + 1
|
||||
Numeral = "0123456789"
|
||||
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@@ -273,6 +274,11 @@ func nearestPowerOfTwo(cap int) int {
|
||||
|
||||
// random generate a random string based on given string range.
|
||||
func random(s string, length int) string {
|
||||
// 确保随机数生成器的种子是动态的
|
||||
pid := os.Getpid()
|
||||
timestamp := time.Now().UnixNano()
|
||||
rand.Seed(int64(pid) + timestamp)
|
||||
|
||||
// 仿照strings.Builder
|
||||
// 创建一个长度为 length 的字节切片
|
||||
bytes := make([]byte, length)
|
||||
@@ -327,3 +333,13 @@ func UUIdV4() (string, error) {
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
||||
|
||||
// RandNumberOfLength 生成一个长度为len的随机数
|
||||
// Play: todo
|
||||
func RandNumberOfLength(len int) int {
|
||||
m := int(math.Pow10(len) - 1)
|
||||
i := int(math.Pow10(len - 1))
|
||||
ret := rand.Intn(m-i+1) + i
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package random
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -361,3 +362,9 @@ func TestRandBoolSlice(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
func TestRandNumberOfLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
randi := RandNumberOfLength(6)
|
||||
assert := internal.NewAssert(t, "TestRandNumberOfLength")
|
||||
assert.Equal(6, len(strconv.Itoa(randi)))
|
||||
}
|
||||
|
||||
105
slice/slice.go
105
slice/slice.go
@@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
var (
|
||||
memoryHashMap = make(map[string]map[any]int)
|
||||
memoryHashCounter = make(map[string]int)
|
||||
muForMemoryHash sync.RWMutex
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not.
|
||||
@@ -919,36 +921,25 @@ func Merge[T any](slices ...[]T) []T {
|
||||
// Intersection creates a slice of unique elements that included by all slices.
|
||||
// Play: https://go.dev/play/p/anJXfB5wq_t
|
||||
func Intersection[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
}
|
||||
if len(slices) == 1 {
|
||||
return Unique(slices[0])
|
||||
}
|
||||
result := []T{}
|
||||
elementCount := make(map[T]int)
|
||||
|
||||
reducer := func(sliceA, sliceB []T) []T {
|
||||
hashMap := make(map[T]int)
|
||||
for _, v := range sliceA {
|
||||
hashMap[v] = 1
|
||||
}
|
||||
for _, slice := range slices {
|
||||
seen := make(map[T]bool)
|
||||
|
||||
out := make([]T, 0)
|
||||
for _, val := range sliceB {
|
||||
if v, ok := hashMap[val]; v == 1 && ok {
|
||||
out = append(out, val)
|
||||
hashMap[val]++
|
||||
for _, item := range slice {
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
elementCount[item]++
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
result := reducer(slices[0], slices[1])
|
||||
|
||||
reduceSlice := make([][]T, 2)
|
||||
for i := 2; i < len(slices); i++ {
|
||||
reduceSlice[0] = result
|
||||
reduceSlice[1] = slices[i]
|
||||
result = reducer(reduceSlice[0], reduceSlice[1])
|
||||
for _, item := range slices[0] {
|
||||
if elementCount[item] == len(slices) {
|
||||
result = append(result, item)
|
||||
elementCount[item] = 0
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -1174,23 +1165,46 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
limit := 10
|
||||
// gets the hash value of the array as the key of the hash table.
|
||||
key := fmt.Sprintf("%p", arr)
|
||||
|
||||
muForMemoryHash.RLock()
|
||||
// determines whether the hash table is empty. If so, the hash table is created.
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
|
||||
muForMemoryHash.RUnlock()
|
||||
muForMemoryHash.Lock()
|
||||
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
}
|
||||
}
|
||||
|
||||
muForMemoryHash.Unlock()
|
||||
} else {
|
||||
muForMemoryHash.RUnlock()
|
||||
}
|
||||
|
||||
muForMemoryHash.Lock()
|
||||
// update the hash table counter.
|
||||
memoryHashCounter[key]++
|
||||
muForMemoryHash.Unlock()
|
||||
|
||||
// use the hash table to find the specified value. If found, the index is returned.
|
||||
if index, ok := memoryHashMap[key][val]; ok {
|
||||
muForMemoryHash.RLock()
|
||||
index, ok := memoryHashMap[key][val]
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
if ok {
|
||||
muForMemoryHash.RLock()
|
||||
// calculate the memory usage of the hash table.
|
||||
size := len(memoryHashMap)
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
|
||||
if size > limit {
|
||||
muForMemoryHash.Lock()
|
||||
var minKey string
|
||||
var minVal int
|
||||
for k, v := range memoryHashCounter {
|
||||
@@ -1204,6 +1218,7 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
}
|
||||
delete(memoryHashMap, minKey)
|
||||
delete(memoryHashCounter, minKey)
|
||||
muForMemoryHash.Unlock()
|
||||
}
|
||||
return index
|
||||
}
|
||||
@@ -1398,3 +1413,35 @@ func Frequency[T comparable](slice []T) map[T]int {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// JoinFunc joins the slice elements into a single string with the given separator.
|
||||
// Play: todo
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
||||
var buf strings.Builder
|
||||
for i, v := range slice {
|
||||
if i > 0 {
|
||||
buf.WriteString(sep)
|
||||
}
|
||||
buf.WriteString(fmt.Sprint(transform(v)))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ConcatBy concats the elements of a slice into a single value using the provided separator and connector function.
|
||||
// Play: todo
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T {
|
||||
var result T
|
||||
|
||||
if len(slice) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
for i, v := range slice {
|
||||
result = connector(result, v)
|
||||
if i < len(slice)-1 {
|
||||
result = connector(result, sep)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool,
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqueByParallel removes duplicate elements from the slice by parallel
|
||||
// UniqueByConcurrent removes duplicate elements from the slice by parallel
|
||||
// The comparator function is used to compare the elements
|
||||
// The numThreads parameter specifies the number of threads to use
|
||||
// If numThreads is less than or equal to 0, it will be set to 1
|
||||
@@ -195,18 +195,14 @@ func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T
|
||||
chunks = append(chunks, slice[i:end])
|
||||
}
|
||||
|
||||
type resultChunk struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
resultCh := make(chan resultChunk, numThreads)
|
||||
resultCh := make(chan resultChunk[T], numThreads)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i, chunk := range chunks {
|
||||
wg.Add(1)
|
||||
go func(index int, chunk []T) {
|
||||
defer wg.Done()
|
||||
resultCh <- resultChunk{index, removeDuplicate(chunk, comparator)}
|
||||
resultCh <- resultChunk[T]{index, removeDuplicate(chunk, comparator)}
|
||||
}(i, chunk)
|
||||
}
|
||||
|
||||
|
||||
@@ -1261,3 +1261,42 @@ func ExampleFrequency() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
|
||||
func ExampleJoinFunc() {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
|
||||
func ExampleConcatBy() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ import (
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// resultChunk is used to store the intermediate results of UniqueByConcurrent.
|
||||
// It is defined separately to be compatible with versions of go up to 1.20.
|
||||
type resultChunk[T comparable] struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
|
||||
// sliceValue return the reflect value of a slice
|
||||
func sliceValue(slice any) reflect.Value {
|
||||
v := reflect.ValueOf(slice)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -1367,6 +1368,37 @@ func TestIndexOf(t *testing.T) {
|
||||
assert.Equal(-1, IndexOf(arr3, "r"))
|
||||
assert.Equal(2, memoryHashCounter[key3])
|
||||
assert.Equal(0, memoryHashCounter[minKey])
|
||||
|
||||
arr4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
const numGoroutines = 100
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
index := IndexOf(arr4, i%10+1)
|
||||
assert.Equal(i%10, index)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkIndexOfDifferentSizes(b *testing.B) {
|
||||
sizes := []int{10, 100, 1000, 10000, 100000}
|
||||
for _, size := range sizes {
|
||||
arr := make([]int, size)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arr[i] = i
|
||||
}
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_ = IndexOf(arr, size/2) // 查找数组中间的元素
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastIndexOf(t *testing.T) {
|
||||
@@ -1816,3 +1848,81 @@ func TestFrequency(t *testing.T) {
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestJoinFunc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestJoinFunc")
|
||||
|
||||
t.Run("basic case", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1, 2, 3}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
expected := "2, 4, 6"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("empty slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("", result)
|
||||
})
|
||||
|
||||
t.Run("single element slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("2", result)
|
||||
})
|
||||
|
||||
t.Run("string slice", func(t *testing.T) {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
expected := "A, B, C"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConcatBy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestConcatBy")
|
||||
|
||||
t.Run("Join strings", func(t *testing.T) {
|
||||
result := ConcatBy([]string{"Hello", "World"}, ", ", func(a, b string) string {
|
||||
return a + b
|
||||
})
|
||||
|
||||
expected := "Hello, World"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("Join Person struct", func(t *testing.T) {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
assert.Equal("Alice | Bob | Charlie", result.Name)
|
||||
assert.Equal(90, result.Age)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -202,6 +202,7 @@ func (s Stream[T]) Skip(n int) Stream[T] {
|
||||
return FromSlice(source)
|
||||
}
|
||||
|
||||
source = make([]T, 0, l-n)
|
||||
for i := n; i < l; i++ {
|
||||
source = append(source, s.source[i])
|
||||
}
|
||||
@@ -393,6 +394,26 @@ func (s Stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
||||
return min, true
|
||||
}
|
||||
|
||||
// IndexOf returns the index of the first occurrence of the specified element in this stream, or -1 if this stream does not contain the element.
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int {
|
||||
for i, v := range s.source {
|
||||
if equal(v, target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index of the last occurrence of the specified element in this stream, or -1 if this stream does not contain the element.
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int {
|
||||
for i := len(s.source) - 1; i >= 0; i-- {
|
||||
if equal(s.source[i], target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ToSlice return the elements in the stream.
|
||||
// Play: https://go.dev/play/p/jI6_iZZuVFE
|
||||
func (s Stream[T]) ToSlice() []T {
|
||||
|
||||
@@ -384,3 +384,31 @@ func ExampleStream_Count() {
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStream_IndexOf() {
|
||||
s := FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleStream_LastIndexOf() {
|
||||
s := FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
|
||||
@@ -381,3 +381,22 @@ func TestStream_Min(t *testing.T) {
|
||||
assert.Equal(1, max)
|
||||
assert.Equal(true, ok)
|
||||
}
|
||||
|
||||
func TestStream_IndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_IndexOf")
|
||||
|
||||
s := FromSlice([]int{4, 2, 1, 3, 4})
|
||||
|
||||
assert.Equal(-1, s.IndexOf(0, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(0, s.IndexOf(4, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(3, s.IndexOf(3, func(a, b int) bool { return a == b }))
|
||||
}
|
||||
|
||||
func TestStream_LastIndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_LastIndexOf")
|
||||
|
||||
s := FromSlice([]int{4, 2, 1, 3, 2})
|
||||
|
||||
assert.Equal(-1, s.LastIndexOf(0, func(a, b int) bool { return a == b }))
|
||||
assert.Equal(4, s.LastIndexOf(2, func(a, b int) bool { return a == b }))
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ func (s *Struct) ToMap() (map[string]any, error) {
|
||||
|
||||
// Fields returns all the struct fields within a slice
|
||||
func (s *Struct) Fields() []*Field {
|
||||
var fields []*Field
|
||||
fieldNum := s.rvalue.NumField()
|
||||
fields := make([]*Field, 0, fieldNum)
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
v := s.rvalue.Field(i)
|
||||
sf := s.rtype.Field(i)
|
||||
|
||||
@@ -735,3 +735,24 @@ func RegexMatchAllGroups(pattern, str string) [][]string {
|
||||
matches := re.FindAllStringSubmatch(str, -1)
|
||||
return matches
|
||||
}
|
||||
|
||||
// ExtractContent extracts the content between the start and end strings in the source string.
|
||||
// Play: todo
|
||||
func ExtractContent(s, start, end string) []string {
|
||||
result := []string{}
|
||||
|
||||
for {
|
||||
if _, after, ok := strings.Cut(s, start); ok {
|
||||
if before, _, ok := strings.Cut(after, end); ok {
|
||||
result = append(result, before)
|
||||
s = after
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -753,3 +753,15 @@ func ExampleRegexMatchAllGroups() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
|
||||
func ExampleExtractContent() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
|
||||
}
|
||||
|
||||
@@ -853,3 +853,87 @@ func TestRegexMatchAllGroups(t *testing.T) {
|
||||
assert.Equal(tt.expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestExtractContent")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
start string
|
||||
end string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "Extract content between <tag> and </tag>",
|
||||
input: "This is <tag>content1</tag> and <tag>content2</tag> and <tag>content3</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content1", "content2", "content3"},
|
||||
},
|
||||
{
|
||||
name: "No tags in the string",
|
||||
input: "This string has no tags",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Single tag pair",
|
||||
input: "<tag>onlyContent</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"onlyContent"},
|
||||
},
|
||||
{
|
||||
name: "Tags without end tag",
|
||||
input: "This <tag>content without end tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Tags with nested content",
|
||||
input: "<tag>content <nested>inner</nested> end</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content <nested>inner</nested> end"},
|
||||
},
|
||||
{
|
||||
name: "Edge case with empty string",
|
||||
input: "",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Edge case with no start tag",
|
||||
input: "content without start tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Edge case with no end tag",
|
||||
input: "<tag>content without end tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Multiple consecutive tags",
|
||||
input: "<tag>content1</tag><tag>content2</tag><tag>content3</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content1", "content2", "content3"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := ExtractContent(tt.input, tt.start, tt.end)
|
||||
assert.Equal(tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
100
xerror/trycatch.go
Normal file
100
xerror/trycatch.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// TryCatch is a struct to handle try-catch-finally block.
|
||||
// This implementation is merely a simulation of Java-style try-catch and does not align with Go's error-handling philosophy. It is recommended to use it with caution.
|
||||
type TryCatch struct {
|
||||
ctx context.Context
|
||||
tryFunc func(ctx context.Context) error
|
||||
catchFunc func(ctx context.Context, err error)
|
||||
finallyFunc func(ctx context.Context)
|
||||
}
|
||||
|
||||
// NewTryCatch creates a new TryCatch instance.
|
||||
func NewTryCatch(ctx context.Context) *TryCatch {
|
||||
return &TryCatch{
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// Try sets the try function.
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch {
|
||||
tc.tryFunc = tryFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Catch sets the catch function.
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch {
|
||||
tc.catchFunc = catchFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Finally sets the finally function.
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch {
|
||||
tc.finallyFunc = finallyFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Do executes the try-catch-finally block.
|
||||
func (tc *TryCatch) Do() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if tc.catchFunc != nil {
|
||||
err := fmt.Errorf("panic: %v", r)
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(err, "Recovered from panic"))
|
||||
}
|
||||
}
|
||||
|
||||
if tc.finallyFunc != nil {
|
||||
tc.finallyFunc(tc.ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
if tc.ctx.Err() != nil {
|
||||
if tc.catchFunc != nil {
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(tc.ctx.Err(), "Context cancelled or timed out"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if tc.tryFunc != nil {
|
||||
if err := tc.tryFunc(tc.ctx); err != nil {
|
||||
if tc.catchFunc != nil {
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(err, "Error in try block"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CatchError is an error type to handle try-catch-finally block.
|
||||
type CatchError struct {
|
||||
Msg string
|
||||
File string
|
||||
Line int
|
||||
Cause error
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (e *CatchError) Error() string {
|
||||
return fmt.Sprintf("%s at %s:%d - Cause: %v", e.Msg, e.File, e.Line, e.Cause)
|
||||
}
|
||||
|
||||
// WrapCatchError wraps an error with message, file, and line.
|
||||
func WrapCatchError(err error, msg string) *CatchError {
|
||||
_, file, line, ok := runtime.Caller(2)
|
||||
if !ok {
|
||||
file = "unknown"
|
||||
line = 0
|
||||
}
|
||||
return &CatchError{
|
||||
Msg: msg,
|
||||
File: file,
|
||||
Line: line,
|
||||
Cause: err,
|
||||
}
|
||||
}
|
||||
172
xerror/trycatch_test.go
Normal file
172
xerror/trycatch_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestTryCatchSuccess(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchSuccess")
|
||||
|
||||
counter := 0
|
||||
calledCatch := false
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
counter++
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
t.Errorf("Catch should not be called")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal(1, counter)
|
||||
assert.Equal(false, calledCatch)
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchError")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchPanic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchPanic")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
panic("panic info")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextCancelled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextCancelled")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextTimeout")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 0)
|
||||
defer cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextError")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 0)
|
||||
defer cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchNoCatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchNoCatch")
|
||||
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func Wrap(cause error, message ...any) *XError {
|
||||
err := newXError()
|
||||
|
||||
if len(message) > 0 {
|
||||
var newMsgs []string
|
||||
newMsgs := make([]string, 0, len(message))
|
||||
for _, m := range message {
|
||||
newMsgs = append(newMsgs, fmt.Sprintf("%v", m))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -61,7 +62,7 @@ func ExampleXError_StackTrace() {
|
||||
|
||||
// Output:
|
||||
// github.com/duke-git/lancet/v2/xerror.ExampleXError_StackTrace
|
||||
// 52
|
||||
// 53
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -154,3 +155,27 @@ func ExampleTryUnwrap() {
|
||||
// 42
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleTryCatch() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error message")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:174 - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user