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

Compare commits

..

23 Commits

Author SHA1 Message Date
dudaodong
9f0ad2354a feat: update some test fucntions 2025-08-21 10:52:44 +08:00
dudaodong
55b66dee99 Merge branch 'rc' into v2 2025-08-21 10:08:21 +08:00
Idichekop
4c64a16204 fix(package): [slice] functions with inconsistent return behaviour (#326)
* Some functions modified

* Fixes in all the functions of slice.go

* Re-use of swap function internal.
2025-08-19 10:50:25 +08:00
dudaodong
385e64cc52 feat: add IsPassport 2025-08-13 14:01:24 +08:00
dudaodong
be45a259db Merge branch 'v2' into rc 2025-08-13 11:24:27 +08:00
Idichekop
6f703fe577 fix(package): [slice] Fix RigthPadding and LeftPadding (#322)
* Fixes in  RightPadding and LeftPadding

* Tests cover padding empty, nil, and negative lenght

* Implemented repeat, concat, and grow functionalities as internal.
2025-08-04 10:45:29 +08:00
Idichekop
cb8d93c499 Simple refactor of ForEach functions (#323) 2025-07-30 14:28:27 +08:00
idichekop
ae1014c572 fix(package):[function] Corrected behaviour of Nand predicate (#319) 2025-07-22 10:08:50 +08:00
dudaodong
d5b9e67330 fix: fix go lint issue 2025-07-07 11:18:34 +08:00
dudaodong
a81403766f feat: add ToPointers, FromPointer, FromPointers 2025-07-07 11:16:44 +08:00
dudaodong
6307d624cb Merge branch 'rc' of github.com:duke-git/lancet into rc 2025-07-07 10:18:37 +08:00
dudaodong
2f9f8b3f3d release v2.3.7 2025-07-07 10:18:05 +08:00
jake
db5d9407bb Update slice_concurrent.go (#316) 2025-06-25 15:33:07 +08:00
dudaodong
55ee000684 merge rc 2025-06-23 11:32:51 +08:00
dudaodong
fc7f2509ca fix: fix issue #314 2025-06-23 11:31:54 +08:00
残念
a97d27c32e perf(retry): the error returned by the Retry function contains the last error (#315) 2025-06-23 11:04:54 +08:00
Grigoris Thanasoulas
c176ba378e arrayqueue: Fix bug in Back() method (#313) 2025-06-20 23:05:14 +08:00
dudaodong
a3a24fc381 doc: update doc styles 2025-06-06 14:33:54 +08:00
Axiss
9caf2ffb1c fix one typo in doc (#310) 2025-06-03 10:10:51 +08:00
残念
1a5c31fd02 perf(retry): remove the waiting time after the last retry (#309) 2025-06-03 09:57:29 +08:00
dudaodong
c175b202de doc: update cryptordoc 2025-05-29 14:04:09 +08:00
dudaodong
d818219672 doc: update cryptordoc 2025-05-29 14:01:12 +08:00
dudaodong
539078e6b8 doc: add play ground demo for v2.3.6 2025-05-29 11:50:17 +08:00
45 changed files with 970 additions and 282 deletions

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.3.6-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.3.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -216,28 +216,28 @@ import "github.com/duke-git/lancet/v2/concurrency"
[[play](https://go.dev/play/p/3TQPKnCirrP)] [[play](https://go.dev/play/p/3TQPKnCirrP)]
- **<big>NewKeyedLocker</big>** : KeyedLocker is a simple implementation of a keyed locker that allows for non-blocking lock acquisition. - **<big>NewKeyedLocker</big>** : KeyedLocker is a simple implementation of a keyed locker that allows for non-blocking lock acquisition.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/GzeyC33T5rw)]
- **<big>Do</big>** :acquires a lock for the specified key and executes the provided function. - **<big>Do</big>** :acquires a lock for the specified key and executes the provided function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Do)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Do)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/GzeyC33T5rw)]
- **<big>NewRWKeyedLocker</big>** :RRWKeyedLocker is a read-write version of KeyedLocker. - **<big>NewRWKeyedLocker</big>** :RRWKeyedLocker is a read-write version of KeyedLocker.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewRWKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewRWKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/ZrCr8sMo77T)]
- **<big>RLock</big>** : acquires a read lock for the specified key and executes the provided function. - **<big>RLock</big>** : acquires a read lock for the specified key and executes the provided function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#RLock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#RLock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/ZrCr8sMo77T)]
- **<big>Lock</big>** : acquires a write lock for the specified key and executes the provided function. - **<big>Lock</big>** : acquires a write lock for the specified key and executes the provided function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Lock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Lock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/WgAcXbOPKGk)]
- **<big>NewTryKeyedLocker</big>** : TryKeyedLocker is a non-blocking version of KeyedLocker. - **<big>NewTryKeyedLocker</big>** : TryKeyedLocker is a non-blocking version of KeyedLocker.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewTryKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewTryKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
- **<big>TryLock</big>** : TryLock tries to acquire a lock for the specified key. - **<big>TryLock</big>** : TryLock tries to acquire a lock for the specified key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#TryLock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#TryLock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
- **<big>Unlock</big>** : Unlock releases the lock for the specified key. - **<big>Unlock</big>** : Unlock releases the lock for the specified key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Unlock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Unlock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
<h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3> <h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
@@ -803,7 +803,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/P2y0XW8a1SH)] [[play](https://go.dev/play/p/P2y0XW8a1SH)]
- **<big>RemoveDir</big>** : delete directory. - **<big>RemoveDir</big>** : delete directory.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#RemoveDir)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#RemoveDir)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/Oa6KnPek2uy)]
- **<big>ReadFileToString</big>** : return string of file content. - **<big>ReadFileToString</big>** : return string of file content.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ReadFileToString)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ReadFileToString)]
[[play](https://go.dev/play/p/cmfwp_5SQTp)] [[play](https://go.dev/play/p/cmfwp_5SQTp)]
@@ -1124,7 +1124,7 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/99QjSYSBdiM)] [[play](https://go.dev/play/p/99QjSYSBdiM)]
- **<big>FindValuesBy</big>** : returns a slice of values from the map that satisfy the given predicate function. - **<big>FindValuesBy</big>** : returns a slice of values from the map that satisfy the given predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#FindValuesBy)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#FindValuesBy)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/bvNwNBZDm6v)]
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3> <h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -1311,10 +1311,10 @@ import "github.com/duke-git/lancet/v2/netutil"
[[play](https://go.dev/play/p/yiLCGtQv_ZG)] [[play](https://go.dev/play/p/yiLCGtQv_ZG)]
- **<big>BuildUrl</big>** : builds a URL from the given params. - **<big>BuildUrl</big>** : builds a URL from the given params.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#BuildUrl)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#BuildUrl)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/JLXl1hZK7l4)]
- **<big>AddQueryParams</big>** : adds query parameters to the given URL. - **<big>AddQueryParams</big>** : adds query parameters to the given URL.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#AddQueryParams)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#AddQueryParams)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/JLXl1hZK7l4)]
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3> <h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -2228,7 +2228,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/LzaKocSV79u)] [[play](https://go.dev/play/p/LzaKocSV79u)]
- **<big>IsAlphaNumeric</big>** : check if the string is alphanumeric. - **<big>IsAlphaNumeric</big>** : check if the string is alphanumeric.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsAlphaNumeric)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsAlphaNumeric)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/RHeESLrLg9c)]
- **<big>IsJSON</big>** : check if the string is valid JSON. - **<big>IsJSON</big>** : check if the string is valid JSON.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsJSON)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsJSON)]
[[play](https://go.dev/play/p/8Kip1Itjiil)] [[play](https://go.dev/play/p/8Kip1Itjiil)]

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.3.6-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.3.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -215,28 +215,28 @@ import "github.com/duke-git/lancet/v2/concurrency"
[[play](https://go.dev/play/p/3TQPKnCirrP)] [[play](https://go.dev/play/p/3TQPKnCirrP)]
- **<big>NewKeyedLocker</big>** : NewKeyedLocker 创建一个新的 KeyedLocker并为锁的过期设置指定的 TTL。 - **<big>NewKeyedLocker</big>** : NewKeyedLocker 创建一个新的 KeyedLocker并为锁的过期设置指定的 TTL。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/GzeyC33T5rw)]
- **<big>Do</big>** :为指定的键获取锁并执行提供的函数。 - **<big>Do</big>** :为指定的键获取锁并执行提供的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Do)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Do)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/GzeyC33T5rw)]
- **<big>NewRWKeyedLocker</big>** :RWKeyedLocker 是一个简单的键值读写锁实现,允许非阻塞的锁获取。 - **<big>NewRWKeyedLocker</big>** :RWKeyedLocker 是一个简单的键值读写锁实现,允许非阻塞的锁获取。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewRWKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewRWKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/ZrCr8sMo77T)]
- **<big>RLock</big>** : 为指定的键获取读锁并执行提供的函数。 - **<big>RLock</big>** : 为指定的键获取读锁并执行提供的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#RLock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#RLock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/ZrCr8sMo77T)]
- **<big>Lock</big>** : 为指定的键获取锁并执行提供的函数。 - **<big>Lock</big>** : 为指定的键获取锁并执行提供的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Lock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Lock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/WgAcXbOPKGk)]
- **<big>NewTryKeyedLocker</big>** : 创建一个 TryKeyedLocker 实例TryKeyedLocker 是 KeyedLocker 的非阻塞版本。 - **<big>NewTryKeyedLocker</big>** : 创建一个 TryKeyedLocker 实例TryKeyedLocker 是 KeyedLocker 的非阻塞版本。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewTryKeyedLocker)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewTryKeyedLocker)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
- **<big>TryLock</big>** : TryLock 尝试获取指定键的锁。如果锁成功获取,则返回 true否则返回 false。 - **<big>TryLock</big>** : TryLock 尝试获取指定键的锁。如果锁成功获取,则返回 true否则返回 false。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#TryLock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#TryLock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
- **<big>Unlock</big>** : 释放指定键的锁。 - **<big>Unlock</big>** : 释放指定键的锁。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Unlock)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Unlock)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/VG9qLvyetE2)]
<h3 id="condition"> 4. condition 包含一些用于条件判断的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3> <h3 id="condition"> 4. condition 包含一些用于条件判断的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -378,9 +378,15 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>AesCbcDecrypt</big>** : 使用 AES CBC 算法模式解密数据。 - **<big>AesCbcDecrypt</big>** : 使用 AES CBC 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCbcDecrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCbcDecrypt)]
[[play](https://go.dev/play/p/IOq_g8_lKZD)] [[play](https://go.dev/play/p/IOq_g8_lKZD)]
- **<big>AesCtrCrypt</big>** : 使用 AES CTR 算法模式加密/解密数据。 - **<big>AesCtrCrypt<sup>deprecated</sup></big>** : 使用 AES CTR 算法模式加密/解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCtrCrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCtrCrypt)]
[[play](https://go.dev/play/p/SpaZO0-5Nsp)] [[play](https://go.dev/play/p/SpaZO0-5Nsp)]
- **<big>AesCtrEncrypt</big>** : 使用 AES CTR 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCtrCrypt)]
[[play](https://go.dev/play/p/x6pjPAvThRz)]
- **<big>AesCtrDecrypt</big>** : 使用 AES CTR 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCtrCrypt)]
[[play](https://go.dev/play/p/x6pjPAvThRz)]
- **<big>AesCfbEncrypt</big>** : 使用 AES CFB 算法模式加密数据。 - **<big>AesCfbEncrypt</big>** : 使用 AES CFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCfbEncrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesCfbEncrypt)]
[[play](https://go.dev/play/p/tfkF10B13kH)] [[play](https://go.dev/play/p/tfkF10B13kH)]
@@ -417,9 +423,15 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>DesCbcDecrypt</big>** : 使用 DES CBC 算法模式解密数据。 - **<big>DesCbcDecrypt</big>** : 使用 DES CBC 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCbcDecrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCbcDecrypt)]
[[play](https://go.dev/play/p/4cC4QvWfe3_1)] [[play](https://go.dev/play/p/4cC4QvWfe3_1)]
- **<big>DesCtrCrypt</big>** : 使用 DES CTR 算法模式加密/解密数据。 - **<big>DesCtrCrypt<sup>deprecated</sup></big>** : 使用 DES CTR 算法模式加密/解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCtrCrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCtrCrypt)]
[[play](https://go.dev/play/p/9-T6OjKpcdw)] [[play](https://go.dev/play/p/9-T6OjKpcdw)]
- **<big>DesCtrEncrypt</big>** : 使用 DES CTR 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCtrEncrypt)]
[[play](https://go.dev/play/p/S6p_WHCgH1d)]
- **<big>DesCtrDecrypt</big>** : 使用 DES CTR 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCtrDecrypt)]
[[play](https://go.dev/play/p/S6p_WHCgH1d)]
- **<big>DesCfbEncrypt</big>** : 使用 DES CFB 算法模式加密数据。 - **<big>DesCfbEncrypt</big>** : 使用 DES CFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCfbEncrypt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#DesCfbEncrypt)]
[[play](https://go.dev/play/p/y-eNxcFBlxL)] [[play](https://go.dev/play/p/y-eNxcFBlxL)]
@@ -801,7 +813,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/P2y0XW8a1SH)] [[play](https://go.dev/play/p/P2y0XW8a1SH)]
- **<big>RemoveDir</big>** : 删除目录,支持传入删除前的回调函数。 - **<big>RemoveDir</big>** : 删除目录,支持传入删除前的回调函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#RemoveDir)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#RemoveDir)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/Oa6KnPek2uy)]
- **<big>ReadFileToString</big>** : 读取文件内容并返回字符串。 - **<big>ReadFileToString</big>** : 读取文件内容并返回字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadFileToString)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadFileToString)]
[[play](https://go.dev/play/p/cmfwp_5SQTp)] [[play](https://go.dev/play/p/cmfwp_5SQTp)]
@@ -1122,7 +1134,7 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/99QjSYSBdiM)] [[play](https://go.dev/play/p/99QjSYSBdiM)]
- **<big>FindValuesBy</big>** : 返回一个切片,包含满足给定谓词判断函数的 map 中的值。 - **<big>FindValuesBy</big>** : 返回一个切片,包含满足给定谓词判断函数的 map 中的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#FindValuesBy)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#FindValuesBy)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/bvNwNBZDm6v)]
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3> <h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -1309,10 +1321,10 @@ import "github.com/duke-git/lancet/v2/netutil"
[[play](https://go.dev/play/p/yiLCGtQv_ZG)] [[play](https://go.dev/play/p/yiLCGtQv_ZG)]
- **<big>BuildUrl</big>** : 创建 url 字符串。 - **<big>BuildUrl</big>** : 创建 url 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#BuildUrl)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#BuildUrl)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/JLXl1hZK7l4)]
- **<big>AddQueryParams</big>** : 向 url 添加查询参数。 - **<big>AddQueryParams</big>** : 向 url 添加查询参数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#AddQueryParams)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#AddQueryParams)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/JLXl1hZK7l4)]
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3> <h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -2225,7 +2237,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/LzaKocSV79u)] [[play](https://go.dev/play/p/LzaKocSV79u)]
- **<big>IsAlphaNumeric</big>** : 验证字符串是字母或数字。 - **<big>IsAlphaNumeric</big>** : 验证字符串是字母或数字。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsAlphaNumeric)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsAlphaNumeric)]
[[play](https://go.dev/play/p/todo)] [[play](https://go.dev/play/p/RHeESLrLg9c)]
- **<big>IsJSON</big>** : 验证字符串是否是有效 json。 - **<big>IsJSON</big>** : 验证字符串是否是有效 json。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsJSON)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsJSON)]
[[play](https://go.dev/play/p/8Kip1Itjiil)] [[play](https://go.dev/play/p/8Kip1Itjiil)]

View File

@@ -25,12 +25,14 @@ type lockEntry struct {
// NewKeyedLocker creates a new KeyedLocker with the specified TTL for lock expiration. // NewKeyedLocker creates a new KeyedLocker with the specified TTL for lock expiration.
// The TTL is used to automatically release locks that are no longer held. // The TTL is used to automatically release locks that are no longer held.
// Play: https://go.dev/play/p/GzeyC33T5rw
func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K] { func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K] {
return &KeyedLocker[K]{ttl: ttl} return &KeyedLocker[K]{ttl: ttl}
} }
// Do acquires a lock for the specified key and executes the provided function. // Do acquires a lock for the specified key and executes the provided function.
// It returns an error if the context is canceled before the function completes. // It returns an error if the context is canceled before the function completes.
// Play: https://go.dev/play/p/GzeyC33T5rw
func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error { func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error {
entry := l.acquire(key) entry := l.acquire(key)
defer l.release(key, entry, key) defer l.release(key, entry, key)
@@ -107,12 +109,14 @@ type rwLockEntry struct {
// NewRWKeyedLocker creates a new RWKeyedLocker with the specified TTL for lock expiration. // NewRWKeyedLocker creates a new RWKeyedLocker with the specified TTL for lock expiration.
// The TTL is used to automatically release locks that are no longer held. // The TTL is used to automatically release locks that are no longer held.
// Play: https://go.dev/play/p/CkaJWWwZm9
func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K] { func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K] {
return &RWKeyedLocker[K]{ttl: ttl} return &RWKeyedLocker[K]{ttl: ttl}
} }
// RLock acquires a read lock for the specified key and executes the provided function. // RLock acquires a read lock for the specified key and executes the provided function.
// It returns an error if the context is canceled before the function completes. // It returns an error if the context is canceled before the function completes.
// Play: https://go.dev/play/p/ZrCr8sMo77T
func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error { func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error {
entry := l.acquire(key) entry := l.acquire(key)
defer l.release(entry, key) defer l.release(entry, key)
@@ -141,6 +145,7 @@ func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error {
// Lock acquires a write lock for the specified key and executes the provided function. // Lock acquires a write lock for the specified key and executes the provided function.
// It returns an error if the context is canceled before the function completes. // It returns an error if the context is canceled before the function completes.
// Play: https://go.dev/play/p/WgAcXbOPKGk
func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error { func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error {
entry := l.acquire(key) entry := l.acquire(key)
defer l.release(entry, key) defer l.release(entry, key)
@@ -199,12 +204,14 @@ type TryKeyedLocker[K comparable] struct {
} }
// NewTryKeyedLocker creates a new TryKeyedLocker. // NewTryKeyedLocker creates a new TryKeyedLocker.
// Play: https://go.dev/play/p/VG9qLvyetE2
func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K] { func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K] {
return &TryKeyedLocker[K]{locks: make(map[K]*casMutex)} return &TryKeyedLocker[K]{locks: make(map[K]*casMutex)}
} }
// TryLock tries to acquire a lock for the specified key. // TryLock tries to acquire a lock for the specified key.
// It returns true if the lock was acquired, false otherwise. // It returns true if the lock was acquired, false otherwise.
// Play: https://go.dev/play/p/VG9qLvyetE2
func (l *TryKeyedLocker[K]) TryLock(key K) bool { func (l *TryKeyedLocker[K]) TryLock(key K) bool {
l.mu.Lock() l.mu.Lock()
@@ -219,6 +226,7 @@ func (l *TryKeyedLocker[K]) TryLock(key K) bool {
} }
// Unlock releases the lock for the specified key. // Unlock releases the lock for the specified key.
// Play: https://go.dev/play/p/VG9qLvyetE2
func (l *TryKeyedLocker[K]) Unlock(key K) { func (l *TryKeyedLocker[K]) Unlock(key K) {
l.mu.Lock() l.mu.Lock()
defer l.mu.Unlock() defer l.mu.Unlock()

View File

@@ -228,6 +228,42 @@ func ToPointer[T any](value T) *T {
return &value return &value
} }
// ToPointers convert a slice of values to a slice of pointers.
// Play: todo
func ToPointers[T any](values []T) []*T {
result := make([]*T, len(values))
for i := range values {
result[i] = &values[i]
}
return result
}
// FromPointer returns the value pointed to by the pointer.
// Play: todo
func FromPointer[T any](ptr *T) T {
if ptr == nil {
var zeroValue T
return zeroValue
}
return *ptr
}
// FromPointers convert a slice of pointers to a slice of values.
// Play: todo
func FromPointers[T any](pointers []*T) []T {
result := make([]T, len(pointers))
for i, ptr := range pointers {
if ptr == nil {
var zeroValue T
result[i] = zeroValue
} else {
result[i] = *ptr
}
}
return result
}
// ToMap convert a slice of structs to a map based on iteratee function. // ToMap convert a slice of structs to a map based on iteratee function.
// Play: https://go.dev/play/p/tVFy7E-t24l // Play: https://go.dev/play/p/tVFy7E-t24l
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V { func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
@@ -406,15 +442,15 @@ func ToStdBase64(value any) string {
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
return "" return ""
} }
switch value.(type) { switch v := value.(type) {
case []byte: case []byte:
return base64.StdEncoding.EncodeToString(value.([]byte)) return base64.StdEncoding.EncodeToString(v)
case string: case string:
return base64.StdEncoding.EncodeToString([]byte(value.(string))) return base64.StdEncoding.EncodeToString([]byte(v))
case error: case error:
return base64.StdEncoding.EncodeToString([]byte(value.(error).Error())) return base64.StdEncoding.EncodeToString([]byte(v.Error()))
default: default:
marshal, err := json.Marshal(value) marshal, err := json.Marshal(v)
if err != nil { if err != nil {
return "" return ""
} }
@@ -428,15 +464,15 @@ func ToUrlBase64(value any) string {
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
return "" return ""
} }
switch value.(type) { switch v := value.(type) {
case []byte: case []byte:
return base64.URLEncoding.EncodeToString(value.([]byte)) return base64.URLEncoding.EncodeToString(v)
case string: case string:
return base64.URLEncoding.EncodeToString([]byte(value.(string))) return base64.URLEncoding.EncodeToString([]byte(v))
case error: case error:
return base64.URLEncoding.EncodeToString([]byte(value.(error).Error())) return base64.URLEncoding.EncodeToString([]byte(v.Error()))
default: default:
marshal, err := json.Marshal(value) marshal, err := json.Marshal(v)
if err != nil { if err != nil {
return "" return ""
} }
@@ -450,7 +486,7 @@ func ToRawStdBase64(value any) string {
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
return "" return ""
} }
switch value.(type) { switch v := value.(type) {
case []byte: case []byte:
return base64.RawStdEncoding.EncodeToString(value.([]byte)) return base64.RawStdEncoding.EncodeToString(value.([]byte))
case string: case string:
@@ -458,7 +494,7 @@ func ToRawStdBase64(value any) string {
case error: case error:
return base64.RawStdEncoding.EncodeToString([]byte(value.(error).Error())) return base64.RawStdEncoding.EncodeToString([]byte(value.(error).Error()))
default: default:
marshal, err := json.Marshal(value) marshal, err := json.Marshal(v)
if err != nil { if err != nil {
return "" return ""
} }
@@ -472,7 +508,7 @@ func ToRawUrlBase64(value any) string {
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
return "" return ""
} }
switch value.(type) { switch v := value.(type) {
case []byte: case []byte:
return base64.RawURLEncoding.EncodeToString(value.([]byte)) return base64.RawURLEncoding.EncodeToString(value.([]byte))
case string: case string:
@@ -480,7 +516,7 @@ func ToRawUrlBase64(value any) string {
case error: case error:
return base64.RawURLEncoding.EncodeToString([]byte(value.(error).Error())) return base64.RawURLEncoding.EncodeToString([]byte(value.(error).Error()))
default: default:
marshal, err := json.Marshal(value) marshal, err := json.Marshal(v)
if err != nil { if err != nil {
return "" return ""
} }

View File

@@ -302,6 +302,75 @@ func TestToPointer(t *testing.T) {
assert.Equal(*result, 123) assert.Equal(*result, 123)
} }
func TestToPointers(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToPointers")
intVals := []int{1, 2, 3}
result := ToPointers(intVals)
assert.Equal(3, len(result))
assert.Equal(1, *result[0])
assert.Equal(2, *result[1])
assert.Equal(3, *result[2])
stringVals := []string{"a", "b", "c"}
resultStr := ToPointers(stringVals)
assert.Equal(3, len(resultStr))
assert.Equal("a", *resultStr[0])
assert.Equal("b", *resultStr[1])
assert.Equal("c", *resultStr[2])
}
func TestFromPointer(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromPointer")
intVal := 123
pointer := &intVal
result := FromPointer(pointer)
assert.Equal(123, result)
stringVal := "abc"
stringPointer := &stringVal
resultStr := FromPointer(stringPointer)
assert.Equal("abc", resultStr)
}
func TestFromPointers(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromPointers")
intPointers := []*int{new(int), new(int), new(int)}
*intPointers[0] = 1
*intPointers[1] = 2
*intPointers[2] = 3
result := FromPointers(intPointers)
assert.Equal(3, len(result))
assert.Equal(1, result[0])
assert.Equal(2, result[1])
assert.Equal(3, result[2])
stringPointers := []*string{new(string), new(string), new(string)}
*stringPointers[0] = "a"
*stringPointers[1] = "b"
*stringPointers[2] = "c"
resultStr := FromPointers(stringPointers)
assert.Equal(3, len(resultStr))
assert.Equal("a", resultStr[0])
assert.Equal("b", resultStr[1])
assert.Equal("c", resultStr[2])
}
func TestEncodeByte(t *testing.T) { func TestEncodeByte(t *testing.T) {
t.Parallel() t.Parallel()

View File

@@ -174,7 +174,7 @@ func AesCtrCrypt(data, key []byte) []byte {
// AesCtrEncrypt encrypt data with key use AES CTR algorithm // AesCtrEncrypt encrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32. // len(key) should be 16, 24 or 32.
// Play: todo // Play: https://go.dev/play/p/x6pjPAvThRz
func AesCtrEncrypt(data, key []byte) []byte { func AesCtrEncrypt(data, key []byte) []byte {
if !isAesKeyLengthValid(len(key)) { if !isAesKeyLengthValid(len(key)) {
panic("aes: invalid key length (must be 16, 24, or 32 bytes)") panic("aes: invalid key length (must be 16, 24, or 32 bytes)")
@@ -199,7 +199,7 @@ func AesCtrEncrypt(data, key []byte) []byte {
// AesCtrDecrypt decrypt data with key use AES CTR algorithm // AesCtrDecrypt decrypt data with key use AES CTR algorithm
// len(key) should be 16, 24 or 32. // len(key) should be 16, 24 or 32.
// Play: todo // Play: https://go.dev/play/p/x6pjPAvThRz
func AesCtrDecrypt(encrypted, key []byte) []byte { func AesCtrDecrypt(encrypted, key []byte) []byte {
if !isAesKeyLengthValid(len(key)) { if !isAesKeyLengthValid(len(key)) {
panic("aes: invalid key length (must be 16, 24, or 32 bytes)") panic("aes: invalid key length (must be 16, 24, or 32 bytes)")
@@ -507,7 +507,7 @@ func DesCtrCrypt(data, key []byte) []byte {
// DesCtrEncrypt encrypt data with key use DES CTR algorithm // DesCtrEncrypt encrypt data with key use DES CTR algorithm
// len(key) should be 8. // len(key) should be 8.
// Play: todo // Play: https://go.dev/play/p/S6p_WHCgH1d
func DesCtrEncrypt(data, key []byte) []byte { func DesCtrEncrypt(data, key []byte) []byte {
if len(key) != 8 { if len(key) != 8 {
panic("des: key length must be 8 bytes") panic("des: key length must be 8 bytes")
@@ -534,7 +534,7 @@ func DesCtrEncrypt(data, key []byte) []byte {
// DesCtrDecrypt decrypt data with key use DES CTR algorithm // DesCtrDecrypt decrypt data with key use DES CTR algorithm
// len(key) should be 8. // len(key) should be 8.
// Play: todo // Play: https://go.dev/play/p/S6p_WHCgH1d
func DesCtrDecrypt(encrypted, key []byte) []byte { func DesCtrDecrypt(encrypted, key []byte) []byte {
if len(key) != 8 { if len(key) != 8 {
panic("des: key length must be 8 bytes") panic("des: key length must be 8 bytes")

View File

@@ -74,6 +74,32 @@ func ExampleAesCtrCrypt() {
// hello // hello
} }
func ExampleAesCtrEncrypt() {
data := "hello"
key := "abcdefghijklmnop"
enCrypt := AesCtrEncrypt([]byte(data), []byte(key))
deCrypt := AesCtrDecrypt(enCrypt, []byte(key))
fmt.Println(string(deCrypt))
// Output:
// hello
}
func ExampleAesCtrDecrypt() {
data := "hello"
key := "abcdefghijklmnop"
enCrypt := AesCtrEncrypt([]byte(data), []byte(key))
deCrypt := AesCtrDecrypt(enCrypt, []byte(key))
fmt.Println(string(deCrypt))
// Output:
// hello
}
func ExampleAesCfbEncrypt() { func ExampleAesCfbEncrypt() {
data := "hello" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
@@ -227,6 +253,19 @@ func ExampleDesCtrCrypt() {
// hello // hello
} }
func ExampleDesCtrDecrypt() {
data := "hello"
key := "abcdefgh"
enCrypt := DesCtrEncrypt([]byte(data), []byte(key))
deCrypt := DesCtrDecrypt(enCrypt, []byte(key))
fmt.Println(string(deCrypt))
// Output:
// hello
}
func ExampleDesCfbEncrypt() { func ExampleDesCfbEncrypt() {
data := "hello" data := "hello"
key := "abcdefgh" key := "abcdefgh"

View File

@@ -1,51 +1,51 @@
-----BEGIN rsa private key----- -----BEGIN rsa private key-----
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
-----END rsa private key----- -----END rsa private key-----

View File

@@ -1,14 +1,14 @@
-----BEGIN rsa public key----- -----BEGIN rsa public key-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw6Q11wDtWHZiyQbv+Xzn MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt8K0R1gvIA4MAX0lpFtV
tJbEELkPQ3oVSVCVjTx+ls5I+yR6oq8LxyoUE6SHcBlludkzs02B0rDkkfj6vl0i hcZQaGd5/4I2W+LESIO/7o1PWh2LodghN4OFF0Wfg+/TBZXXAfzCH5MlLtu7w89f
PCzr3HP1XT1WwFiQJnXKtNNNiLvvewB/aynj/UIBCZZvMTYwK6nc76i4JWcajaiU ee/vLMUpRqTxIR26pybgKKi3RUEQb69PMuq8fFEpNwYc5n+rFNg531Jn/qylDnMS
I4u84Fp7gOn0IgXMhvrwtGHk7HK1Zjr0afUJVbodc6pMZfe0QWpnDq7zaeYdkPwz pfTn2qHNrLUnMOMR+hnAh3yBJpAx61V/8BlFuCUx/99r3uZY0xKA7Hr7OlEvCsvg
8klWAatLDZTeR5dYli2NiWOBepO1538ZvEK3S/QP2nWJzPJy2PbEHfDaFgr055w/ uAzHhPPnhTf37zsiebpoWluTadq9XO2XfBKcIb/MXzOhb+fR9mqJ3ajy8xGhtI3H
wu0MzAQgkXGV8PubhYboJuQAkuXc63IPpmWVL/93WeCNRiL5fvNzUHsbPtT48A9N QK1wfjF1c/uzyatjDHfzpCTF00v6k3pEH646sHJjgzCs+ZT4wXZU2YiIyrFpr64R
nnUn4QVuVGeXIxJ1skAFsoh7i+h+mK/p5rzjPtw56nE20gYXhxf7FzbHYtHn0ego vpBaERXBjBe2jlEC9fKnFCYfkBSW3oYHi1Mh5C7DW/ttzKBjVyS8sBF2L9X+PoRJ
BddUzlOY0yzvCgI5Yy1RdkNe/5vU1bpLsdU/WItjR2h6EfqLosQ4iKowPBYQXJOI QNH7yp4kED18XQwrzuLaJ8xJzQNnvVjWxzPeXngmX+CIIlNCt3zc2hLPTteqbpmK
NbpkvIhkhCVbPpMvmhfi/lATiKdoXgtvuB04wth011c5W/yXA+A3Ob73Sr2+zyxF VuZusrSz4O8d6Qqwo4ofhj/gz67v31lsrOCOc5tkuXRfikUHGbEOE7S2zfSlh2wA
870tOp3rNTWsYLvCOjf+JdjgM3AzNuFxE4NdMLvXDf7CIXSb3X9rj3qM769Lz6XX sgSX/LjQZH6WHyZqLJIVTcrccouZDkCBbQhuGJMTA2VOUZkKPB8RJ8Fw3su/ge9N
bRBVbO0HxGyqLTPPmSWV61jQuUTWNGnxkovoYLrpgyumIjjIcl0aY1hogmQeA6ZN dig8YNSAjbWFFSFl1tyncWuadS046IXVLF80a/z66i8OOQ6D/uUjGWWKIbUFp/w3
gJxaUw9r/p8vnThL5UXKlbcCAwEAAQ== hOlLNXLCnCRV/LJ1L4UmzusCAwEAAQ==
-----END rsa public key----- -----END rsa public key-----

View File

@@ -60,7 +60,7 @@ func (q *ArrayQueue[T]) Front() T {
// Back return back value of queue // Back return back value of queue
func (q *ArrayQueue[T]) Back() T { func (q *ArrayQueue[T]) Back() T {
return q.data[q.size-1] return q.data[q.tail-1]
} }
// EnQueue put element into queue // EnQueue put element into queue

View File

@@ -2,10 +2,9 @@
outline: deep outline: deep
--- ---
# API概述 # API 概述
<b>lancet柳叶刀是一个功能强大、全面、高效、可复用的go语言工具函数库。包含25个包超过600个工具函数。功能涵盖字符串处理、切片处理、网络、并发、加解密、文件处理、时间/日期、流处理、迭代器等等。</b>
<b>lancet柳叶刀是一个功能强大、全面、高效、可复用的 go 语言工具函数库。包含 25 个包,超过 600 个工具函数。功能涵盖字符串处理、切片处理、网络、并发、加解密、文件处理、时间/日期、流处理、迭代器等等。</b>
<style> <style>
.package-title { .package-title {
@@ -27,7 +26,7 @@ outline: deep
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
line-height: 40px; line-height: 40px;
background: #10b981; background: #6cadf5;
border: 1px solid; border: 1px solid;
margin-right: 10px; margin-right: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@@ -67,4 +66,4 @@ outline: deep
<div class="package-cell">validator</div> <div class="package-cell">validator</div>
<div class="package-cell">xerror</div> <div class="package-cell">xerror</div>
</div> </div>
</div> </div>

View File

@@ -8,7 +8,7 @@ algorithm 算法包实现一些基本算法sortsearchlrucache。
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/lrucache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lrucache.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>

View File

@@ -477,7 +477,7 @@ func main() {
func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K] func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K]
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GzeyC33T5rw)</span></b>
```go ```go
package main package main
@@ -534,7 +534,7 @@ func main() {
func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GzeyC33T5rw)</span></b>
```go ```go
package main package main
@@ -591,7 +591,7 @@ func main() {
func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K] func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K]
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CkaJWWwZm9)</span></b>
```go ```go
package main package main
@@ -640,7 +640,7 @@ func main() {
func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZrCr8sMo77T)</span></b>
```go ```go
package main package main
@@ -689,7 +689,7 @@ func main() {
func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/WgAcXbOPKGk)</span></b>
```go ```go
package main package main
@@ -738,7 +738,7 @@ func main() {
func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K] func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K]
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main
@@ -779,7 +779,7 @@ func main() {
func (l *TryKeyedLocker[K]) TryLock(key K) bool func (l *TryKeyedLocker[K]) TryLock(key K) bool
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main
@@ -820,7 +820,7 @@ func main() {
func (l *TryKeyedLocker[K]) Unlock(key K) func (l *TryKeyedLocker[K]) Unlock(key K)
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main

View File

@@ -27,7 +27,9 @@ import (
- [AesEcbDecrypt](#AesEcbDecrypt) - [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt) - [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt) - [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt) - [AesCtrCrypt<sup>deprecated</sup>](#AesCtrCrypt)
- [AesCtrEncrypt](#AesCtrEncrypt)
- [AesCtrDecrypt](#AesCtrDecrypt)
- [AesCfbEncrypt](#AesCfbEncrypt) - [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt) - [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt) - [AesOfbEncrypt](#AesOfbEncrypt)
@@ -40,7 +42,7 @@ import (
- [DesEcbDecrypt](#DesEcbDecrypt) - [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt) - [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt) - [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt) - [DesCtrCrypt<sup>deprecated</sup>](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt) - [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt) - [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt) - [DesOfbEncrypt](#DesOfbEncrypt)
@@ -73,7 +75,6 @@ import (
- [RsaSign](#RsaSign) - [RsaSign](#RsaSign)
- [RsaVerifySign](#RsaVerifySign) - [RsaVerifySign](#RsaVerifySign)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## 文档 ## 文档
@@ -218,6 +219,8 @@ func main() {
<p>使用AES CTR算法模式加密/解密数据,参数`key`的长度是16, 24 or 32。</p> <p>使用AES CTR算法模式加密/解密数据,参数`key`的长度是16, 24 or 32。</p>
> ⚠️ 本函数已弃用,使用`AesCtrEncrypt`和`AesCtrDecrypt`代替。
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
@@ -248,6 +251,74 @@ func main() {
} }
``` ```
### <span id="AesCtrEncrypt">AesCtrEncrypt</span>
<p>使用AES CTR算法模式加密数据参数`key`的长度是16, 24 or 32。</p>
<b>函数签名:</b>
```go
func AesCtrEncrypt(data, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/x6pjPAvThRz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="AesCtrDecrypt">AesCtrDecrypt</span>
<p>使用AES CTR算法模式解密数据参数`key`的长度是16, 24 or 32。</p>
<b>函数签名:</b>
```go
func AesCtrDecrypt(encrypted, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/x6pjPAvThRz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span> ### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>使用AES CFB算法模式加密数据参数`key`的长度是16, 24 or 32。</p> <p>使用AES CFB算法模式加密数据参数`key`的长度是16, 24 or 32。</p>
@@ -648,10 +719,80 @@ func main() {
} }
``` ```
### <span id="DesCtrEncrypt">DesCtrEncrypt</span>
<p>使用DES CTR算法模式加密数据参数`key`的长度是8</p>
<b>函数签名:</b>
```go
func DesCtrEncrypt(data, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/S6p_WHCgH1d)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefgh"
encrypted := cryptor.DesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="DesCtrDecrypt">DesCtrDecrypt</span>
<p>使用DES CTR算法模式加密数据参数`key`的长度是8</p>
<b>函数签名:</b>
```go
func DesCtrDecrypt(encrypted, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/S6p_WHCgH1d)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefgh"
encrypted := cryptor.DesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="DesCtrCrypt">DesCtrCrypt</span> ### <span id="DesCtrCrypt">DesCtrCrypt</span>
<p>使用DES CTR算法模式加密/解密数据,参数`key`的长度是8</p> <p>使用DES CTR算法模式加密/解密数据,参数`key`的长度是8</p>
> ⚠️ 本函数已弃用,使用`DesCtrEncrypt`和`DesCtrDecrypt`代替。
<b>函数签名:</b> <b>函数签名:</b>
```go ```go

View File

@@ -427,7 +427,7 @@ func main() {
func RemoveDir(path string, onDelete ...func(path string)) error func RemoveDir(path string, onDelete ...func(path string)) error
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Oa6KnPek2uy)</span></b>
```go ```go
package main package main
@@ -970,7 +970,7 @@ func main() {
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uNep3Tr8fqF)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
@@ -994,9 +994,9 @@ func main() {
if err != nil { if err != nil {
return return
} }
fmt.Println(string(dat)) fmt.Println(string(dat))
// Output: // Output:
// User-agent: * // User-agent: *
// Disallow: /deny // Disallow: /deny
@@ -1025,7 +1025,7 @@ import (
func main() { func main() {
const mb = 1024 * 1024 const mb = 1024 * 1024
const defaultChunkSizeMB = 100 const defaultChunkSizeMB = 100
// test1.csv file content: // test1.csv file content:
// Lili,22,female // Lili,22,female
@@ -1089,7 +1089,7 @@ func main() {
numParsers := runtime.NumCPU() numParsers := runtime.NumCPU()
linesCh := make(chan []string, numParsers) linesCh := make(chan []string, numParsers)
// test1.csv file content: // test1.csv file content:
// Lili,22,female // Lili,22,female
// Jim,21,male // Jim,21,male
@@ -1114,6 +1114,7 @@ func main() {
// 2 // 2
} }
``` ```
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span> ### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
<p>返回exe,dll文件版本号(仅Window平台).</p> <p>返回exe,dll文件版本号(仅Window平台).</p>
@@ -1143,4 +1144,4 @@ func main() {
// Output: // Output:
// 3.9.10.19 // 3.9.10.19
} }
``` ```

View File

@@ -1095,7 +1095,7 @@ func main() {
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V) func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0nlPo6YLdt3)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0nlPo6YLdt3)</span></b>
@@ -1259,7 +1259,6 @@ func main() {
} }
``` ```
### <span id="OrderedMap_Delete">OrderedMap_Delete</span> ### <span id="OrderedMap_Delete">OrderedMap_Delete</span>
<p>删除给定键的键值对。</p> <p>删除给定键的键值对。</p>
@@ -2192,7 +2191,6 @@ func main() {
} }
``` ```
### <span id="GetOrSet">GetOrSet</span> ### <span id="GetOrSet">GetOrSet</span>
<p>返回给定键的值,如果不存在则设置该值。</p> <p>返回给定键的值,如果不存在则设置该值。</p>
@@ -2276,7 +2274,7 @@ func main() {
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b>
@@ -2319,7 +2317,7 @@ func main() {
func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bvNwNBZDm6v)</span></b>
```go ```go
package main package main
@@ -2346,4 +2344,4 @@ func main() {
// Output: // Output:
// [b d] // [b d]
} }
``` ```

View File

@@ -1044,7 +1044,7 @@ func main() {
func BuildUrl(scheme, host, path string, query map[string][]string) (string, error) func BuildUrl(scheme, host, path string, query map[string][]string) (string, error)
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JLXl1hZK7l4)</span></b>
```go ```go
package main package main
@@ -1084,7 +1084,7 @@ func main() {
func AddQueryParams(urlStr string, params map[string][]string) (string, error) func AddQueryParams(urlStr string, params map[string][]string) (string, error)
``` ```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b> <b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JLXl1hZK7l4)</span></b>
```go ```go
package main package main

View File

@@ -834,7 +834,7 @@ func main() {
func IsAlphaNumeric(s string) bool func IsAlphaNumeric(s string) bool
``` ```
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/todo)</span></b> <b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/RHeESLrLg9c)</span></b>
```go ```go
import ( import (

View File

@@ -6,7 +6,6 @@ outline: deep
<b>Lancet (Lancet) is a powerful, comprehensive, efficient and reusable go language tool function library. Contains 25 packages, more than 600 utility functions. Functions cover string processing, slice processing, network, concurrency, encryption and decryption, file processing, time/date, stream processing, iterators, and more.</b> <b>Lancet (Lancet) is a powerful, comprehensive, efficient and reusable go language tool function library. Contains 25 packages, more than 600 utility functions. Functions cover string processing, slice processing, network, concurrency, encryption and decryption, file processing, time/date, stream processing, iterators, and more.</b>
<style> <style>
.package-title { .package-title {
color: black; color: black;
@@ -27,7 +26,7 @@ outline: deep
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
line-height: 40px; line-height: 40px;
background: #059669; background: #6cadf5;
border: 1px solid; border: 1px solid;
margin-right: 10px; margin-right: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@@ -47,6 +46,7 @@ outline: deep
<div class="package-cell">cryptor</div> <div class="package-cell">cryptor</div>
<div class="package-cell">datastructure</div> <div class="package-cell">datastructure</div>
<div class="package-cell">datetime</div> <div class="package-cell">datetime</div>
<div class="package-cell">eventbus</div>
<div class="package-cell">fileutil</div> <div class="package-cell">fileutil</div>
<div class="package-cell">formatter</div> <div class="package-cell">formatter</div>
<div class="package-cell">function</div> <div class="package-cell">function</div>
@@ -67,4 +67,3 @@ outline: deep
<div class="package-cell">xerror</div> <div class="package-cell">xerror</div>
</div> </div>
</div> </div>

View File

@@ -8,7 +8,7 @@ Package algorithm implements some basic algorithm. eg. sort, search.
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go) - [https://github.com/duke-git/lancet/blob/main/algorithm/lrucache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lrucache.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>

View File

@@ -479,7 +479,7 @@ func main() {
func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K] func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K]
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GzeyC33T5rw)</span></b>
```go ```go
package main package main
@@ -536,7 +536,7 @@ func main() {
func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GzeyC33T5rw)</span></b>
```go ```go
package main package main
@@ -593,7 +593,7 @@ func main() {
func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K] func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K]
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ZrCr8sMo77T)</span></b>
```go ```go
package main package main
@@ -642,7 +642,7 @@ func main() {
func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ZrCr8sMo77T)</span></b>
```go ```go
package main package main
@@ -691,7 +691,7 @@ func main() {
func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/WgAcXbOPKGk)</span></b>
```go ```go
package main package main
@@ -740,7 +740,7 @@ func main() {
func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K] func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K]
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main
@@ -781,7 +781,7 @@ func main() {
func (l *TryKeyedLocker[K]) TryLock(key K) bool func (l *TryKeyedLocker[K]) TryLock(key K) bool
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main
@@ -822,7 +822,7 @@ func main() {
func (l *TryKeyedLocker[K]) Unlock(key K) func (l *TryKeyedLocker[K]) Unlock(key K)
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/VG9qLvyetE2)</span></b>
```go ```go
package main package main

View File

@@ -27,7 +27,9 @@ import (
- [AesEcbDecrypt](#AesEcbDecrypt) - [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt) - [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt) - [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt) - [AesCtrCrypt<sup>deprecated</sup>](#AesCtrCrypt)
- [AesCtrEncrypt](#AesCtrEncrypt)
- [AesCtrDecrypt](#AesCtrDecrypt)
- [AesCfbEncrypt](#AesCfbEncrypt) - [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt) - [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt) - [AesOfbEncrypt](#AesOfbEncrypt)
@@ -40,7 +42,9 @@ import (
- [DesEcbDecrypt](#DesEcbDecrypt) - [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt) - [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt) - [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt) - [DesCtrCrypt<sup>deprecated</sup>](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesCfbEncrypt](#DesCfbEncrypt) - [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt) - [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt) - [DesOfbEncrypt](#DesOfbEncrypt)
@@ -217,6 +221,8 @@ func main() {
<p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p>
> ⚠️ This function is deprecated. use `AesCtrEncrypt` and `AesCtrDecrypt` instead.
<b>Signature:</b> <b>Signature:</b>
```go ```go
@@ -247,6 +253,74 @@ func main() {
} }
``` ```
### <span id="AesCtrEncrypt">AesCtrEncrypt</span>
<p>Encrypt data with key use AES CTR algorithm</p>
<b>Signature:</b>
```go
func AesCtrEncrypt(data, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/x6pjPAvThRz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="AesCtrDecrypt">AesCtrDecrypt</span>
<p>Decrypt data with key use AES CTR algorithm</p>
<b>Signature:</b>
```go
func AesCtrDecrypt(encrypted, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/x6pjPAvThRz)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span> ### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -651,6 +725,8 @@ func main() {
<p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p> <p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
> ⚠️ This function is deprecated. use `DesCtrEncrypt` and `DesCtrDecrypt` instead.
<b>Signature:</b> <b>Signature:</b>
```go ```go
@@ -681,6 +757,74 @@ func main() {
} }
``` ```
### <span id="DesCtrEncrypt">DesCtrCrypt</span>
<p>Encrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
<b>Signature:</b>
```go
func DesCtrEncrypt(data, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/S6p_WHCgH1d)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefgh"
encrypted := cryptor.DesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="DesCtrDecrypt">DesCtrDecrypt</span>
<p>Decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
<b>Signature:</b>
```go
func DesCtrDecrypt(encrypted, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/S6p_WHCgH1d)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello"
key := "abcdefgh"
encrypted := cryptor.DesCtrEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
}
```
### <span id="DesCfbEncrypt">DesCfbEncrypt</span> ### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
<p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p>

View File

@@ -427,7 +427,7 @@ func main() {
func RemoveDir(path string, onDelete ...func(path string)) error func RemoveDir(path string, onDelete ...func(path string)) error
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Oa6KnPek2uy)</span></b>
```go ```go
package main package main
@@ -970,7 +970,7 @@ func main() {
<b>Signature:</b> <b>Signature:</b>
```go ```go
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uNep3Tr8fqF)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
@@ -1023,7 +1023,7 @@ import (
func main() { func main() {
const mb = 1024 * 1024 const mb = 1024 * 1024
const defaultChunkSizeMB = 100 const defaultChunkSizeMB = 100
// test1.csv file content: // test1.csv file content:
// Lili,22,female // Lili,22,female
@@ -1087,7 +1087,7 @@ func main() {
numParsers := runtime.NumCPU() numParsers := runtime.NumCPU()
linesCh := make(chan []string, numParsers) linesCh := make(chan []string, numParsers)
// test1.csv file content: // test1.csv file content:
// Lili,22,female // Lili,22,female
// Jim,21,male // Jim,21,male
@@ -1140,8 +1140,8 @@ func main() {
} }
fmt.Println(v) fmt.Println(v)
// Output: // Output:
// 3.9.10.19 // 3.9.10.19
} }
``` ```

View File

@@ -620,7 +620,7 @@ func main() {
### <span id="Nand">Nand</span> ### <span id="Nand">Nand</span>
<p>Returns a composed predicate that represents the logical NAND of a list of predicates. It evaluates to true only if all predicates evaluate to false for the given value.</p> <p>Returns a composed predicate that represents the logical NAND of a list of predicates. It evaluates to false only if all predicates evaluate to true for the given value.</p>
<b>Signature:</b> <b>Signature:</b>
@@ -650,7 +650,7 @@ func main() {
// Output: // Output:
// false // false
// false // true
// true // true
} }
``` ```

View File

@@ -10,7 +10,6 @@ Package maputil includes some functions to manipulate map.
- [https://github.com/duke-git/lancet/blob/main/maputil/concurrentmap.go](https://github.com/duke-git/lancet/blob/main/maputil/concurrentmap.go) - [https://github.com/duke-git/lancet/blob/main/maputil/concurrentmap.go](https://github.com/duke-git/lancet/blob/main/maputil/concurrentmap.go)
- [https://github.com/duke-git/lancet/blob/main/maputil/orderedmap.go](https://github.com/duke-git/lancet/blob/main/maputil/orderedmap.go) - [https://github.com/duke-git/lancet/blob/main/maputil/orderedmap.go](https://github.com/duke-git/lancet/blob/main/maputil/orderedmap.go)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
## Example: ## Example:
@@ -1111,7 +1110,7 @@ Translate the key and value of the map into two slices that are sorted according
<b>Signature:</b> <b>Signature:</b>
```go ```go
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V) func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/0nlPo6YLdt3)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/0nlPo6YLdt3)</span></b>
@@ -1275,7 +1274,6 @@ func main() {
} }
``` ```
### <span id="OrderedMap_Delete">OrderedMap_Delete</span> ### <span id="OrderedMap_Delete">OrderedMap_Delete</span>
<p>Deletes the key-value pair for the given key.</p> <p>Deletes the key-value pair for the given key.</p>
@@ -1838,7 +1836,7 @@ func main() {
fmt.Println(om.Elements()) fmt.Println(om.Elements())
// Output: // Output:
// [{a 1} {b 2} {c 3}] // [{a 1} {b 2} {c 3}]
} }
``` ```
@@ -2294,7 +2292,7 @@ func main() {
<b>Signature:</b> <b>Signature:</b>
```go ```go
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/99QjSYSBdiM)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/99QjSYSBdiM)</span></b>
@@ -2337,7 +2335,7 @@ func main() {
func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/bvNwNBZDm6v)</span></b>
```go ```go
package main package main
@@ -2364,4 +2362,4 @@ func main() {
// Output: // Output:
// [b d] // [b d]
} }
``` ```

View File

@@ -51,7 +51,6 @@ import (
- [BuildUrl](#BuildUrl) - [BuildUrl](#BuildUrl)
- [AddQueryParams](#AddQueryParams) - [AddQueryParams](#AddQueryParams)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
<link rel="stylesheet" type="text/css" href="/styles/api_doc.css"> <link rel="stylesheet" type="text/css" href="/styles/api_doc.css">
@@ -1045,7 +1044,7 @@ func main() {
func BuildUrl(scheme, host, path string, query map[string][]string) (string, error) func BuildUrl(scheme, host, path string, query map[string][]string) (string, error)
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JLXl1hZK7l4)</span></b>
```go ```go
package main package main
@@ -1085,7 +1084,7 @@ func main() {
func AddQueryParams(urlStr string, params map[string][]string) (string, error) func AddQueryParams(urlStr string, params map[string][]string) (string, error)
``` ```
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b> <b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JLXl1hZK7l4)</span></b>
```go ```go
package main package main
@@ -1113,4 +1112,4 @@ func main() {
// https://example.com/query?a=foo&a=bar&b=baz // https://example.com/query?a=foo&a=bar&b=baz
// <nil> // <nil>
} }
``` ```

View File

@@ -836,7 +836,7 @@ func main() {
func IsAlphaNumeric(s string) bool func IsAlphaNumeric(s string) bool
``` ```
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/todo)</span></b> <b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/RHeESLrLg9c)</span></b>
```go ```go
import ( import (

View File

@@ -190,7 +190,7 @@ func RemoveFile(path string, onDelete ...func(path string)) error {
} }
// RemoveDir remove the path directory. // RemoveDir remove the path directory.
// Play: todo // Play: https://go.dev/play/p/Oa6KnPek2uy
func RemoveDir(path string, onDelete ...func(path string)) error { func RemoveDir(path string, onDelete ...func(path string)) error {
info, err := os.Stat(path) info, err := os.Stat(path)
if err != nil { if err != nil {

View File

@@ -18,7 +18,7 @@ func And[T any](predicates ...func(T) bool) func(T) bool {
} }
// Nand returns a composed predicate that represents the logical NAND of a list of predicates. // Nand returns a composed predicate that represents the logical NAND of a list of predicates.
// It evaluates to true only if all predicates evaluate to false for the given value. // It evaluates to false only if all predicates evaluate to true for the given value.
// Play: https://go.dev/play/p/Rb-FdNGpgSO // Play: https://go.dev/play/p/Rb-FdNGpgSO
func Nand[T any](predicates ...func(T) bool) func(T) bool { func Nand[T any](predicates ...func(T) bool) func(T) bool {
if len(predicates) < 2 { if len(predicates) < 2 {
@@ -26,11 +26,11 @@ func Nand[T any](predicates ...func(T) bool) func(T) bool {
} }
return func(value T) bool { return func(value T) bool {
for _, predicate := range predicates { for _, predicate := range predicates {
if predicate(value) { if !predicate(value) {
return false // Short-circuit on the first true predicate return true // Short-circuit on the first false predicate
} }
} }
return true // True if all predicates are false return false // False if all predicates are true
} }
} }

View File

@@ -65,7 +65,7 @@ func ExampleNand() {
// Output: // Output:
// false // false
// false // true
// true // true
} }

View File

@@ -65,7 +65,7 @@ func TestPredicatesNandPure(t *testing.T) {
) )
assert.ShouldBeFalse(isNumericAndLength5("12345")) assert.ShouldBeFalse(isNumericAndLength5("12345"))
assert.ShouldBeFalse(isNumericAndLength5("1234")) assert.ShouldBeTrue(isNumericAndLength5("1234"))
assert.ShouldBeTrue(isNumericAndLength5("abcdef")) assert.ShouldBeTrue(isNumericAndLength5("abcdef"))
} }

View File

@@ -668,7 +668,7 @@ func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V {
} }
// FindValuesBy returns a slice of values from the map that satisfy the given predicate function. // FindValuesBy returns a slice of values from the map that satisfy the given predicate function.
// Play: todo // Play: https://go.dev/play/p/bvNwNBZDm6v
func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V { func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) []V {
result := make([]V, 0) result := make([]V, 0)

View File

@@ -309,7 +309,7 @@ func IsTelnetConnected(host string, port string) bool {
} }
// BuildUrl builds a URL from the given params. // BuildUrl builds a URL from the given params.
// Play: todo // Play: https://go.dev/play/p/JLXl1hZK7l4
func BuildUrl(scheme, host, path string, query map[string][]string) (string, error) { func BuildUrl(scheme, host, path string, query map[string][]string) (string, error) {
if err := validateScheme(scheme); err != nil { if err := validateScheme(scheme); err != nil {
return "", err return "", err
@@ -365,13 +365,13 @@ func validateScheme(scheme string) error {
return nil return nil
} }
var hostRegex = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])(\.[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])*$`) var hostRegex = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]?)(\.[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]?)+$`)
var pathRegex = regexp.MustCompile(`^\/([a-zA-Z0-9%_-]+(?:\/[a-zA-Z0-9%_-]+)*)$`) var pathRegex = regexp.MustCompile(`^\/([a-zA-Z0-9%_-]+(?:\/[a-zA-Z0-9%_-]+)*)$`)
var alphaNumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]+$`) var alphaNumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
// AddQueryParams adds query parameters to the given URL. // AddQueryParams adds query parameters to the given URL.
// Play: todoå // Play: https://go.dev/play/p/JLXl1hZK7l4
func AddQueryParams(urlStr string, params map[string][]string) (string, error) { func AddQueryParams(urlStr string, params map[string][]string) (string, error) {
parsedUrl, err := url.Parse(urlStr) parsedUrl, err := url.Parse(urlStr)
if err != nil { if err != nil {

View File

@@ -196,6 +196,14 @@ func TestBuildUrl(t *testing.T) {
want: "https://www.test.com/path%20with%20spaces", want: "https://www.test.com/path%20with%20spaces",
wantErr: false, wantErr: false,
}, },
{
scheme: "https",
host: "my.api.edu.cn",
path: "/api",
query: nil,
want: "https://my.api.edu.cn/api",
wantErr: false,
},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -128,16 +128,19 @@ func Retry(retryFunc RetryFunc, opts ...Option) error {
} }
var i uint var i uint
var lastErr error
for i < config.retryTimes { for i < config.retryTimes {
err := retryFunc() lastErr = retryFunc()
if err != nil { if lastErr == nil {
return nil
}
if i < config.retryTimes-1 { // Only wait if it's not the last retry
select { select {
case <-time.After(config.backoffStrategy.CalculateInterval()): case <-time.After(config.backoffStrategy.CalculateInterval()):
case <-config.context.Done(): case <-config.context.Done():
return errors.New("retry is cancelled") return errors.New("retry is cancelled")
} }
} else {
return nil
} }
i++ i++
} }
@@ -146,7 +149,7 @@ func Retry(retryFunc RetryFunc, opts ...Option) error {
lastSlash := strings.LastIndex(funcPath, "/") lastSlash := strings.LastIndex(funcPath, "/")
funcName := funcPath[lastSlash+1:] funcName := funcPath[lastSlash+1:]
return fmt.Errorf("function %s run failed after %d times retry", funcName, i) return fmt.Errorf("function %s run failed after %d times retry, last error: %w", funcName, i, lastErr)
} }
// BackoffStrategy is an interface that defines a method for calculating backoff intervals. // BackoffStrategy is an interface that defines a method for calculating backoff intervals.

View File

@@ -118,7 +118,7 @@ func ExampleRetryTimes() {
} }
// Output: // Output:
// function retry.ExampleRetryTimes.func1 run failed after 2 times retry // function retry.ExampleRetryTimes.func1 run failed after 2 times retry, last error: error occurs
} }
func ExampleRetry() { func ExampleRetry() {

View File

@@ -15,14 +15,16 @@ func TestRetryFailed(t *testing.T) {
assert := internal.NewAssert(t, "TestRetryFailed") assert := internal.NewAssert(t, "TestRetryFailed")
var number int var number int
customError := errors.New("error occurs")
increaseNumber := func() error { increaseNumber := func() error {
number++ number++
return errors.New("error occurs") return customError
} }
err := Retry(increaseNumber, RetryWithLinearBackoff(time.Microsecond*50)) err := Retry(increaseNumber, RetryWithLinearBackoff(time.Microsecond*50))
assert.IsNotNil(err) assert.IsNotNil(err)
assert.Equal(errors.Is(err, customError), true)
assert.Equal(DefaultRetryTimes, number) assert.Equal(DefaultRetryTimes, number)
} }

View File

@@ -507,19 +507,17 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
} }
// ForEach iterates over elements of slice and invokes function for each element. // ForEach iterates over elements of slice and invokes function for each element.
// Play: https://go.dev/play/p/DrPaa4YsHRF
func ForEach[T any](slice []T, iteratee func(index int, item T)) { func ForEach[T any](slice []T, iteratee func(index int, item T)) {
for i := 0; i < len(slice); i++ { for idx, elem := range slice {
iteratee(i, slice[i]) iteratee(idx, elem)
} }
} }
// ForEachWithBreak iterates over elements of slice and invokes function for each element, // ForEachWithBreak iterates over elements of slice and invokes function for each element,
// when iteratee return false, will break the for each loop. // when function return false, will break the for each loop.
// Play: https://go.dev/play/p/qScs39f3D9W
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) { func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
for i := 0; i < len(slice); i++ { for idx, elem := range slice {
if !iteratee(i, slice[i]) { if !iteratee(idx, elem) {
break break
} }
} }
@@ -692,11 +690,12 @@ func IntSlice(slice any) []int {
// DeleteAt delete the element of slice at index. // DeleteAt delete the element of slice at index.
// Play: https://go.dev/play/p/800B1dPBYyd // Play: https://go.dev/play/p/800B1dPBYyd
func DeleteAt[T any](slice []T, index int) []T { func DeleteAt[T any](slice []T, index int) []T {
result := append([]T(nil), slice...)
if index < 0 || index >= len(slice) { if index < 0 || index >= len(slice) {
return slice[:len(slice)-1] return result[:len(slice)-1]
} }
result := append([]T(nil), slice...)
copy(result[index:], result[index+1:]) copy(result[index:], result[index+1:])
// Set the last element to zero value, clean up the memory. // Set the last element to zero value, clean up the memory.
@@ -736,7 +735,8 @@ func Drop[T any](slice []T, n int) []T {
} }
if n <= 0 { if n <= 0 {
return slice result := make([]T, 0, size)
return append(result, slice...)
} }
result := make([]T, 0, size-n) result := make([]T, 0, size-n)
@@ -754,7 +754,8 @@ func DropRight[T any](slice []T, n int) []T {
} }
if n <= 0 { if n <= 0 {
return slice result := make([]T, 0, size)
return append(result, slice...)
} }
result := make([]T, 0, size-n) result := make([]T, 0, size-n)
@@ -800,7 +801,9 @@ func InsertAt[T any](slice []T, index int, value any) []T {
size := len(slice) size := len(slice)
if index < 0 || index > size { if index < 0 || index > size {
return slice result := make([]T, size)
copy(result, slice)
return result
} }
switch v := value.(type) { switch v := value.(type) {
@@ -817,21 +820,21 @@ func InsertAt[T any](slice []T, index int, value any) []T {
copy(result[index+len(v):], slice[index:]) copy(result[index+len(v):], slice[index:])
return result return result
default: default:
return slice result := make([]T, size)
copy(result, slice)
return result
} }
} }
// UpdateAt update the slice element at index. // UpdateAt update the slice element at index.
// Play: https://go.dev/play/p/f3mh2KloWVm // Play: https://go.dev/play/p/f3mh2KloWVm
func UpdateAt[T any](slice []T, index int, value T) []T { func UpdateAt[T any](slice []T, index int, value T) []T {
if index < 0 || index >= len(slice) {
return slice
}
result := make([]T, len(slice)) result := make([]T, len(slice))
copy(result, slice) copy(result, slice)
result[index] = value if index >= 0 && index < len(slice) {
result[index] = value
}
return result return result
} }
@@ -1021,7 +1024,9 @@ func SymmetricDifference[T comparable](slices ...[]T) []T {
return []T{} return []T{}
} }
if len(slices) == 1 { if len(slices) == 1 {
return Unique(slices[0]) result := make([]T, len(slices[0]))
copy(result, slices[0])
return Unique(result)
} }
result := make([]T, 0) result := make([]T, 0)
@@ -1042,6 +1047,7 @@ func SymmetricDifference[T comparable](slices ...[]T) []T {
} }
// Reverse return slice of element order is reversed to the given slice. // Reverse return slice of element order is reversed to the given slice.
// Reverse modifies the slice in place.
// Play: https://go.dev/play/p/8uI8f1lwNrQ // Play: https://go.dev/play/p/8uI8f1lwNrQ
func Reverse[T any](slice []T) { func Reverse[T any](slice []T) {
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
@@ -1049,7 +1055,8 @@ func Reverse[T any](slice []T) {
} }
} }
// ReverseCopy return a new slice of element order is reversed to the given slice. // ReverseCopy return a new slice of element where the order is reversed to the given
// slice.
// Play: https://go.dev/play/p/c9arEaP7Cg- // Play: https://go.dev/play/p/c9arEaP7Cg-
func ReverseCopy[T any](slice []T) []T { func ReverseCopy[T any](slice []T) []T {
result := make([]T, len(slice)) result := make([]T, len(slice))
@@ -1067,7 +1074,7 @@ func Shuffle[T any](slice []T) []T {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(slice), func(i, j int) { rand.Shuffle(len(slice), func(i, j int) {
slice[i], slice[j] = slice[j], slice[i] swap(slice, i, j)
}) })
return slice return slice
@@ -1240,11 +1247,12 @@ func SortByField[T any](slice []T, field string, sortType ...string) error {
// Without creates a slice excluding all given items. // Without creates a slice excluding all given items.
// Play: https://go.dev/play/p/bwhEXEypThg // Play: https://go.dev/play/p/bwhEXEypThg
func Without[T comparable](slice []T, items ...T) []T { func Without[T comparable](slice []T, items ...T) []T {
result := make([]T, 0, len(slice))
if len(items) == 0 || len(slice) == 0 { if len(items) == 0 || len(slice) == 0 {
return slice return append(result, slice...)
} }
result := make([]T, 0, len(slice))
for _, v := range slice { for _, v := range slice {
if !Contain(items, v) { if !Contain(items, v) {
result = append(result, v) result = append(result, v)
@@ -1465,36 +1473,28 @@ func Random[T any](slice []T) (val T, idx int) {
return slice[idx], idx return slice[idx], idx
} }
// RightPadding adds padding to the right end of a slice. // RightPadding returns a copy of the slice padding the given value to the right end of a slice.
// If paddingLength is zero or less, the function returns a copy of the slice.
// Play: https://go.dev/play/p/0_2rlLEMBXL // Play: https://go.dev/play/p/0_2rlLEMBXL
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T { func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
if paddingLength == 0 { suffix := []T{}
return slice if paddingLength > 0 {
suffix = repeat([]T{paddingValue}, paddingLength)
} }
for i := 0; i < paddingLength; i++ { padded := concat(slice, suffix)
slice = append(slice, paddingValue) return padded
}
return slice
} }
// LeftPadding adds padding to the left begin of a slice. // LeftPadding returns a copy of the slice padding the given value to the left begin of a slice.
// If paddingLength is zero or less, the function returns a copy of the slice.
// Play: https://go.dev/play/p/jlQVoelLl2k // Play: https://go.dev/play/p/jlQVoelLl2k
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T { func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
if paddingLength == 0 { prefix := []T{}
return slice if paddingLength > 0 {
prefix = repeat([]T{paddingValue}, paddingLength)
} }
padded := concat(prefix, slice)
paddedSlice := make([]T, len(slice)+paddingLength) return padded
i := 0
for ; i < paddingLength; i++ {
paddedSlice[i] = paddingValue
}
for j := 0; j < len(slice); j++ {
paddedSlice[i] = slice[j]
i++
}
return paddedSlice
} }
// Frequency counts the frequency of each element in the slice. // Frequency counts the frequency of each element in the slice.

View File

@@ -125,6 +125,8 @@ func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T { func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
result := make([]T, 0) result := make([]T, 0)
var wg sync.WaitGroup var wg sync.WaitGroup
var mu sync.Mutex
workerChan := make(chan struct{}, numThreads) workerChan := make(chan struct{}, numThreads)
@@ -137,7 +139,9 @@ func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool,
defer wg.Done() defer wg.Done()
if predicate(i, v) { if predicate(i, v) {
mu.Lock()
result = append(result, v) result = append(result, v)
mu.Unlock()
} }
<-workerChan <-workerChan

View File

@@ -831,7 +831,7 @@ func ExampleUniqueByComparator() {
}) })
caseInsensitiveStrings := UniqueByComparator([]string{"apple", "banana", "Apple", "cherry", "Banana", "date"}, func(item string, other string) bool { caseInsensitiveStrings := UniqueByComparator([]string{"apple", "banana", "Apple", "cherry", "Banana", "date"}, func(item string, other string) bool {
return strings.ToLower(item) == strings.ToLower(other) return strings.EqualFold(item, other)
}) })
fmt.Println(uniqueNums) fmt.Println(uniqueNums)

View File

@@ -2,6 +2,7 @@ package slice
import ( import (
"fmt" "fmt"
"math/bits"
"reflect" "reflect"
"golang.org/x/exp/constraints" "golang.org/x/exp/constraints"
@@ -96,3 +97,71 @@ func partitionAnySlice[T any](slice []T, lowIndex, highIndex int, less func(a, b
func swap[T any](slice []T, i, j int) { func swap[T any](slice []T, i, j int) {
slice[i], slice[j] = slice[j], slice[i] slice[i], slice[j] = slice[j], slice[i]
} }
// `repeat` returns a new slice that repeats the provided slice the given number of
// times. The result has length and capacity (len(x) * count). The result is never nil.
// Repeat panics if count is negative or if the result of (len(x) * count) overflows.
//
// repeat has been provided in the standard lib within the package `slices` under the
// name Repeat since GO version 1.21 onwards. As lancet commits to compatibility with GO
// 1.18 onwards, we implement the functionality as an internal function.
func repeat[S ~[]E, E any](x S, count int) S {
if count < 0 {
panic("count cannot be negative")
}
const maxInt = ^uint(0) >> 1
hi, lo := bits.Mul(uint(len(x)), uint(count))
if hi > 0 || lo > maxInt {
panic("the result of (len(x) * count) overflows")
}
newslice := make(S, int(lo)) // lo = len(x) * count
n := copy(newslice, x)
for n < len(newslice) {
n += copy(newslice[n:], newslice[:n])
}
return newslice
}
// concat returns a new slice concatenating the passed in slices.
//
// concat has been provided in the standard lib within the package `slices` under the
// name Concat since GO version 1.21 onwards. As lancet commits to compatibility with GO
// 1.18 onwards, we implement the functionality as an internal function.
func concat[S ~[]E, E any](slices ...S) S {
size := 0
for _, s := range slices {
size += len(s)
if size < 0 {
panic("len out of range")
}
}
// Use Grow, not make, to round up to the size class:
// the extra space is otherwise unused and helps
// callers that append a few elements to the result.
newslice := grow[S](nil, size)
for _, s := range slices {
newslice = append(newslice, s...)
}
return newslice
}
// grow increases the slice's capacity, if necessary, to guarantee space for
// another n elements. After grow(n), at least n elements can be appended
// to the slice without another allocation. If n is negative or too large to
// allocate the memory, grow panics.
//
// grow has been provided in the standard lib within the package `slices` under the
// name Grow since GO version 1.21 onwards. As lancet commits to compatibility with GO
// 1.18 onwards, we implement the functionality as an internal function.
func grow[S ~[]E, E any](s S, n int) S {
if n < 0 {
panic("cannot be negative")
}
if n -= cap(s) - len(s); n > 0 {
// This expression allocates only once.
s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
}
return s
}

View File

@@ -1008,7 +1008,7 @@ func TestUniqueByComparator(t *testing.T) {
t.Run("case-insensitive string comparison", func(t *testing.T) { t.Run("case-insensitive string comparison", func(t *testing.T) {
stringSlice := []string{"apple", "banana", "Apple", "cherry", "Banana", "date"} stringSlice := []string{"apple", "banana", "Apple", "cherry", "Banana", "date"}
caseInsensitiveComparator := func(item, other string) bool { caseInsensitiveComparator := func(item, other string) bool {
return strings.ToLower(item) == strings.ToLower(other) return strings.EqualFold(item, other)
} }
result := UniqueByComparator(stringSlice, caseInsensitiveComparator) result := UniqueByComparator(stringSlice, caseInsensitiveComparator)
@@ -1756,6 +1756,20 @@ func TestRightPaddingAndLeftPadding(t *testing.T) {
padded := LeftPadding(RightPadding(nums, 0, 3), 0, 3) padded := LeftPadding(RightPadding(nums, 0, 3), 0, 3)
assert.Equal([]int{0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0}, padded) assert.Equal([]int{0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0}, padded)
// Test with negative padding length
paddedNegative := LeftPadding(RightPadding(nums, 0, -3), 0, -3)
assert.Equal([]int{1, 2, 3, 4, 5}, paddedNegative)
// Test with empty slice
empty := []int{}
paddedEmpty := LeftPadding(RightPadding(empty, 0, 3), 0, 3)
assert.Equal([]int{0, 0, 0, 0, 0, 0}, paddedEmpty)
// Test with nil
nilSlice := []int(nil)
paddedNil := LeftPadding(RightPadding(nilSlice, 0, 3), 0, 3)
assert.Equal([]int{0, 0, 0, 0, 0, 0}, paddedNil)
} }
func TestUniqueByConcurrent(t *testing.T) { func TestUniqueByConcurrent(t *testing.T) {

View File

@@ -19,16 +19,17 @@ import (
) )
var ( var (
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`) alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`) letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
alphaNumericMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z0-9-]+$`) alphaNumericMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z0-9-]+$`)
numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`) numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`)
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`) intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`) urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`) dnsMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`) // emailMatcher *regexp.Regexp = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+(-+.\w+)*@\w+(-.\w+)*.\w+(-.\w+)*`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`) chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^(\d{17})([0-9]|X|x)$`) chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`([1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])|([1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}[0-9Xx])`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]") chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8}`) chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8}`)
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`) creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
@@ -39,10 +40,26 @@ var (
visaMatcher *regexp.Regexp = regexp.MustCompile(`^4[0-9]{12}(?:[0-9]{3})?$`) visaMatcher *regexp.Regexp = regexp.MustCompile(`^4[0-9]{12}(?:[0-9]{3})?$`)
masterCardMatcher *regexp.Regexp = regexp.MustCompile(`^5[1-5][0-9]{14}$`) masterCardMatcher *regexp.Regexp = regexp.MustCompile(`^5[1-5][0-9]{14}$`)
americanExpressMatcher *regexp.Regexp = regexp.MustCompile(`^3[47][0-9]{13}$`) americanExpressMatcher *regexp.Regexp = regexp.MustCompile(`^3[47][0-9]{13}$`)
unionPay *regexp.Regexp = regexp.MustCompile("^62[0-5]\\d{13,16}$") unionPayMatcher *regexp.Regexp = regexp.MustCompile(`^62[0-5]\\d{13,16}$`)
chinaUnionPay *regexp.Regexp = regexp.MustCompile(`^62[0-9]{14,17}$`) chinaUnionPayMatcher *regexp.Regexp = regexp.MustCompile(`^62[0-9]{14,17}$`)
) )
var passportMatcher = map[string]*regexp.Regexp{
"CN": regexp.MustCompile(`^P\d{9}$`),
"US": regexp.MustCompile(`^\d{9}$`),
"GB": regexp.MustCompile(`^[A-Z0-9]{9}$`),
"RU": regexp.MustCompile(`^[A-Z]{2}\d{7}$`),
"DE": regexp.MustCompile(`^\d{9}$`),
"FR": regexp.MustCompile(`^[A-Z]{2}\d{7}$`),
"JP": regexp.MustCompile(`^\d{8}$`),
"IT": regexp.MustCompile(`^\d{8}$`),
"AU": regexp.MustCompile(`^[A-Z]{1}\d{8}$`),
"BR": regexp.MustCompile(`^\d{9}$`),
"IN": regexp.MustCompile(`^[A-Z]{1,2}\d{7}$`),
"HK": regexp.MustCompile(`^M\d{8}$`),
"MO": regexp.MustCompile(`^[A-Z]\d{8}$`),
}
var ( var (
// Identity card formula // Identity card formula
factor = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2} factor = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
@@ -183,7 +200,7 @@ func IsJSON(str string) bool {
} }
// IsAlphaNumeric check if the string is alphanumeric. // IsAlphaNumeric check if the string is alphanumeric.
// Play: todo // Play: https://go.dev/play/p/RHeESLrLg9c
func IsAlphaNumeric(s string) bool { func IsAlphaNumeric(s string) bool {
return alphaNumericMatcher.MatchString(s) return alphaNumericMatcher.MatchString(s)
} }
@@ -258,21 +275,45 @@ func IsPort(str string) bool {
// IsUrl check if the string is url. // IsUrl check if the string is url.
// Play: https://go.dev/play/p/pbJGa7F98Ka // Play: https://go.dev/play/p/pbJGa7F98Ka
func IsUrl(str string) bool { func IsUrl(str string) bool {
if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") { if str == "" {
return false
}
u, err := url.Parse(str)
if err != nil {
return false
}
if strings.HasPrefix(u.Host, ".") {
return false
}
if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
return false return false
} }
return urlMatcher.MatchString(str) u, err := url.Parse(str)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
allowedSchemes := map[string]struct{}{
"http": {},
"https": {},
"ftp": {},
"ws": {},
"wss": {},
"file": {},
"mailto": {},
"data": {},
}
if _, ok := allowedSchemes[u.Scheme]; !ok {
return false
}
if u.Scheme == "file" || u.Scheme == "mailto" || u.Scheme == "data" {
return true
}
host := u.Hostname()
if !strings.Contains(host, ".") || strings.HasSuffix(host, ".") {
return false
}
// domainRegexp := regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-\.]*[a-zA-Z0-9]$`)
if !dnsMatcher.MatchString(host) {
return false
}
return true
} }
// IsDns check if the string is dns. // IsDns check if the string is dns.
@@ -286,8 +327,6 @@ func IsDns(dns string) bool {
func IsEmail(email string) bool { func IsEmail(email string) bool {
_, err := mail.ParseAddress(email) _, err := mail.ParseAddress(email)
return err == nil return err == nil
// return emailMatcher.MatchString(email)
} }
// IsChineseMobile check if the string is chinese mobile number. // IsChineseMobile check if the string is chinese mobile number.
@@ -460,12 +499,13 @@ func IsZeroValue(value any) bool {
func IsGBK(data []byte) bool { func IsGBK(data []byte) bool {
i := 0 i := 0
for i < len(data) { for i < len(data) {
if data[i] <= 0xff { if data[i] < 0x81 {
i++ i++
continue continue
} else { } else {
if data[i] >= 0x81 && if data[i] >= 0x81 &&
data[i] <= 0xfe && data[i] <= 0xfe &&
i+1 < len(data) &&
data[i+1] >= 0x40 && data[i+1] >= 0x40 &&
data[i+1] <= 0xfe && data[i+1] <= 0xfe &&
data[i+1] != 0xf7 { data[i+1] != 0xf7 {
@@ -562,11 +602,22 @@ func IsAmericanExpress(v string) bool {
// IsUnionPay check if a give string is a valid union pay nubmer or not. // IsUnionPay check if a give string is a valid union pay nubmer or not.
// Play: https://go.dev/play/p/CUHPEwEITDf // Play: https://go.dev/play/p/CUHPEwEITDf
func IsUnionPay(v string) bool { func IsUnionPay(v string) bool {
return unionPay.MatchString(v) return unionPayMatcher.MatchString(v)
} }
// IsChinaUnionPay check if a give string is a valid china union pay nubmer or not. // IsChinaUnionPay check if a give string is a valid china union pay nubmer or not.
// Play: https://go.dev/play/p/yafpdxLiymu // Play: https://go.dev/play/p/yafpdxLiymu
func IsChinaUnionPay(v string) bool { func IsChinaUnionPay(v string) bool {
return chinaUnionPay.MatchString(v) return chinaUnionPayMatcher.MatchString(v)
}
// IsPassport checks if the passport number is valid for a given country.
// country is a two-letter country code (ISO 3166-1 alpha-2).
// Play: todo
func IsPassport(passport, country string) bool {
if matcher, ok := passportMatcher[country]; ok {
return matcher.MatchString(passport)
}
return false
} }

View File

@@ -214,7 +214,7 @@ func ExampleIsUrl() {
fmt.Println(result3) fmt.Println(result3)
// Output: // Output:
// true // false
// true // true
// false // false
} }
@@ -683,3 +683,21 @@ func ExampleIsAlphaNumeric() {
// true // true
// false // false
} }
func ExampleIsPassport() {
result1 := IsPassport("P123456789", "CN")
result2 := IsPassport("123456789", "US")
result3 := IsPassport("AB1234567", "RU")
result4 := IsPassport("123456789", "CN")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}

View File

@@ -437,10 +437,32 @@ func TestIsUrl(t *testing.T) {
assert := internal.NewAssert(t, "TestIsUrl") assert := internal.NewAssert(t, "TestIsUrl")
assert.Equal(true, IsUrl("http://abc.com")) tests := []struct {
assert.Equal(true, IsUrl("abc.com")) input string
assert.Equal(true, IsUrl("a.b.com")) expected bool
assert.Equal(false, IsUrl("abc")) }{
{"http://abc.com", true},
{"https://abc.com", true},
{"ftp://abc.com", true},
{"http://abc.com/path?query=123", true},
{"https://abc.com/path/to/resource", true},
{"ws://abc.com", true},
{"wss://abc.com", true},
{"mailto://abc.com", true},
{"file://path/to/file", true},
{"data://text/plain;base64,SGVsbG8sIFdvcmxkIQ==", true},
{"http://abc.com/path/to/resource?query=123#fragment", true},
{"abc", false},
{"http://", false},
{"http://abc", false},
{"http://abc:8080", false},
{"http://abc:99999999", false},
}
for _, tt := range tests {
assert.Equal(tt.expected, IsUrl(tt.input))
}
} }
func TestIsDns(t *testing.T) { func TestIsDns(t *testing.T) {
@@ -477,12 +499,24 @@ func TestIsEmail(t *testing.T) {
func TestContainChinese(t *testing.T) { func TestContainChinese(t *testing.T) {
t.Parallel() t.Parallel()
assert := internal.NewAssert(t, "TestContainChinese") assert := internal.NewAssert(t, "TestContainChinese")
assert.Equal(true, ContainChinese("你好")) tests := []struct {
assert.Equal(true, ContainChinese("你好hello")) input string
assert.Equal(false, ContainChinese("hello")) expected bool
}{
{"你好", true},
{"hello", false},
{"你好hello", true},
{"hello你好", true},
{"", false},
{"123", false},
{"!@#$%^&*()", false},
}
for _, tt := range tests {
assert.Equal(tt.expected, ContainChinese(tt.input))
}
} }
func TestIsChineseMobile(t *testing.T) { func TestIsChineseMobile(t *testing.T) {
@@ -490,8 +524,20 @@ func TestIsChineseMobile(t *testing.T) {
assert := internal.NewAssert(t, "TestIsChineseMobile") assert := internal.NewAssert(t, "TestIsChineseMobile")
assert.Equal(true, IsChineseMobile("13263527980")) tests := []struct {
assert.Equal(false, IsChineseMobile("434324324")) input string
expected bool
}{
{"13263527980", true},
{"1326352798", false},
{"132635279801", false},
{"1326352798a", false},
{"1326352798@", false},
}
for _, tt := range tests {
assert.Equal(tt.expected, IsChineseMobile(tt.input))
}
} }
func TestIsChinesePhone(t *testing.T) { func TestIsChinesePhone(t *testing.T) {
@@ -924,3 +970,33 @@ func TestIsAlphaNumeric(t *testing.T) {
assert.Equal(tt.expected, IsAlphaNumeric(tt.input)) assert.Equal(tt.expected, IsAlphaNumeric(tt.input))
} }
} }
func TestIsPassport(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsPassport")
tests := []struct {
passport string
countryCode string
expected bool
}{
{"P123456789", "CN", true},
{"123456789", "US", true},
{"A12345678", "GB", true},
{"AB1234567", "FR", true},
{"12345678", "JP", true},
{"M12345678", "HK", true},
{"A12345678", "MO", true},
{"A1234567", "IN", true},
{"12345678", "IT", true},
{"A12345678", "AU", true},
{"123456789", "BR", true},
{"AB1234567", "RU", true},
{"123456789", "CN", false},
}
for _, tt := range tests {
assert.Equal(tt.expected, IsPassport(tt.passport, tt.countryCode))
}
}