mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
11 Commits
9e813d236b
...
v2.3.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdefbde9f5 | ||
|
|
1e57a743af | ||
|
|
7d4184a365 | ||
|
|
1b73483945 | ||
|
|
622aacaf44 | ||
|
|
e78ac65605 | ||
|
|
03f0d4d905 | ||
|
|
b2ae71c983 | ||
|
|
093f4a2286 | ||
|
|
f7ada6093c | ||
|
|
47e82aad39 |
49
README.md
49
README.md
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -214,6 +214,30 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
|||||||
- **<big>Tee</big>** : split one chanel into two channels, until cancel the context.
|
- **<big>Tee</big>** : split one chanel into two channels, until cancel the context.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Tee)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Tee)]
|
||||||
[[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.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#NewKeyedLocker)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator... <a href="#index">index</a> </h3>
|
<h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator... <a href="#index">index</a> </h3>
|
||||||
|
|
||||||
@@ -331,7 +355,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
- **<big>ToRawUrlBase64</big>** : converts a value to a string encoded in raw url Base64.
|
- **<big>ToRawUrlBase64</big>** : converts a value to a string encoded in raw url Base64.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawUrlBase64)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToRawUrlBase64)]
|
||||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||||
- **<big>ToBigInt</big>** : converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int.
|
- **<big>ToBigInt</big>** : converts an integer of any supported type (int, int64, uint64, etc.) to \*big.Int.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToBigInt)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToBigInt)]
|
||||||
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
||||||
|
|
||||||
@@ -694,7 +718,6 @@ import optional "github.com/duke-git/lancet/v2/datastructure/optional"
|
|||||||
- **<big>Optional</big>** : Optional container.
|
- **<big>Optional</big>** : Optional container.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datastructure/optional.md)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datastructure/optional.md)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="eventbus"> 9. EventBus is an event bus used for handling events within an application. <a href="#index">Index</a></h3>
|
<h3 id="eventbus"> 9. EventBus is an event bus used for handling events within an application. <a href="#index">Index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -778,6 +801,9 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
- **<big>RemoveFile</big>** : remove file, param should be file path.
|
- **<big>RemoveFile</big>** : remove file, param should be file path.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#RemoveFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#RemoveFile)]
|
||||||
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
||||||
|
- **<big>RemoveDir</big>** : delete directory.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#RemoveDir)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<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)]
|
||||||
@@ -926,7 +952,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</a></h3>
|
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1097,7 +1122,9 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
- **<big>GetOrDefault</big>** : returns the value of the given key or a default value if the key is not present.
|
- **<big>GetOrDefault</big>** : returns the value of the given key or a default value if the key is not present.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#GetOrDefault)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#GetOrDefault)]
|
||||||
[[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.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#FindValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</a></h3>
|
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1282,6 +1309,12 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>IsTelnetConnected</big>** : checks if can if can telnet the specified host or not.
|
- **<big>IsTelnetConnected</big>** : checks if can if can telnet the specified host or not.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#IsTelnetConnected)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#IsTelnetConnected)]
|
||||||
[[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.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#BuildUrl)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. <a href="#index">index</a></h3>
|
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1408,7 +1441,6 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
||||||
[[play](https://go.dev/play/p/xp1avQmn16X)]
|
[[play](https://go.dev/play/p/xp1avQmn16X)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -2012,7 +2044,6 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#GetProcessInfo)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#GetProcessInfo)]
|
||||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -2195,6 +2226,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsNumberStr</big>** : check if the string can convert to a number.
|
- **<big>IsNumberStr</big>** : check if the string can convert to a number.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsNumberStr)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsNumberStr)]
|
||||||
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
||||||
|
- **<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)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<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)]
|
||||||
@@ -2324,6 +2358,7 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
#### [Contribution Guide](./CONTRIBUTION.md)
|
#### [Contribution Guide](./CONTRIBUTION.md)
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
Thank you to all the people who contributed to lancet!
|
Thank you to all the people who contributed to lancet!
|
||||||
|
|
||||||
<a href="https://github.com/duke-git/lancet/graphs/contributors">
|
<a href="https://github.com/duke-git/lancet/graphs/contributors">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -101,7 +101,6 @@ func main() {
|
|||||||
- [Validator](#user-content-validator)
|
- [Validator](#user-content-validator)
|
||||||
- [Xerror](#user-content-xerror)
|
- [Xerror](#user-content-xerror)
|
||||||
|
|
||||||
|
|
||||||
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -214,6 +213,30 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
|||||||
- **<big>Tee</big>** : 将一个 channel 分成两个 channel,直到取消上下文。
|
- **<big>Tee</big>** : 将一个 channel 分成两个 channel,直到取消上下文。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Tee)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Tee)]
|
||||||
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
||||||
|
- **<big>NewKeyedLocker</big>** : NewKeyedLocker 创建一个新的 KeyedLocker,并为锁的过期设置指定的 TTL。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewKeyedLocker)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Do</big>** :为指定的键获取锁并执行提供的函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Do)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>NewRWKeyedLocker</big>** :RWKeyedLocker 是一个简单的键值读写锁实现,允许非阻塞的锁获取。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewRWKeyedLocker)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>RLock</big>** : 为指定的键获取读锁并执行提供的函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#RLock)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Lock</big>** : 为指定的键获取锁并执行提供的函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Lock)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>NewTryKeyedLocker</big>** : 创建一个 TryKeyedLocker 实例,TryKeyedLocker 是 KeyedLocker 的非阻塞版本。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#NewTryKeyedLocker)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>TryLock</big>** : TryLock 尝试获取指定键的锁。如果锁成功获取,则返回 true,否则返回 false。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#TryLock)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Unlock</big>** : 释放指定键的锁。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/concurrency.md#Unlock)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="condition"> 4. condition 包含一些用于条件判断的函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="condition"> 4. condition 包含一些用于条件判断的函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -331,7 +354,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
- **<big>ToRawUrlBase64</big>** : 将值转换为 RawUrlBase64 编码的字符串。
|
- **<big>ToRawUrlBase64</big>** : 将值转换为 RawUrlBase64 编码的字符串。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawUrlBase64)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToRawUrlBase64)]
|
||||||
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
[[play](https://go.dev/play/p/HwdDPFcza1O)]
|
||||||
- **<big>ToBigInt</big>** : 将整数转为*big.Int。
|
- **<big>ToBigInt</big>** : 将整数转为\*big.Int。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToBigInt)]
|
||||||
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
[[play](https://go.dev/play/p/X3itkCxwB_x)]
|
||||||
|
|
||||||
@@ -658,7 +681,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#MaxMin)]
|
||||||
[[play](https://go.dev/play/p/rbW51cDtM_2)]
|
[[play](https://go.dev/play/p/rbW51cDtM_2)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -777,6 +799,9 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
- **<big>RemoveFile</big>** : 删除文件。
|
- **<big>RemoveFile</big>** : 删除文件。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#RemoveFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#RemoveFile)]
|
||||||
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
||||||
|
- **<big>RemoveDir</big>** : 删除目录,支持传入删除前的回调函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#RemoveDir)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<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)]
|
||||||
@@ -832,7 +857,6 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
|
||||||
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="formatter"> 11. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
<h3 id="formatter"> 11. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -926,8 +950,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="maputil"> 13. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="maputil"> 13. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1098,6 +1120,9 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
- **<big>GetOrDefault</big>** : 返回给定键的值,如果键不存在,则返回默认值。
|
- **<big>GetOrDefault</big>** : 返回给定键的值,如果键不存在,则返回默认值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#GetOrDefault)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#GetOrDefault)]
|
||||||
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
||||||
|
- **<big>FindValuesBy</big>** : 返回一个切片,包含满足给定谓词判断函数的 map 中的值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#FindValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1282,6 +1307,12 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>IsTelnetConnected</big>** : 检查能否 telnet 到主机。
|
- **<big>IsTelnetConnected</big>** : 检查能否 telnet 到主机。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#IsTelnetConnected)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#IsTelnetConnected)]
|
||||||
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
|
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
|
||||||
|
- **<big>BuildUrl</big>** : 创建 url 字符串。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#BuildUrl)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddQueryParams</big>** : 向 url 添加查询参数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#AddQueryParams)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1405,8 +1436,6 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
||||||
[[play](https://go.dev/play/p/xp1avQmn16X)]
|
[[play](https://go.dev/play/p/xp1avQmn16X)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="slice"> 19. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
<h3 id="slice"> 19. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1964,7 +1993,6 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#FindAllOccurrences)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#FindAllOccurrences)]
|
||||||
[[play](https://go.dev/play/p/uvyA6azGLB1)]
|
[[play](https://go.dev/play/p/uvyA6azGLB1)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="system"> 23. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="system"> 23. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -2013,8 +2041,6 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#GetProcessInfo)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#GetProcessInfo)]
|
||||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="tuple"> 24. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
<h3 id="tuple"> 24. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -2197,6 +2223,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。
|
- **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsNumberStr)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsNumberStr)]
|
||||||
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
||||||
|
- **<big>IsAlphaNumeric</big>** : 验证字符串是字母或数字。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsAlphaNumeric)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<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)]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package concurrency
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -199,3 +200,159 @@ func ExampleChannel_Bridge() {
|
|||||||
// true
|
// true
|
||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleKeyedLocker_Do() {
|
||||||
|
locker := NewKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
task := func() {
|
||||||
|
fmt.Println("Executing task...")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("Task completed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx2, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRWKeyedLocker_Lock() {
|
||||||
|
locker := NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.Lock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRWKeyedLocker_RLock() {
|
||||||
|
locker := NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.RLock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleTryKeyedLocker() {
|
||||||
|
locker := NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleTryKeyedLocker_TryLock() {
|
||||||
|
locker := NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
locker.Unlock(key)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
locker.Unlock(key)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the goroutine to finish
|
||||||
|
<-done
|
||||||
|
|
||||||
|
fmt.Println("Retrying...")
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lock failed
|
||||||
|
// Retrying...
|
||||||
|
// Lock acquired
|
||||||
|
// Lock released
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
-----BEGIN rsa private key-----
|
-----BEGIN rsa private key-----
|
||||||
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
|
||||||
-----END rsa private key-----
|
-----END rsa private key-----
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
-----BEGIN rsa public key-----
|
-----BEGIN rsa public key-----
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwUdYQvqsym2r86Xlcu8C
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw6Q11wDtWHZiyQbv+Xzn
|
||||||
zK6MAjtZH3aW/BsfZ852dra1nYGqUoJMe31eiurN9BK/OXmo7D3zm3OCCl/uGUCi
|
tJbEELkPQ3oVSVCVjTx+ls5I+yR6oq8LxyoUE6SHcBlludkzs02B0rDkkfj6vl0i
|
||||||
NgWKYAfaW2o4rFE7tHwHf5E4/bLmp2c6+xwP5bSo6r0pXonszPpMK4sTHNxgaXLh
|
PCzr3HP1XT1WwFiQJnXKtNNNiLvvewB/aynj/UIBCZZvMTYwK6nc76i4JWcajaiU
|
||||||
HYdx1dKXWt5SvHXo012fWsXTC7MQrpTeQIOZViC3ldQpXO026nKzwzgr7WW9kZak
|
I4u84Fp7gOn0IgXMhvrwtGHk7HK1Zjr0afUJVbodc6pMZfe0QWpnDq7zaeYdkPwz
|
||||||
HYPz0IdwQGkl6/EY3LpnP3ADsop9HWZmTIcZUfaztdwnC9JS4zJg1gGMioQXgavl
|
8klWAatLDZTeR5dYli2NiWOBepO1538ZvEK3S/QP2nWJzPJy2PbEHfDaFgr055w/
|
||||||
POVEDmXk8Oi+1ORB6CphlovSeuT9IxIoSlv77ARazKZcTfnxzXgpPT2wBdiGiTvq
|
wu0MzAQgkXGV8PubhYboJuQAkuXc63IPpmWVL/93WeCNRiL5fvNzUHsbPtT48A9N
|
||||||
2/vON1IvjDPd4MkBYEx3k5tbdL//HjzkKlg/zElELvrXEQFpdvzCdrqrTDQ56ej1
|
nnUn4QVuVGeXIxJ1skAFsoh7i+h+mK/p5rzjPtw56nE20gYXhxf7FzbHYtHn0ego
|
||||||
A5AH1q6eIJULh5hhq5jLIxkSYiiCrXYlTSPX7D9t7PLHj5AVv2PkHhuU1pwv7HnL
|
BddUzlOY0yzvCgI5Yy1RdkNe/5vU1bpLsdU/WItjR2h6EfqLosQ4iKowPBYQXJOI
|
||||||
sPfTwxYcxjygLP8lJPPE+y8UJLFCOUKkPr9dGLqA8G6ZvWhYHTyiwVEENwb+RdV2
|
NbpkvIhkhCVbPpMvmhfi/lATiKdoXgtvuB04wth011c5W/yXA+A3Ob73Sr2+zyxF
|
||||||
lakg7YNgRfEymvY3HqiiZiH8T7eOc1tt/eF3gDbG2jjlD83cxYetYFNgtSk/+0gy
|
870tOp3rNTWsYLvCOjf+JdjgM3AzNuFxE4NdMLvXDf7CIXSb3X9rj3qM769Lz6XX
|
||||||
dBQKRR+w8PUTdLb1ZZhzk/7yZCrrsh043967ECjNI5hyvSYdR+sj3W9i39Jj/4JS
|
bRBVbO0HxGyqLTPPmSWV61jQuUTWNGnxkovoYLrpgyumIjjIcl0aY1hogmQeA6ZN
|
||||||
X05C9FKEAehvubw9V/AMXcMCAwEAAQ==
|
gJxaUw9r/p8vnThL5UXKlbcCAwEAAQ==
|
||||||
-----END rsa public key-----
|
-----END rsa public key-----
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
## 源码:
|
## 源码:
|
||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go](https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -35,6 +36,17 @@ import (
|
|||||||
- [Take](#Take)
|
- [Take](#Take)
|
||||||
- [Tee](#Tee)
|
- [Tee](#Tee)
|
||||||
|
|
||||||
|
### KeyedLocker
|
||||||
|
|
||||||
|
- [NewKeyedLocker](#NewKeyedLocker)
|
||||||
|
- [KeyedLocker_Do](#Do)
|
||||||
|
- [NewRWKeyedLocker](#NewRWKeyedLocker)
|
||||||
|
- [RLock](#RLock)
|
||||||
|
- [Lock](#Lock)
|
||||||
|
- [NewTryKeyedLocker](#NewTryKeyedLocker)
|
||||||
|
- [TryLock](#TryLock)
|
||||||
|
- [Unlock](#Unlock)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
@@ -452,3 +464,389 @@ func main() {
|
|||||||
// 1
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### KeyedLocker
|
||||||
|
|
||||||
|
### <span id="NewKeyedLocker">NewKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>NewKeyedLocker创建一个新的KeyedLocker,并为锁的过期设置指定的 TTL。KeyedLocker 是一个简单的键值锁实现,允许非阻塞的锁获取。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
task := func() {
|
||||||
|
fmt.Println("Executing task...")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("Task completed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx2, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Do">Do</span>
|
||||||
|
|
||||||
|
<p>为指定的键获取锁并执行提供的函数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
task := func() {
|
||||||
|
fmt.Println("Executing task...")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("Task completed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx2, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NewRWKeyedLocker">NewRWKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>NewRWKeyedLocker创建一个新的RWKeyedLocker,并为锁的过期设置指定的 TTL。RWKeyedLocker 是一个简单的键值读写锁实现,允许非阻塞的锁获取。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.Lock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RLock">RLock</span>
|
||||||
|
|
||||||
|
<p>RLock为指定的键获取读锁并执行提供的函数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.RLock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Lock">Lock</span>
|
||||||
|
|
||||||
|
<p>Lock为指定的键获取锁并执行提供的函数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.Lock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NewTryKeyedLocker">NewTryKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>创建一个TryKeyedLocker实例,TryKeyedLocker是KeyedLocker的非阻塞版本。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K]
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TryLock">TryLock</span>
|
||||||
|
|
||||||
|
<p>TryLock尝试获取指定键的锁。如果锁成功获取,则返回true,否则返回false。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (l *TryKeyedLocker[K]) TryLock(key K) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Unlock">Unlock</span>
|
||||||
|
|
||||||
|
<p>释放指定键的锁。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (l *TryKeyedLocker[K]) Unlock(key K)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1092,7 +1092,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### 4. PriorityQueue
|
### 4. PriorityQueue
|
||||||
切片实现的额优先级队列。
|
切片实现的优先级队列。
|
||||||
|
|
||||||
### <span id="NewPriorityQueue">NewPriorityQueue</span>
|
### <span id="NewPriorityQueue">NewPriorityQueue</span>
|
||||||
<p>返回一个具有特定容量的PriorityQueue指针,参数 `comarator` 用于比较队列中T类型的值。</p>
|
<p>返回一个具有特定容量的PriorityQueue指针,参数 `comarator` 用于比较队列中T类型的值。</p>
|
||||||
|
|||||||
@@ -466,14 +466,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="T运行cRound">T运行cRound</span>
|
### <span id="TruncRound">TruncRound</span>
|
||||||
|
|
||||||
<p>截短n位小数(不进行四舍五入)</p>
|
<p>截短n位小数(不进行四舍五入)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func T运行cRound[T constraints.Float | constraints.Integer](x T, n int) T
|
func TruncRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
|
||||||
@@ -487,9 +487,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
result1 := mathutil.T运行cRound(0.124, 2)
|
result1 := mathutil.TruncRound(0.124, 2)
|
||||||
result2 := mathutil.T运行cRound(0.125, 2)
|
result2 := mathutil.TruncRound(0.125, 2)
|
||||||
result3 := mathutil.T运行cRound(0.125, 3)
|
result3 := mathutil.TruncRound(0.125, 3)
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import (
|
|||||||
- [UploadFile](#UploadFile)
|
- [UploadFile](#UploadFile)
|
||||||
- [IsPingConnected](#IsPingConnected)
|
- [IsPingConnected](#IsPingConnected)
|
||||||
- [IsTelnetConnected](#IsTelnetConnected)
|
- [IsTelnetConnected](#IsTelnetConnected)
|
||||||
- [IsTelnetConnected](#IsTelnetConnected)
|
|
||||||
- [BuildUrl](#BuildUrl)
|
- [BuildUrl](#BuildUrl)
|
||||||
- [AddQueryParams](#AddQueryParams)
|
- [AddQueryParams](#AddQueryParams)
|
||||||
|
|
||||||
|
|||||||
@@ -824,6 +824,43 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsAlphaNumeric">IsAlphaNumeric</span>
|
||||||
|
|
||||||
|
<p>验证字符串是字母或数字。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsAlphaNumeric(s string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsAlphaNumeric("ABC")
|
||||||
|
result2 := validator.IsAlphaNumeric("123")
|
||||||
|
result3 := validator.IsAlphaNumeric("abc123")
|
||||||
|
result4 := validator.IsAlphaNumeric("abc123@#$")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsJSON">IsJSON</span>
|
### <span id="IsJSON">IsJSON</span>
|
||||||
|
|
||||||
<p>验证字符串是否是有效json。</p>
|
<p>验证字符串是否是有效json。</p>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Concurrency
|
# Concurrency
|
||||||
|
|
||||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -6,10 +7,12 @@ Package concurrency contain some functions to support concurrent programming. eg
|
|||||||
## Source:
|
## Source:
|
||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go](https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
"github.com/duke-git/lancet/v2/concurrency"
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
@@ -19,7 +22,9 @@ import (
|
|||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
|
|
||||||
### Channel
|
### Channel
|
||||||
|
|
||||||
- [NewChannel](#NewChannel)
|
- [NewChannel](#NewChannel)
|
||||||
- [Bridge](#Bridge)
|
- [Bridge](#Bridge)
|
||||||
- [FanIn](#FanIn)
|
- [FanIn](#FanIn)
|
||||||
@@ -31,12 +36,25 @@ import (
|
|||||||
- [Take](#Take)
|
- [Take](#Take)
|
||||||
- [Tee](#Tee)
|
- [Tee](#Tee)
|
||||||
|
|
||||||
|
### KeyedLocker
|
||||||
|
|
||||||
|
- [NewKeyedLocker](#NewKeyedLocker)
|
||||||
|
- [Do](#Do)
|
||||||
|
- [NewRWKeyedLocker](#NewRWKeyedLocker)
|
||||||
|
- [RLock](#RLock)
|
||||||
|
- [Lock](#Lock)
|
||||||
|
- [NewTryKeyedLocker](#NewTryKeyedLocker)
|
||||||
|
- [TryLock](#TryLock)
|
||||||
|
- [Unlock](#Unlock)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
## Channel
|
## Channel
|
||||||
|
|
||||||
### <span id="NewChannel">NewChannel</span>
|
### <span id="NewChannel">NewChannel</span>
|
||||||
|
|
||||||
<p>Create a Channel pointer instance.</p>
|
<p>Create a Channel pointer instance.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -45,6 +63,7 @@ import (
|
|||||||
type Channel[T any] struct
|
type Channel[T any] struct
|
||||||
func NewChannel[T any]() *Channel[T]
|
func NewChannel[T any]() *Channel[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -69,6 +88,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
|
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -121,6 +141,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/2VYFMexEvTm)</span></b>
|
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/2VYFMexEvTm)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -160,6 +181,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -199,6 +221,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -237,6 +260,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -279,6 +303,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -322,6 +347,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -360,6 +386,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -406,6 +433,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -438,3 +466,389 @@ func main() {
|
|||||||
// 1
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### KeyedLocker
|
||||||
|
|
||||||
|
### <span id="NewKeyedLocker">NewKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>KeyedLocker is a simple implementation of a keyed locker that allows for non-blocking lock acquisition.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
task := func() {
|
||||||
|
fmt.Println("Executing task...")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("Task completed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx2, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Do">Do</span>
|
||||||
|
|
||||||
|
<p>Acquires a lock for the specified key and executes the provided function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
task := func() {
|
||||||
|
fmt.Println("Executing task...")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("Task completed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := locker.Do(ctx2, "mykey", task); err != nil {
|
||||||
|
log.Fatalf("Error executing task: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Task successfully executed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
// Executing task...
|
||||||
|
// Task completed.
|
||||||
|
// Task successfully executed.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NewRWKeyedLocker">NewRWKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>RWKeyedLocker is a read-write version of KeyedLocker.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.Lock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RLock">RLock</span>
|
||||||
|
|
||||||
|
<p>Acquires a read lock for the specified key and executes the provided function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.RLock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Lock">Lock</span>
|
||||||
|
|
||||||
|
<p>Acquires a write lock for the specified key and executes the provided function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := NewRWKeyedLocker[string](2 * time.Second)
|
||||||
|
|
||||||
|
// Simulate a key
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
fn := func() {
|
||||||
|
fmt.Println("Starting write operation...")
|
||||||
|
// Simulate write operation, assuming it takes 2 seconds
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
fmt.Println("Write operation completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the write lock and execute the operation
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Execute the lock operation with a 3-second timeout
|
||||||
|
err := locker.Lock(ctx, key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Starting write operation...
|
||||||
|
//Write operation completed!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="NewTryKeyedLocker">NewTryKeyedLocker</span>
|
||||||
|
|
||||||
|
<p>TryKeyedLocker is a non-blocking version of KeyedLocker.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K]
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="TryLock">TryLock</span>
|
||||||
|
|
||||||
|
<p>TryLock tries to acquire a lock for the specified key.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Unlock">Unlock</span>
|
||||||
|
|
||||||
|
<p>Unlock releases the lock for the specified key.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
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>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
locker := concurrency.NewTryKeyedLocker[string]()
|
||||||
|
|
||||||
|
key := "resource_key"
|
||||||
|
|
||||||
|
if locker.TryLock(key) {
|
||||||
|
fmt.Println("Lock acquired")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// Unlock after work is done
|
||||||
|
locker.Unlock(key)
|
||||||
|
fmt.Println("Lock released")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Lock failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
//output:
|
||||||
|
//Lock acquired
|
||||||
|
//Lock released
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -826,6 +826,43 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsAlphaNumeric">IsAlphaNumeric</span>
|
||||||
|
|
||||||
|
<p>Check if the string is alphanumeric.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsAlphaNumeric(s string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsAlphaNumeric("ABC")
|
||||||
|
result2 := validator.IsAlphaNumeric("123")
|
||||||
|
result3 := validator.IsAlphaNumeric("abc123")
|
||||||
|
result4 := validator.IsAlphaNumeric("abc123@#$")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsJSON">IsJSON</span>
|
### <span id="IsJSON">IsJSON</span>
|
||||||
|
|
||||||
<p>Check if the string is valid JSON.</p>
|
<p>Check if the string is valid JSON.</p>
|
||||||
|
|||||||
@@ -842,6 +842,10 @@ func ExampleFindValuesBy() {
|
|||||||
return k%2 == 0
|
return k%2 == 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// github action will excute this test currently, so sort the result
|
||||||
|
// to make it deterministic
|
||||||
|
sort.Strings(result)
|
||||||
|
|
||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
|
|||||||
196
slice/slice.go
196
slice/slice.go
@@ -59,16 +59,18 @@ func ContainSubSlice[T comparable](slice, subSlice []T) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
elementMap := make(map[T]struct{}, len(slice))
|
elementCount := make(map[T]int, len(slice))
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
elementMap[item] = struct{}{}
|
elementCount[item]++
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range subSlice {
|
for _, item := range subSlice {
|
||||||
if _, ok := elementMap[item]; !ok {
|
if elementCount[item] == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
elementCount[item]--
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,14 +83,18 @@ func Chunk[T any](slice []T, size int) [][]T {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentChunk := []T{}
|
||||||
|
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
l := len(result)
|
if len(currentChunk) == size {
|
||||||
if l == 0 || len(result[l-1]) == size {
|
result = append(result, currentChunk)
|
||||||
result = append(result, []T{})
|
currentChunk = []T{}
|
||||||
l++
|
}
|
||||||
|
currentChunk = append(currentChunk, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
result[l-1] = append(result[l-1], item)
|
if len(currentChunk) > 0 {
|
||||||
|
result = append(result, currentChunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -106,6 +112,7 @@ func Compact[T comparable](slice []T) []T {
|
|||||||
result = append(result, v)
|
result = append(result, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result[:len(result):len(result)]
|
return result[:len(result):len(result)]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +140,17 @@ func Concat[T any](slices ...[]T) []T {
|
|||||||
func Difference[T comparable](slice, comparedSlice []T) []T {
|
func Difference[T comparable](slice, comparedSlice []T) []T {
|
||||||
result := []T{}
|
result := []T{}
|
||||||
|
|
||||||
|
if len(slice) == 0 {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
comparedMap := make(map[T]struct{}, len(comparedSlice))
|
||||||
|
for _, v := range comparedSlice {
|
||||||
|
comparedMap[v] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range slice {
|
for _, v := range slice {
|
||||||
if !Contain(comparedSlice, v) {
|
if _, found := comparedMap[v]; !found {
|
||||||
result = append(result, v)
|
result = append(result, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,13 +163,17 @@ func Difference[T comparable](slice, comparedSlice []T) []T {
|
|||||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy.
|
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy.
|
||||||
// Play: https://go.dev/play/p/DiivgwM5OnC
|
// Play: https://go.dev/play/p/DiivgwM5OnC
|
||||||
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
|
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
|
||||||
orginSliceAfterMap := Map(slice, iteratee)
|
|
||||||
comparedSliceAfterMap := Map(comparedSlice, iteratee)
|
|
||||||
|
|
||||||
result := make([]T, 0)
|
result := make([]T, 0)
|
||||||
for i, v := range orginSliceAfterMap {
|
|
||||||
if !Contain(comparedSliceAfterMap, v) {
|
comparedMap := make(map[T]struct{}, len(comparedSlice))
|
||||||
result = append(result, slice[i])
|
for _, item := range comparedSlice {
|
||||||
|
comparedMap[iteratee(0, item)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, item := range slice {
|
||||||
|
transformedItem := iteratee(i, item)
|
||||||
|
if _, found := comparedMap[transformedItem]; !found {
|
||||||
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,23 +185,32 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
|
|||||||
// The comparator is invoked with two arguments: (arrVal, othVal).
|
// The comparator is invoked with two arguments: (arrVal, othVal).
|
||||||
// Play: https://go.dev/play/p/v2U2deugKuV
|
// Play: https://go.dev/play/p/v2U2deugKuV
|
||||||
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
||||||
result := make([]T, 0)
|
|
||||||
|
|
||||||
getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int {
|
getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int {
|
||||||
index := -1
|
|
||||||
for i, v := range arr {
|
for i, v := range arr {
|
||||||
if comparison(item, v) {
|
if comparison(item, v) {
|
||||||
index = i
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, 0, len(slice))
|
||||||
|
|
||||||
|
comparedMap := make(map[int]T, len(comparedSlice))
|
||||||
|
for _, v := range comparedSlice {
|
||||||
|
comparedMap[getIndex(comparedSlice, v, comparator)] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range slice {
|
||||||
|
found := false
|
||||||
|
for _, existing := range comparedSlice {
|
||||||
|
if comparator(v, existing) {
|
||||||
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index
|
if !found {
|
||||||
}
|
result = append(result, v)
|
||||||
|
|
||||||
for i, v := range slice {
|
|
||||||
index := getIndex(comparedSlice, v, comparator)
|
|
||||||
if index == -1 {
|
|
||||||
result = append(result, slice[i])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,19 +452,20 @@ func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T,
|
|||||||
// Flatten flattens slice with one level.
|
// Flatten flattens slice with one level.
|
||||||
// Play: https://go.dev/play/p/hYa3cBEevtm
|
// Play: https://go.dev/play/p/hYa3cBEevtm
|
||||||
func Flatten(slice any) any {
|
func Flatten(slice any) any {
|
||||||
sv := sliceValue(slice)
|
sv := reflect.ValueOf(slice)
|
||||||
|
if sv.Kind() != reflect.Slice {
|
||||||
var result reflect.Value
|
panic("Flatten: input must be a slice")
|
||||||
if sv.Type().Elem().Kind() == reflect.Interface {
|
|
||||||
result = reflect.MakeSlice(reflect.TypeOf([]interface{}{}), 0, sv.Len())
|
|
||||||
} else if sv.Type().Elem().Kind() == reflect.Slice {
|
|
||||||
result = reflect.MakeSlice(sv.Type().Elem(), 0, sv.Len())
|
|
||||||
} else {
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elemType := sv.Type().Elem()
|
||||||
|
if elemType.Kind() == reflect.Slice {
|
||||||
|
elemType = elemType.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
result := reflect.MakeSlice(reflect.SliceOf(elemType), 0, sv.Len())
|
||||||
|
|
||||||
for i := 0; i < sv.Len(); i++ {
|
for i := 0; i < sv.Len(); i++ {
|
||||||
item := reflect.ValueOf(sv.Index(i).Interface())
|
item := sv.Index(i)
|
||||||
if item.Kind() == reflect.Slice {
|
if item.Kind() == reflect.Slice {
|
||||||
for j := 0; j < item.Len(); j++ {
|
for j := 0; j < item.Len(); j++ {
|
||||||
result = reflect.Append(result, item.Index(j))
|
result = reflect.Append(result, item.Index(j))
|
||||||
@@ -607,7 +637,7 @@ func Repeat[T any](item T, n int) []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceSlice convert param to slice of interface.
|
// InterfaceSlice convert param to slice of interface.
|
||||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
// deprecated: use generics feature of go1.18+ for replacement.
|
||||||
// Play: https://go.dev/play/p/FdQXF0Vvqs-
|
// Play: https://go.dev/play/p/FdQXF0Vvqs-
|
||||||
func InterfaceSlice(slice any) []any {
|
func InterfaceSlice(slice any) []any {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
@@ -624,7 +654,7 @@ func InterfaceSlice(slice any) []any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StringSlice convert param to slice of string.
|
// StringSlice convert param to slice of string.
|
||||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
// deprecated: use generics feature of go1.18+ for replacement.
|
||||||
// Play: https://go.dev/play/p/W0TZDWCPFcI
|
// Play: https://go.dev/play/p/W0TZDWCPFcI
|
||||||
func StringSlice(slice any) []string {
|
func StringSlice(slice any) []string {
|
||||||
v := sliceValue(slice)
|
v := sliceValue(slice)
|
||||||
@@ -642,7 +672,7 @@ func StringSlice(slice any) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IntSlice convert param to slice of int.
|
// IntSlice convert param to slice of int.
|
||||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
// deprecated: use generics feature of go1.18+ for replacement.
|
||||||
// Play: https://go.dev/play/p/UQDj-on9TGN
|
// Play: https://go.dev/play/p/UQDj-on9TGN
|
||||||
func IntSlice(slice any) []int {
|
func IntSlice(slice any) []int {
|
||||||
sv := sliceValue(slice)
|
sv := sliceValue(slice)
|
||||||
@@ -773,46 +803,54 @@ func InsertAt[T any](slice []T, index int, value any) []T {
|
|||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := value.(T); ok {
|
switch v := value.(type) {
|
||||||
slice = append(slice[:index], append([]T{v}, slice[index:]...)...)
|
case T:
|
||||||
|
result := make([]T, size+1)
|
||||||
|
copy(result, slice[:index])
|
||||||
|
result[index] = v
|
||||||
|
copy(result[index+1:], slice[index:])
|
||||||
|
return result
|
||||||
|
case []T:
|
||||||
|
result := make([]T, size+len(v))
|
||||||
|
copy(result, slice[:index])
|
||||||
|
copy(result[index:], v)
|
||||||
|
copy(result[index+len(v):], slice[index:])
|
||||||
|
return result
|
||||||
|
default:
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := value.([]T); ok {
|
|
||||||
slice = append(slice[:index], append(v, slice[index:]...)...)
|
|
||||||
return slice
|
|
||||||
}
|
|
||||||
|
|
||||||
return slice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
size := len(slice)
|
if index < 0 || index >= len(slice) {
|
||||||
|
|
||||||
if index < 0 || index >= size {
|
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
slice = append(slice[:index], append([]T{value}, slice[index+1:]...)...)
|
|
||||||
|
|
||||||
return slice
|
result := make([]T, len(slice))
|
||||||
|
copy(result, slice)
|
||||||
|
|
||||||
|
result[index] = value
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique remove duplicate elements in slice.
|
// Unique remove duplicate elements in slice.
|
||||||
// Play: https://go.dev/play/p/AXw0R3ZTE6a
|
// Play: https://go.dev/play/p/AXw0R3ZTE6a
|
||||||
func Unique[T comparable](slice []T) []T {
|
func Unique[T comparable](slice []T) []T {
|
||||||
result := make([]T, 0, len(slice))
|
if len(slice) == 0 {
|
||||||
seen := make(map[T]struct{}, len(slice))
|
return slice
|
||||||
|
|
||||||
for i := range slice {
|
|
||||||
if _, ok := seen[slice[i]]; ok {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seen[slice[i]] = struct{}{}
|
seen := make(map[T]struct{}, len(slice))
|
||||||
|
result := slice[:0]
|
||||||
|
|
||||||
result = append(result, slice[i])
|
for _, item := range slice {
|
||||||
|
if _, exists := seen[item]; !exists {
|
||||||
|
seen[item] = struct{}{}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -822,18 +860,19 @@ func Unique[T comparable](slice []T) []T {
|
|||||||
// The function maintains the order of the elements.
|
// The function maintains the order of the elements.
|
||||||
// Play: https://go.dev/play/p/GY7JE4yikrl
|
// Play: https://go.dev/play/p/GY7JE4yikrl
|
||||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
||||||
result := make([]T, 0, len(slice))
|
if len(slice) == 0 {
|
||||||
seen := make(map[U]struct{}, len(slice))
|
return slice
|
||||||
|
|
||||||
for i := range slice {
|
|
||||||
key := iteratee(slice[i])
|
|
||||||
if _, ok := seen[key]; ok {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seen[key] = struct{}{}
|
seen := make(map[U]struct{}, len(slice))
|
||||||
|
result := slice[:0]
|
||||||
|
|
||||||
result = append(result, slice[i])
|
for _, item := range slice {
|
||||||
|
key := iteratee(item)
|
||||||
|
if _, exists := seen[key]; !exists {
|
||||||
|
seen[key] = struct{}{}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -843,19 +882,20 @@ func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
|||||||
// The function maintains the order of the elements.
|
// The function maintains the order of the elements.
|
||||||
// Play: https://go.dev/play/p/rwSacr-ZHsR
|
// Play: https://go.dev/play/p/rwSacr-ZHsR
|
||||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T {
|
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T {
|
||||||
result := make([]T, 0, len(slice))
|
if len(slice) == 0 {
|
||||||
seen := make([]T, 0, len(slice))
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, 0, len(slice))
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
duplicate := false
|
isDuplicate := false
|
||||||
for _, seenItem := range seen {
|
for _, existing := range result {
|
||||||
if comparator(item, seenItem) {
|
if comparator(item, existing) {
|
||||||
duplicate = true
|
isDuplicate = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !duplicate {
|
if !isDuplicate {
|
||||||
seen = append(seen, item)
|
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,7 +396,10 @@ func RemoveNonPrintable(str string) string {
|
|||||||
// StringToBytes converts a string to byte slice without a memory allocation.
|
// StringToBytes converts a string to byte slice without a memory allocation.
|
||||||
// Play: https://go.dev/play/p/7OyFBrf9AxA
|
// Play: https://go.dev/play/p/7OyFBrf9AxA
|
||||||
func StringToBytes(str string) (b []byte) {
|
func StringToBytes(str string) (b []byte) {
|
||||||
return *(*[]byte)(unsafe.Pointer(&str))
|
return *(*[]byte)(unsafe.Pointer(&struct {
|
||||||
|
string
|
||||||
|
Cap int
|
||||||
|
}{str, len(str)}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BytesToString converts a byte slice to string without a memory allocation.
|
// BytesToString converts a byte slice to string without a memory allocation.
|
||||||
|
|||||||
@@ -518,7 +518,8 @@ func TestStringToBytes(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestStringToBytes")
|
assert := internal.NewAssert(t, "TestStringToBytes")
|
||||||
|
|
||||||
bytes := StringToBytes("abc")
|
bytes := StringToBytes("abc")
|
||||||
assert.Equal(bytes, []byte{'a', 'b', 'c'})
|
assert.Equal([]byte{'a', 'b', 'c'}, bytes)
|
||||||
|
assert.Equal(3, cap(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBytesToString(t *testing.T) {
|
func TestBytesToString(t *testing.T) {
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func IsJSON(str string) bool {
|
|||||||
return json.Unmarshal([]byte(str), &js) == nil
|
return json.Unmarshal([]byte(str), &js) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAlphaNumericStr check if the string is alphanumeric.
|
// IsAlphaNumeric check if the string is alphanumeric.
|
||||||
// Play: todo
|
// Play: todo
|
||||||
func IsAlphaNumeric(s string) bool {
|
func IsAlphaNumeric(s string) bool {
|
||||||
return alphaNumericMatcher.MatchString(s)
|
return alphaNumericMatcher.MatchString(s)
|
||||||
|
|||||||
@@ -665,3 +665,21 @@ func ExampleIsChinaUnionPay() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleIsAlphaNumeric() {
|
||||||
|
result1 := IsAlphaNumeric("ABC")
|
||||||
|
result2 := IsAlphaNumeric("123")
|
||||||
|
result3 := IsAlphaNumeric("abc123")
|
||||||
|
result4 := IsAlphaNumeric("abc123@#$")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user