mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
28 Commits
c1d49517d1
...
v2.3.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8120c4db78 | ||
|
|
0d0f213d36 | ||
|
|
41d4bbf0e3 | ||
|
|
fed1d5220e | ||
|
|
29a8318d6e | ||
|
|
3696213e5d | ||
|
|
90a3b87b67 | ||
|
|
a7b28ee864 | ||
|
|
f2823014f2 | ||
|
|
4181c42805 | ||
|
|
a09f5623d6 | ||
|
|
a9c75b081d | ||
|
|
db479ef1bc | ||
|
|
df8121fbbd | ||
|
|
0e7297cb97 | ||
|
|
2e619e48a3 | ||
|
|
3069acba4a | ||
|
|
fc43138a0e | ||
|
|
1e56e9964c | ||
|
|
e27df00fa8 | ||
|
|
23e61f1acf | ||
|
|
cb308f628c | ||
|
|
7653afa919 | ||
|
|
a0d97cf38e | ||
|
|
1f6bab467c | ||
|
|
2e5b9bc200 | ||
|
|
ab89f0aee1 | ||
|
|
1f64e02df4 |
72
README.md
72
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)
|
||||||
@@ -506,9 +506,24 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
- **<big>AddMinute</big>** : add or sub day to the time.
|
- **<big>AddMinute</big>** : add or sub day to the time.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMinute)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMinute)]
|
||||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||||
|
- **<big>AddWeek</big>** : add or sub week to time.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddWeek)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddMonth</big>** : add or sub months to time.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMonth)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<big>AddYear</big>** : add or sub year to the time.
|
- **<big>AddYear</big>** : add or sub year to the time.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddYear)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddYear)]
|
||||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||||
|
- **<big>AddDaySafe</big>** : add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddDaySafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddMonthSafe</big>** : add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddMonthSafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddYearSafe</big>** : Add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#AddYearSafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<big>BeginOfMinute</big>** : return the date time at the begin of minute of specific date.
|
- **<big>BeginOfMinute</big>** : return the date time at the begin of minute of specific date.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#BeginOfMinute)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#BeginOfMinute)]
|
||||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||||
@@ -680,6 +695,45 @@ import optional "github.com/duke-git/lancet/v2/datastructure/optional"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datastructure/optional.md)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datastructure/optional.md)]
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="eventbus"> 9. EventBus is an event bus used for handling events within an application. <a href="#index">Index</a></h3>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 函数列表:
|
||||||
|
|
||||||
|
- **<big>NewEventBus</big>** : Create an EventBus instance.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#NewEventBus)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Subscribe</big>** : subscribes to an event with a specific event topic and listener function.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Subscribe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Unsubscribe</big>** : unsubscribes from an event with a specific event topic and listener function.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Unsubscribe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Publish</big>** : publishes an event with a specific event topic and data payload.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#Publish)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>ClearListeners</big>** : clears all the listeners.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#ClearListeners)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>ClearListenersByTopic</big>** : clears all the listeners by topic.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#ClearListenersByTopic)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetListenersCount</big>** : returns the number of listeners for a specific event topic.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetListenersCount)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetAllListenersCount</big>** : returns the total number of all listeners.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetAllListenersCount)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetEvents</big>** : returns all the events topics.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#GetEvents)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>SetErrorHandler</big>** : sets the error handler function.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#SetErrorHandler)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. <a href="#index">index</a></h3>
|
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1423,6 +1477,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>EqualWith</big>** : checks if two slices are equal with comparator func.
|
- **<big>EqualWith</big>** : checks if two slices are equal with comparator func.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#EqualWith)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#EqualWith)]
|
||||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||||
|
- **<big>EqualUnordered</big>** : Checks if two slices are equal: the same length and all elements value are equal (unordered).
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#EqualUnordered)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>Every</big>** : return true if all of the values in the slice pass the predicate function.
|
- **<big>Every</big>** : return true if all of the values in the slice pass the predicate function.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Every)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Every)]
|
||||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||||
@@ -1522,6 +1579,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>Shuffle</big>** : shuffle the slice.
|
- **<big>Shuffle</big>** : shuffle the slice.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Shuffle)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Shuffle)]
|
||||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||||
|
- **<big>ShuffleCopy</big>** : return a new slice with elements shuffled.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ShuffleCopy)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>IsAscending</big>** : Checks if a slice is ascending order.
|
- **<big>IsAscending</big>** : Checks if a slice is ascending order.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#IsAscending)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#IsAscending)]
|
||||||
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
||||||
@@ -1668,6 +1728,9 @@ import "github.com/duke-git/lancet/v2/stream"
|
|||||||
- **<big>Reverse</big>** : returns a stream whose elements are reverse order of given stream.
|
- **<big>Reverse</big>** : returns a stream whose elements are reverse order of given stream.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Reverse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Reverse)]
|
||||||
[[play](https://go.dev/play/p/A8_zkJnLHm4)]
|
[[play](https://go.dev/play/p/A8_zkJnLHm4)]
|
||||||
|
- **<big>ReverseCopy</big>** : returns a new slice of element order is reversed to the given slice.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#ReverseCopy)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>Range</big>** : returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
- **<big>Range</big>** : returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Range)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Range)]
|
||||||
[[play](https://go.dev/play/p/indZY5V2f4j)]
|
[[play](https://go.dev/play/p/indZY5V2f4j)]
|
||||||
@@ -1897,7 +1960,9 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
- **<big>ExtractContent</big>** : extracts the content between the start and end strings in the source string.
|
- **<big>ExtractContent</big>** : extracts the content between the start and end strings in the source string.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#ExtractContent)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#ExtractContent)]
|
||||||
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||||
|
- **<big>FindAllOccurrences</big>** : Returns the positions of all occurrences of a substring in a string.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#FindAllOccurrences)]
|
||||||
|
[[play](todo)]
|
||||||
|
|
||||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -2151,6 +2216,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsIpV6</big>** : check if the string is ipv6.
|
- **<big>IsIpV6</big>** : check if the string is ipv6.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsIpV6)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsIpV6)]
|
||||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||||
|
- **<big>IsIpPort</big>** : check if the string is ip:port.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsIpPort)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>IsStrongPassword</big>** : check if the string is strong password.
|
- **<big>IsStrongPassword</big>** : check if the string is strong password.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsStrongPassword)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsStrongPassword)]
|
||||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||||
|
|||||||
106
README_zh-CN.md
106
README_zh-CN.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)
|
||||||
@@ -507,9 +507,24 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
- **<big>AddMinute</big>** : 将日期加/减分钟数。
|
- **<big>AddMinute</big>** : 将日期加/减分钟数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMinute)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMinute)]
|
||||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||||
|
- **<big>AddWeek</big>** : 将日期加/减星期数.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddWeek)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddMonth</big>** : 将日期加/减月数.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMonth)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<big>AddYear</big>** : 将日期加/减分年数。
|
- **<big>AddYear</big>** : 将日期加/减分年数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddYear)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddYear)]
|
||||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||||
|
- **<big>AddDaySafe</big>** : 增加/减少指定的天数,并确保日期是有效日期。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddDaySafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddMonthSafe</big>** : 增加/减少指定的月份,并确保日期是有效日期。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddMonthSafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>AddYearSafe</big>** : 增加/减少指定的年份,并确保日期是有效日期。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#AddYearSafe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
- **<big>BeginOfMinute</big>** : 返回指定时间的分钟开始时间。
|
- **<big>BeginOfMinute</big>** : 返回指定时间的分钟开始时间。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#BeginOfMinute)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#BeginOfMinute)]
|
||||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||||
@@ -679,7 +694,46 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
|||||||
- **<big>Hashmap</big>** : 哈希映射。
|
- **<big>Hashmap</big>** : 哈希映射。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datastructure/hashmap.md)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datastructure/hashmap.md)]
|
||||||
|
|
||||||
<h3 id="fileutil"> 9. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
<h3 id="eventbus"> 9. EventbBus是一个事件总线,用于在应用程序中处理事件。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 函数列表:
|
||||||
|
|
||||||
|
- **<big>NewEventBus</big>** : 创建EventBus实例。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#NewEventBus)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Subscribe</big>** : 订阅具有特定事件主题和监听函数的事件。支持异步,事件优先级,事件过滤器。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Subscribe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Unsubscribe</big>** : 取消订阅具有特定事件主题的事件。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Unsubscribe)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>Publish</big>** : 发布一个带有特定事件主题和数据负载的事件。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#Publish)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>ClearListeners</big>** : 清空所有事件监听器。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#ClearListeners)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>ClearListenersByTopic</big>** : 清空特定事件监听器。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#ClearListenersByTopic)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetListenersCount</big>** : 获取特定事件的监听器数量。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetListenersCount)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetAllListenersCount</big>** : 获取所有事件的监听器数量。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetAllListenersCount)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>GetEvents</big>** : 获取所有事件的topic。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#GetEvents)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
- **<big>SetErrorHandler</big>** : 设置事件的错误处理函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#SetErrorHandler)]
|
||||||
|
[[play](https://go.dev/play/p/todo)]
|
||||||
|
|
||||||
|
<h3 id="fileutil"> 10. fileutil 包含文件基本操作。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/fileutil"
|
import "github.com/duke-git/lancet/v2/fileutil"
|
||||||
@@ -779,7 +833,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
[[play](https://go.dev/play/p/iLRrDBhE38E)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
<h3 id="formatter"> 11. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/formatter"
|
import "github.com/duke-git/lancet/v2/formatter"
|
||||||
@@ -809,7 +863,7 @@ import "github.com/duke-git/lancet/v2/formatter"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/formatter.md#ParseBinaryBytes)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/formatter.md#ParseBinaryBytes)]
|
||||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||||
|
|
||||||
<h3 id="function"> 11. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
<h3 id="function"> 12. function 函数包控制函数执行流程,包含部分函数式编程。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/function"
|
import "github.com/duke-git/lancet/v2/function"
|
||||||
@@ -874,7 +928,7 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="maputil"> 12. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="maputil"> 13. maputil 包括一些操作 map 的函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/maputil"
|
import "github.com/duke-git/lancet/v2/maputil"
|
||||||
@@ -1045,7 +1099,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[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)]
|
||||||
|
|
||||||
<h3 id="mathutil"> 13. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/mathutil"
|
import "github.com/duke-git/lancet/v2/mathutil"
|
||||||
@@ -1156,7 +1210,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
|
||||||
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
|
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
|
||||||
|
|
||||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
<h3 id="netutil"> 15. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/netutil"
|
import "github.com/duke-git/lancet/v2/netutil"
|
||||||
@@ -1229,7 +1283,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#IsTelnetConnected)]
|
[[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)]
|
||||||
|
|
||||||
<h3 id="pointer"> 15. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/pointer"
|
import "github.com/duke-git/lancet/v2/pointer"
|
||||||
@@ -1253,7 +1307,7 @@ import "github.com/duke-git/lancet/v2/pointer"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/pointer.md#UnwrapOrDefault)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/pointer.md#UnwrapOrDefault)]
|
||||||
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
|
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
|
||||||
|
|
||||||
<h3 id="random"> 16. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
<h3 id="random"> 17. random 随机数生成器包,可以生成随机[]bytes, int, string。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/random"
|
import "github.com/duke-git/lancet/v2/random"
|
||||||
@@ -1319,7 +1373,7 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
|
||||||
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
|
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
|
||||||
|
|
||||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
<h3 id="retry"> 18. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/retry"
|
import "github.com/duke-git/lancet/v2/retry"
|
||||||
@@ -1353,7 +1407,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
<h3 id="slice"> 19. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/slice"
|
import "github.com/duke-git/lancet/v2/slice"
|
||||||
@@ -1421,6 +1475,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数 comparator,返回 true。
|
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数 comparator,返回 true。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#EqualWith)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#EqualWith)]
|
||||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||||
|
- **<big>EqualUnordered</big>** : 检查两个切片是否相等,元素数量相同,值相等,不考虑元素顺序。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#EqualUnordered)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回 true。
|
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回 true。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Every)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Every)]
|
||||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||||
@@ -1496,6 +1553,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>Reverse</big>** : 反转切片中的元素顺序。
|
- **<big>Reverse</big>** : 反转切片中的元素顺序。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reverse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reverse)]
|
||||||
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
||||||
|
- **<big>ReverseCopy</big>** : 反转切片中的元素顺序, 不改变原slice。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#ReverseCopy)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>Reduce<sup>deprecated</sup></big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。(废弃:建议使用 ReduceBy)
|
- **<big>Reduce<sup>deprecated</sup></big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。(废弃:建议使用 ReduceBy)
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reduce)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Reduce)]
|
||||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||||
@@ -1520,6 +1580,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
|
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Shuffle)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Shuffle)]
|
||||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||||
|
- **<big>ShuffleCopy</big>** : 随机打乱切片中的元素顺序, 不改变原切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ShuffleCopy)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>IsAscending</big>** : 检查切片元素是否按升序排列。
|
- **<big>IsAscending</big>** : 检查切片元素是否按升序排列。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#IsAscending)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#IsAscending)]
|
||||||
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
[[play](https://go.dev/play/p/9CtsFjet4SH)]
|
||||||
@@ -1615,7 +1678,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
|
||||||
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
|
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
|
||||||
|
|
||||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
<h3 id="stream"> 20. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/stream"
|
import "github.com/duke-git/lancet/v2/stream"
|
||||||
@@ -1711,7 +1774,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
|
||||||
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
|
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
|
||||||
|
|
||||||
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="structs"> 21. structs 提供操作 struct, tag, field 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/structs"
|
import "github.com/duke-git/lancet/v2/structs"
|
||||||
@@ -1748,7 +1811,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
|||||||
- **<big>IsTargetType</big>** : 判断属性是否是目标类型。
|
- **<big>IsTargetType</big>** : 判断属性是否是目标类型。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsTargetType)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsTargetType)]
|
||||||
|
|
||||||
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="strutil"> 22. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -1897,8 +1960,12 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
- **<big>ExtractContent</big>** : 提取两个标记之间的内容。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#ExtractContent)]
|
||||||
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
[[play](https://go.dev/play/p/Ay9UIk7Rum9)]
|
||||||
|
- **<big>FindAllOccurrences</big>** : 返回子字符串在字符串中所有出现的位置。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#FindAllOccurrences)]
|
||||||
|
[[play](todo)]
|
||||||
|
|
||||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
|
||||||
|
<h3 id="system"> 23. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/system"
|
import "github.com/duke-git/lancet/v2/system"
|
||||||
@@ -1948,7 +2015,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="tuple"> 23. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
<h3 id="tuple"> 24. Tuple 包实现一个元组数据类型。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/tuple"
|
import "github.com/duke-git/lancet/v2/tuple"
|
||||||
@@ -2065,7 +2132,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/tuple.md#Unzip10)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/tuple.md#Unzip10)]
|
||||||
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
|
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
|
||||||
|
|
||||||
<h3 id="validator"> 24. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="validator"> 25. validator 验证器包,包含常用字符串格式验证函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -2151,6 +2218,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV6)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpV6)]
|
||||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||||
|
- **<big>IsIpPort</big>** : 检查字符串是否是ip:port格式。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsIpPort)]
|
||||||
|
[[play](todo)]
|
||||||
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsStrongPassword)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsStrongPassword)]
|
||||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||||
@@ -2200,7 +2270,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsChinaUnionPay)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsChinaUnionPay)]
|
||||||
[[play](https://go.dev/play/p/yafpdxLiymu)]
|
[[play](https://go.dev/play/p/yafpdxLiymu)]
|
||||||
|
|
||||||
<h3 id="xerror"> 25. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="xerror"> 26. xerror 包实现一些错误处理函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
|
|||||||
@@ -157,10 +157,10 @@ func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
|||||||
// Play: https://go.dev/play/p/qmWSy1NVF-Y
|
// Play: https://go.dev/play/p/qmWSy1NVF-Y
|
||||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||||
valStream := make(chan T)
|
valStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(valStream)
|
defer close(valStream)
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
defer wg.Wait()
|
||||||
for {
|
for {
|
||||||
var stream <-chan T
|
var stream <-chan T
|
||||||
select {
|
select {
|
||||||
@@ -169,19 +169,22 @@ func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
stream = maybeStream
|
stream = maybeStream
|
||||||
|
wg.Add(1)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for val := range c.OrDone(ctx, stream) {
|
go func() {
|
||||||
select {
|
defer wg.Done()
|
||||||
case valStream <- val:
|
for val := range c.OrDone(ctx, stream) {
|
||||||
case <-ctx.Done():
|
select {
|
||||||
|
case valStream <- val:
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return valStream
|
return valStream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,8 @@ func ExampleChannel_Tee() {
|
|||||||
func ExampleChannel_Bridge() {
|
func ExampleChannel_Bridge() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
m1 := make(map[int]int)
|
||||||
|
m2 := make(map[int]int)
|
||||||
c := NewChannel[int]()
|
c := NewChannel[int]()
|
||||||
genVals := func() <-chan <-chan int {
|
genVals := func() <-chan <-chan int {
|
||||||
out := make(chan (<-chan int))
|
out := make(chan (<-chan int))
|
||||||
@@ -177,6 +178,7 @@ func ExampleChannel_Bridge() {
|
|||||||
for i := 1; i <= 5; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
stream := make(chan int, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
|
m1[i]++
|
||||||
close(stream)
|
close(stream)
|
||||||
out <- stream
|
out <- stream
|
||||||
}
|
}
|
||||||
@@ -185,12 +187,15 @@ func ExampleChannel_Bridge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for v := range c.Bridge(ctx, genVals()) {
|
for v := range c.Bridge(ctx, genVals()) {
|
||||||
fmt.Println(v)
|
m2[v]++
|
||||||
|
}
|
||||||
|
for k, v := range m1 {
|
||||||
|
fmt.Println(m2[k] == v)
|
||||||
}
|
}
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// true
|
||||||
// 2
|
// true
|
||||||
// 3
|
// true
|
||||||
// 4
|
// true
|
||||||
// 5
|
// true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ func TestTee(t *testing.T) {
|
|||||||
func TestBridge(t *testing.T) {
|
func TestBridge(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
assert := internal.NewAssert(t, "TestBridge")
|
assert := internal.NewAssert(t, "TestBridge")
|
||||||
|
m1 := make(map[int]int)
|
||||||
|
m2 := make(map[int]int)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -181,6 +182,7 @@ func TestBridge(t *testing.T) {
|
|||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
stream := make(chan int, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
|
m1[i]++
|
||||||
close(stream)
|
close(stream)
|
||||||
chanStream <- stream
|
chanStream <- stream
|
||||||
}
|
}
|
||||||
@@ -188,9 +190,11 @@ func TestBridge(t *testing.T) {
|
|||||||
return chanStream
|
return chanStream
|
||||||
}
|
}
|
||||||
|
|
||||||
index := 0
|
|
||||||
for val := range c.Bridge(ctx, genVals()) {
|
for val := range c.Bridge(ctx, genVals()) {
|
||||||
assert.Equal(index, val)
|
m2[val]++
|
||||||
index++
|
}
|
||||||
|
|
||||||
|
for k, v := range m1 {
|
||||||
|
assert.Equal(m2[k], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
-----BEGIN rsa private key-----
|
-----BEGIN rsa private key-----
|
||||||
MIIJKAIBAAKCAgEA3aIM62NSgImSuiZwlvnVY9U+nJbq/77e5TMQa8h0OiY8d/c4
|
MIIJKAIBAAKCAgEA0HaqqGWnNqwRVKoJUUjYiH/dwkSK61La4RGYkvDfcuo9pDgc
|
||||||
OfyCHM2vQIlxl28a3WpbUkI3kebkDEefLDoBxaL1+A+x8S5Lvy0zfNk/Eo2vxNmJ
|
zHVhFUb/MYWeb3bAlFAGcZLYSBh6WAGxbeMjSkaLroaXnafhKZ2oXXUy8CzyYxZw
|
||||||
OnWF8FLAPFhZq7DzGIGsmgDHe9uXDhsbosfq34chnYOQuZ9/mFy9+Jv8axI+Cgbr
|
pLCDgJLG7Pf0jer3STZW93ZT8UJixbKwbqD6b8fkpMANwCYrTlXDWBuZVaEKuQNn
|
||||||
d0N6MVlZ50LEQ3x5SY0xVnCPDxPFKPumvZNeD3prp5BvX4v3IoA5Xx1Kkm2tM4yI
|
C4XufQis4fwRxRgfrZuLMvuQVtnyYmssmnp8JHovYkr87giDjEgvlrC84Lez32Zh
|
||||||
kJrfZFX+B+BGjpyCt6HU+yz+i7gtSjtZ5IvpnpvsJ0SseSz9AXCIfofFxqpO40Vr
|
EhORRu5NGEDeZ1OewbkXGyQtbcBQYNAxgnOcO44MTTPhEdz4/A0xwzEe+yIOxWIA
|
||||||
GRGK3bKyTDaZjvybt7+5IMb4dUyzKMdjujjLStKP0S+W2phEaNWHLEzXA3AXOJ+n
|
WuEM2rclXpZBW/MEK41gZ3C04KcX5R0KRdj2PTTH7vJ33yRC4hKtWetwMvsUrewr
|
||||||
RN6oplso0BNtyiC9sWKSJUWbUqmdZXmbVuB6vZDb5Ae9KLgeHeb37HUdFbNs5rus
|
RKVcUgaeFykDAlgIDoSWvG0nzb70AWSoNcj7krLlwEc2WLGy/kCYWppnfYKafEJX
|
||||||
pfdoDaXZzUI2zM2M8A0NRzxQJUGbDxqyPvPUEr84O1P6A6WQ1JlOpljGB6fprgF7
|
pgblHrDFKlWvte68yrvGdCsWRLQ2uUF0xokQIg4u2bApyWNroxEtjHwUp1VeJuZB
|
||||||
Su/HHYesEYPbTUoV/WrcYTVdoOiC7K5jNgRVapbng8NNDvaQvsJwKgeRDonzxsMG
|
Qkfg+vIW+t3moQpMtlhy4aai/oGIxI5TIB82nv8TPVczjHmmE3hwL6nZ5OfbFyWp
|
||||||
21Iqd0/ekaRp+t8BwX6kHJtkadGUkF5aDoWecnyk8baN/JAVuGv4IN8K7dtKBOTm
|
RFvKLtXcaAKMi2HqOLRkQhqjjJUCO9Wyhu1BkX8RAeKLl3S7gRyhuOB5JNUGEpQ3
|
||||||
KxPFtyPHAl6rUlc/oKnQ/36MoRTXJwiqRCGnaSrjaU++9M2VC6zBecCERYECAwEA
|
89MdbUX5S12Qp1xTDS+otbC8tYS1gu0OOOWowxbuF5+Ci2SYgSHv/3zXKoMCAwEA
|
||||||
AQKCAgEAjdRM9jlKK41eQxekR0k7gDaPab++RMkNdJj38jGGB0w+t/qRlbH8RZhu
|
AQKCAgBASCdt0BLVABBEDD7dStpClTNbwWkZEa6e8p8ayJ4OwH6LkiYHQjbSqdbt
|
||||||
hRsvgNwN0hFkvUA4tXqPBziyKKg6SBJf202X7qJUwNOZNlUD4sie6ZbYFXvtqXwb
|
fWeStYrC8T5bbU22RZ4MX1FIMl9iewh9o9FC806yV4RgdVBk0WdY+MV5c1jJn/kp
|
||||||
HsLfJ1sGRfF91dOX1LASe2lnhwTuTfr4zQbLj639BjCbNUQFBTPYVaxV9K1OvdPT
|
f3hw/sCMWe5NVrah0bfFgMl5A7jWGUy/JN3Yn6yA9l9LXw9UYVl+Hbd7zSvycGdn
|
||||||
D4YPeKxoJWRgZVOEiP561h4sdvaeY8NQrxtj2j4EeaSakj55YTkkdG+DWR5yxI+v
|
NCSCo2K5VRqCeSJUNdbRVH0nkZeQZAESjU8bU5LFAklybUOBBAS6YcaTHWeR+M/b
|
||||||
D7U7EboggIjkdZQ2lIzZFr7iaLoMV36qYfq1cJoUkl5ESsxyCQ8lipT600EBn5vi
|
J72tHRL6Z8nhO7Gqg0AF6o0pzd6iWrYeZF4F9R7uEl+C8jW8eQ8W/JZhb75X/1vN
|
||||||
M5lhLTqEH9NmEg6iItZhdEAclqgPlvI4wXjdqwM080zYwlcWGM5tu7c0C+kPryC/
|
pAW5heGGUI0muJF+KOhsZR0S1slvHbCSvwaNBQi8HEbOEPa7wVzsrGLfc+re5ysF
|
||||||
PnUTxGx+IDh92H/iuedoPuYKB3cQtMCFsmo7MyamSJXGhU/cxsSHNZR6P5mM2X8j
|
X2n5GL4qBwNdMHrADnMWWVa9LEUSr3XmXfpmNDctmdv1ekWpJ44G/qrjKOuimtfk
|
||||||
Kg25x95m+hiM8NoqlhAsDVKd/yb1WeoZSjwdQWllLSp98jgKeuG8bK7Ww9ZY/brv
|
t9haDjhN5lx3V05k18kb53tYAdi3CqrT4syiibtqZLvTRam/yoFJgSOczO5WxNNk
|
||||||
Pp6GRivRce6WHwgKwRv0Srt8VIzdpT+/DZCkgxkUaBRHMN1Gd4QaFqc9d0ZQmgnN
|
xnhnEdr/FQcFQhzuQ6gU196SBi8Bqjz1t0cNozNu3wvp8Fu0G8Rr9gjYnH8m5xXz
|
||||||
oJoVL0FbWMiRHnbQOF0Y91oBut8vGYEIvOujqEhwvSsLus0oQpHGn7YpOxgtr3Nl
|
xb9xevR7X/swfxd+/KUqoenYdU5ZFJpDRCmUMDKWR/3Q7s4SRxMN0+c/uBSaih3J
|
||||||
LJiQhwVJ7Ye/7u8A1BQR6BuO6DC0YE1KwdFGeomcupvD9Ke1NJECggEBAPMgsMpq
|
I9I8urHG6mFW2qWQZTvuostmb7vVHaefx0RZOhX0efJVMZPwiQKCAQEA8BUXRw9k
|
||||||
ykI+kesCeTljGmg4o+ApbH+pGlySUWvLraBXfKr17t7k+4q5t8BzuITK0IFdtRxc
|
Ms3tqmBMVM4sMcPgsffJxjAJUdunUgEpaBAqrDQmZ6uBjAYq7iTzLgJJuLI1o1sv
|
||||||
mI5HM5A6UcImmq5NVWVckn0UoYDY6dilccqIX7OBjNBPz85DjzA6QNddOXxVjOqq
|
HtEWuGLHRRJpdoEamGweJE/o28OH2MBiiL2ezfRIHsg8RRr6os6KvlKevty6m7d9
|
||||||
LbTZ01dCszbHxJDe2SJ9MGIMbgqYosKREh5M+T8vsAZsBtZgXfLqjjDS9QRWmOAx
|
hAvpS6XvZGK2eCSooL6zZ8XTgnDw+Hw8Q4i+dazjb5dDRRL97eHHUqzcYH5vIsAE
|
||||||
KWUAJsf4IgbbZ2+GVOjs2qw9BdRo3tvXxQTjfOBO0Jpoe3COTuLiJDMF1FclbETt
|
EBaNXMKrhf/NyVWCJBVRHg8PZZjGXcrj8ZMx+ejDR0AL5BXUaAX3fYnQyJf6QzrD
|
||||||
B339JImevoAQCGxVJAcDuI+Qhz+j+NSEpJlinkI0V+l5F6BTnQeQopifllPO0Q01
|
t5aNDoU6vPO77CLkqBavTePTToiVeTIMZP5yHZFQuPWtP/y67e0csNA6ezwpWEh4
|
||||||
3fjr6uhKeWMmZ40CggEBAOleBlOu2eBAHk+YiWXqosBAuNFK59/2TEiH3KmDDoP1
|
4MnpLWzC2YRZ/wKCAQEA3kjpB3977IHFw90Xn8TQu3/SzBMUBqdj5yo6gPBijKNf
|
||||||
71WPQOh0H9ERNp5F0ZCdZrOit3sbVYvxJ86KBJpZvEuhx6EED6uL7xcAsqv5sHfW
|
4mZ1shUp6vZkFOHbAmoafjqCzOO18tW4ci+UWAQgdXQWXwsQDUM+fZsr/5Z9LoIN
|
||||||
z4F3Z7qbdkrHgceYEjM3n4aiOEz0js4hq7LkfpyT4VZrWmivrJAnU2u7+1u+JNE3
|
TYuq98Yh/rjKABxkFdMmkLmykuAblDRwVeMf3e4x6/55hAkwvESBRdfnSjjoNmEM
|
||||||
AfXyKL5TCNyyfPVhbFJ8aM5znB2UZ9IKFSnMZrxRMuPMVzMOUn5JyLUaVGXCW4LT
|
MRVW4v5meDv0W4NS1eyohWPe/IoR09dSsmMhz311b7btBxc97NNqDD4SdxmASnOZ
|
||||||
bL3FGXZX8X8K2wTb7Pp7zVxkDyZvU0fkLrQwx9vIwK++jIP0AdzaV4r9HM5Iynsb
|
qsE2QxRHRFjpTvytpZH/lTQH6IYdh9REZgX7uvmlmTQwqLy6wX5T/oEzVPRhXgh9
|
||||||
8Z1DoNHCN7KIF3bMoqeaQUDSTCQ7oRaNhh3xA4dYbsUCggEAQ0fQpLNYtWxLRRWy
|
rgbPPJuoZwWF+fXipJ8c+laQ/sdzDKCxEEhRZr7HfQKCAQBKflDVtLnjZbA78Fte
|
||||||
Jkdej2jdMLNF6y4ItYVoMsRyj+SmA0l7iQMk+Qbb6s4bSeQ2PxaHgAm/zd+2TTtW
|
6QYffubGcdtCyn7pzl0RfdjKOFH1Us0j17x/pR5G/GIUQZN8YpdwE4gAaOJC3it0
|
||||||
VLwKIiIUd7BeeW60IsvkKqfeDYYftbUsGpl7kEDx5w630uFhfx7NmELv0xRUf9ld
|
jCz7Hz4QU2Pa4oyfPAF3yOIKCcQvpX+HRZwl2SQxxiKYwWwOTtD8JiglA8kktt0b
|
||||||
btNpeg2xWPH76aY27Ye/wsgSk4AJmYrA04YhfkG8vfRa1PgMBd9Q/vmb0u9vy/bG
|
6eEyUDWegu2J4oEpdT/f6jSMw+5M9xMu+eFemnD+EdNWHNrYegKj5q6cC1Nbl+++
|
||||||
s88TmLE73hltiix46Ib85SmYw/mQHSKyZ4hyYHuBKRgbnGMIl/UrOQe/AwaCjfL4
|
yUuiEA0sgwzDZeriHFBYo+6sc37LS2TkQ8QsxnU8vbU4V73XsAhwOdimq2kjO0Wp
|
||||||
FMhbDF+jUK2e7Vu5kcr2mRj709aOpROHIHz6JMv+sJE97a58E0UwZM97Vd8zaoTx
|
gXsq3vzSBw/n/CwBrzGqBFSCNc1UzVUdvuU9+H5L+wmu9z1eJaGyifIv1ZariJbB
|
||||||
gpamIQKCAQArrWdtvioVKKsDpr8AjjvL09FDist/RW/dm2AXceoDlMIot1kkqKdT
|
BWcjAoIBACWRJPEDdqot9IJ5pzh1RuGpZLLgto25VIUI+gI4ni8unVHiBxolwYPY
|
||||||
z+7zDIo+kNcqA+hnaCRIvuf+ZiKaaPUvCqZ8YnA0YUpsebr3KRJ4O4I27wxBBtvK
|
SGnPEfiCfh+/O8Ps6B82R4nkyKlnaSTwjadac0gKiVEpHHKBuH5XtG/anvZpIe2u
|
||||||
/zAxFStC3sRCxJXZAWTA+9hQ8ScpUxw3unv/X/HiQRoB7fsLnrjxV2RMjfhGNvBP
|
xVTnd3LI0Me82pVAEuklQ6cAT65uRzmfNGJAO2BWI5LuPkSpAXXPSQQymxCZ9i9z
|
||||||
rjBpFMTbY2GSUl0DxETyMOTpH9KSqHfn3tTrP2D9Nf4Ut0rYiNnr0Hpnwj4Twj32
|
0oR02VcWPBTvIAyGOSUYSv2jC1/J0EMlI0IDh4+y20VeaDiAstHiX6IgLU+A6dp/
|
||||||
0ydO74KZFxbGlgun2+owaGq9WuvtHNPDkNxnzgGTPmJoJxt/GGydQgukrYWp/LnD
|
PE8BHUfSOOO6e2us3ujJ0xV7BWRANOCDlYWu/9EbzI5Cv64n7xy5SqRSukt/8yIW
|
||||||
9mi92WsQB3TzFukdVvO9btuNOxC4AjspAoIBAFeJ8ND4aVzHHfh9BJKTytlFMNXY
|
KOJpz/gKfBdC8hZdFvCXZ9Vco4U90PECggEBAIwy5zuWqSaJ8kom7kMZj+JYfhVz
|
||||||
Z7VrCNxXN5ab1L2DL1JeUWAF0pwQifkcSUWB0nXvf5+zfhclIOkCOQSjQgVEZbF1
|
rdozFil1CkmWcw4E+rNcq8bKVTa9Er6/3nBTXfKX+4sYzMzbFr6xjFyrPA62wjiT
|
||||||
uma21nrLd+EgrqaF3XtBIiYfZCiGUcI2dj+WT15ZBiSEqX5VbhTMBD37GyvXIZBp
|
2MRdHu9iB+Rtxn83Ilnh+Aqu/8bPFQUlYFr7nefy2t1aL76diQnsBu4xHOtEMgSv
|
||||||
Gs95zje9JJ8kDtaTLYf08FtveLAyPwt4WaQnNY+5dE6wHQij+ueMgNlnxy1i0CRK
|
F6d/pDFRC+PZN0B7glrz870jRaw9LNcuIBVoKN07hGBwD76EEZhCrn6eLqMI8srH
|
||||||
xzrxTxksQkdJ0BQTiRlAsqwTpEI8toCeeUZk3zOcX4maxjlabiGp7ZAgqyEkP8wA
|
YESDPUR/wl/PV8ZrA/hNRvjp44PYiLMYRDSQw8kpbLMMc0QgQCvhfMbYVvGteTmG
|
||||||
guchSFfon1+Ukf6jnOhGNFVZwL2cXxlDiZGozTdztLc5GF2IQ/NagL7eyyo=
|
qdCFyy2x70wSh6Rfzb7WEWl15I4yfBTddXkJX82S+MrZu/Xq4FDtng594h0=
|
||||||
-----END rsa private key-----
|
-----END rsa private key-----
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
-----BEGIN rsa public key-----
|
-----BEGIN rsa public key-----
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3aIM62NSgImSuiZwlvnV
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0HaqqGWnNqwRVKoJUUjY
|
||||||
Y9U+nJbq/77e5TMQa8h0OiY8d/c4OfyCHM2vQIlxl28a3WpbUkI3kebkDEefLDoB
|
iH/dwkSK61La4RGYkvDfcuo9pDgczHVhFUb/MYWeb3bAlFAGcZLYSBh6WAGxbeMj
|
||||||
xaL1+A+x8S5Lvy0zfNk/Eo2vxNmJOnWF8FLAPFhZq7DzGIGsmgDHe9uXDhsbosfq
|
SkaLroaXnafhKZ2oXXUy8CzyYxZwpLCDgJLG7Pf0jer3STZW93ZT8UJixbKwbqD6
|
||||||
34chnYOQuZ9/mFy9+Jv8axI+Cgbrd0N6MVlZ50LEQ3x5SY0xVnCPDxPFKPumvZNe
|
b8fkpMANwCYrTlXDWBuZVaEKuQNnC4XufQis4fwRxRgfrZuLMvuQVtnyYmssmnp8
|
||||||
D3prp5BvX4v3IoA5Xx1Kkm2tM4yIkJrfZFX+B+BGjpyCt6HU+yz+i7gtSjtZ5Ivp
|
JHovYkr87giDjEgvlrC84Lez32ZhEhORRu5NGEDeZ1OewbkXGyQtbcBQYNAxgnOc
|
||||||
npvsJ0SseSz9AXCIfofFxqpO40VrGRGK3bKyTDaZjvybt7+5IMb4dUyzKMdjujjL
|
O44MTTPhEdz4/A0xwzEe+yIOxWIAWuEM2rclXpZBW/MEK41gZ3C04KcX5R0KRdj2
|
||||||
StKP0S+W2phEaNWHLEzXA3AXOJ+nRN6oplso0BNtyiC9sWKSJUWbUqmdZXmbVuB6
|
PTTH7vJ33yRC4hKtWetwMvsUrewrRKVcUgaeFykDAlgIDoSWvG0nzb70AWSoNcj7
|
||||||
vZDb5Ae9KLgeHeb37HUdFbNs5ruspfdoDaXZzUI2zM2M8A0NRzxQJUGbDxqyPvPU
|
krLlwEc2WLGy/kCYWppnfYKafEJXpgblHrDFKlWvte68yrvGdCsWRLQ2uUF0xokQ
|
||||||
Er84O1P6A6WQ1JlOpljGB6fprgF7Su/HHYesEYPbTUoV/WrcYTVdoOiC7K5jNgRV
|
Ig4u2bApyWNroxEtjHwUp1VeJuZBQkfg+vIW+t3moQpMtlhy4aai/oGIxI5TIB82
|
||||||
apbng8NNDvaQvsJwKgeRDonzxsMG21Iqd0/ekaRp+t8BwX6kHJtkadGUkF5aDoWe
|
nv8TPVczjHmmE3hwL6nZ5OfbFyWpRFvKLtXcaAKMi2HqOLRkQhqjjJUCO9Wyhu1B
|
||||||
cnyk8baN/JAVuGv4IN8K7dtKBOTmKxPFtyPHAl6rUlc/oKnQ/36MoRTXJwiqRCGn
|
kX8RAeKLl3S7gRyhuOB5JNUGEpQ389MdbUX5S12Qp1xTDS+otbC8tYS1gu0OOOWo
|
||||||
aSrjaU++9M2VC6zBecCERYECAwEAAQ==
|
wxbuF5+Ci2SYgSHv/3zXKoMCAwEAAQ==
|
||||||
-----END rsa public key-----
|
-----END rsa public key-----
|
||||||
|
|||||||
@@ -64,28 +64,95 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMinute add or sub minute to the time.
|
// AddMinute add or sub minutes to the time.
|
||||||
// Play: https://go.dev/play/p/nT1heB1KUUK
|
// Play: https://go.dev/play/p/nT1heB1KUUK
|
||||||
func AddMinute(t time.Time, minute int64) time.Time {
|
func AddMinute(t time.Time, minutes int64) time.Time {
|
||||||
return t.Add(time.Minute * time.Duration(minute))
|
return t.Add(time.Minute * time.Duration(minutes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHour add or sub hour to the time.
|
// AddHour add or sub hours to the time.
|
||||||
// Play: https://go.dev/play/p/rcMjd7OCsi5
|
// Play: https://go.dev/play/p/rcMjd7OCsi5
|
||||||
func AddHour(t time.Time, hour int64) time.Time {
|
func AddHour(t time.Time, hours int64) time.Time {
|
||||||
return t.Add(time.Hour * time.Duration(hour))
|
return t.Add(time.Hour * time.Duration(hours))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDay add or sub day to the time.
|
// AddDay add or sub days to the time.
|
||||||
// Play: https://go.dev/play/p/dIGbs_uTdFa
|
// Play: https://go.dev/play/p/dIGbs_uTdFa
|
||||||
func AddDay(t time.Time, day int64) time.Time {
|
func AddDay(t time.Time, days int64) time.Time {
|
||||||
return t.Add(24 * time.Hour * time.Duration(day))
|
return t.Add(24 * time.Hour * time.Duration(days))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWeek add or sub weeks to the time.
|
||||||
|
// play: todo
|
||||||
|
func AddWeek(t time.Time, weeks int64) time.Time {
|
||||||
|
return t.Add(7 * 24 * time.Hour * time.Duration(weeks))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMonth add or sub months to the time.
|
||||||
|
// Play: todo
|
||||||
|
func AddMonth(t time.Time, months int64) time.Time {
|
||||||
|
return t.AddDate(0, int(months), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddYear add or sub year to the time.
|
// AddYear add or sub year to the time.
|
||||||
// Play: https://go.dev/play/p/MqW2ujnBx10
|
// Play: https://go.dev/play/p/MqW2ujnBx10
|
||||||
func AddYear(t time.Time, year int64) time.Time {
|
func AddYear(t time.Time, year int64) time.Time {
|
||||||
return t.Add(365 * 24 * time.Hour * time.Duration(year))
|
return t.AddDate(int(year), 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDaySafe add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
// Play: todo
|
||||||
|
func AddDaySafe(t time.Time, days int) time.Time {
|
||||||
|
t = t.AddDate(0, 0, days)
|
||||||
|
year, month, day := t.Date()
|
||||||
|
|
||||||
|
lastDayOfMonth := time.Date(year, month+1, 0, 0, 0, 0, 0, t.Location()).Day()
|
||||||
|
|
||||||
|
if day > lastDayOfMonth {
|
||||||
|
t = time.Date(year, month, lastDayOfMonth, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMonthSafe add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
// Play: todo
|
||||||
|
func AddMonthSafe(t time.Time, months int) time.Time {
|
||||||
|
year := t.Year()
|
||||||
|
month := int(t.Month()) + months
|
||||||
|
|
||||||
|
for month > 12 {
|
||||||
|
month -= 12
|
||||||
|
year++
|
||||||
|
}
|
||||||
|
for month < 1 {
|
||||||
|
month += 12
|
||||||
|
year--
|
||||||
|
}
|
||||||
|
|
||||||
|
daysInMonth := time.Date(year, time.Month(month+1), 0, 0, 0, 0, 0, time.UTC).Day()
|
||||||
|
|
||||||
|
day := t.Day()
|
||||||
|
if day > daysInMonth {
|
||||||
|
day = daysInMonth
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Date(year, time.Month(month), day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddYearSafe add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.
|
||||||
|
// Play: todo
|
||||||
|
func AddYearSafe(t time.Time, years int) time.Time {
|
||||||
|
year, month, day := t.Date()
|
||||||
|
year += years
|
||||||
|
|
||||||
|
if month == time.February && day == 29 {
|
||||||
|
if !IsLeapYear(year) {
|
||||||
|
day = 28
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Date(year, month, day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNowDate return format yyyy-mm-dd of current date.
|
// GetNowDate return format yyyy-mm-dd of current date.
|
||||||
|
|||||||
@@ -7,71 +7,141 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ExampleAddDay() {
|
func ExampleAddDay() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
tomorrow := AddDay(now, 1)
|
after1Day := AddDay(date, 1)
|
||||||
diff1 := tomorrow.Sub(now)
|
before1Day := AddDay(date, -1)
|
||||||
|
|
||||||
yesterday := AddDay(now, -1)
|
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := yesterday.Sub(now)
|
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 24h0m0s
|
// 2021-01-02 00:00:00
|
||||||
// -24h0m0s
|
// 2020-12-31 00:00:00
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAddWeek() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Weeks := AddWeek(date, 2)
|
||||||
|
before2Weeks := AddWeek(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-01-15
|
||||||
|
// 2020-12-18
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAddMonth() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Months := AddMonth(date, 2)
|
||||||
|
before2Months := AddMonth(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Months.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Months.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-03-01
|
||||||
|
// 2020-11-01
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleAddHour() {
|
func ExampleAddHour() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Hours := AddHour(now, 2)
|
after2Hours := AddHour(date, 2)
|
||||||
diff1 := after2Hours.Sub(now)
|
before2Hours := AddHour(date, -2)
|
||||||
|
|
||||||
before2Hours := AddHour(now, -2)
|
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Hours.Sub(now)
|
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2h0m0s
|
// 2021-01-01 02:00:00
|
||||||
// -2h0m0s
|
// 2020-12-31 22:00:00
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleAddMinute() {
|
func ExampleAddMinute() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Minutes := AddMinute(now, 2)
|
after2Minutes := AddMinute(date, 2)
|
||||||
diff1 := after2Minutes.Sub(now)
|
before2Minutes := AddMinute(date, -2)
|
||||||
|
|
||||||
before2Minutes := AddMinute(now, -2)
|
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Minutes.Sub(now)
|
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2m0s
|
// 2021-01-01 00:02:00
|
||||||
// -2m0s
|
// 2020-12-31 23:58:00
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleAddYear() {
|
func ExampleAddYear() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
after1Year := AddYear(now, 1)
|
after2Years := AddYear(date, 2)
|
||||||
diff1 := after1Year.Sub(now)
|
before2Years := AddYear(date, -2)
|
||||||
|
|
||||||
before1Year := AddYear(now, -1)
|
fmt.Println(after2Years.Format("2006-01-02"))
|
||||||
diff2 := before1Year.Sub(now)
|
fmt.Println(before2Years.Format("2006-01-02"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 8760h0m0s
|
// 2023-01-01
|
||||||
// -8760h0m0s
|
// 2019-01-01
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAddDaySafe() {
|
||||||
|
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result1 := AddDaySafe(leapYearDate1, 1)
|
||||||
|
|
||||||
|
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||||
|
result2 := AddDaySafe(leapYearDate2, -1)
|
||||||
|
|
||||||
|
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||||
|
result3 := AddDaySafe(nonLeapYearDate1, 1)
|
||||||
|
|
||||||
|
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||||
|
result4 := AddDaySafe(nonLeaYearDate2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
fmt.Println(result3.Format("2006-01-02"))
|
||||||
|
fmt.Println(result4.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2024-03-01
|
||||||
|
// 2024-02-29
|
||||||
|
// 2025-03-01
|
||||||
|
// 2025-02-28
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAddMonthSafe() {
|
||||||
|
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||||
|
result1 := AddMonthSafe(date1, 1)
|
||||||
|
|
||||||
|
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result2 := AddMonthSafe(date2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2025-02-28
|
||||||
|
// 2024-01-29
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAddYearSafe() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||||
|
|
||||||
|
result1 := AddYearSafe(date, 1)
|
||||||
|
result2 := AddYearSafe(date, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-02-28
|
||||||
|
// 2019-02-28
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleGetNowDate() {
|
func ExampleGetNowDate() {
|
||||||
|
|||||||
@@ -9,78 +9,427 @@ import (
|
|||||||
|
|
||||||
func TestAddYear(t *testing.T) {
|
func TestAddYear(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAddDay")
|
assert := internal.NewAssert(t, "TestAddDay")
|
||||||
|
|
||||||
now := time.Now()
|
tests := []struct {
|
||||||
after2Years := AddYear(now, 1)
|
inputDate string
|
||||||
diff1 := after2Years.Sub(now)
|
years int
|
||||||
assert.Equal(float64(8760), diff1.Hours())
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: 1,
|
||||||
|
expected: "2022-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: -1,
|
||||||
|
expected: "2020-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: 0,
|
||||||
|
expected: "2021-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: 2,
|
||||||
|
expected: "2023-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: 3,
|
||||||
|
expected: "2024-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
years: 4,
|
||||||
|
expected: "2025-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
before2Years := AddYear(now, -1)
|
for _, tt := range tests {
|
||||||
diff2 := before2Years.Sub(now)
|
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||||
assert.Equal(float64(-8760), diff2.Hours())
|
result := AddYear(date, int64(tt.years))
|
||||||
}
|
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
func TestBetweenSeconds(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
|
||||||
|
|
||||||
today := time.Now()
|
|
||||||
tomorrow := AddDay(today, 1)
|
|
||||||
yesterday := AddDay(today, -1)
|
|
||||||
|
|
||||||
result1 := BetweenSeconds(today, tomorrow)
|
|
||||||
result2 := BetweenSeconds(today, yesterday)
|
|
||||||
|
|
||||||
assert.Equal(int64(86400), result1)
|
|
||||||
assert.Equal(int64(-86400), result2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddDay(t *testing.T) {
|
func TestAddDay(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAddDay")
|
assert := internal.NewAssert(t, "TestAddDay")
|
||||||
|
|
||||||
now := time.Now()
|
tests := []struct {
|
||||||
after2Days := AddDay(now, 2)
|
inputDate string
|
||||||
diff1 := after2Days.Sub(now)
|
days int
|
||||||
assert.Equal(float64(48), diff1.Hours())
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: 1,
|
||||||
|
expected: "2021-01-02 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: -1,
|
||||||
|
expected: "2020-12-31 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: 0,
|
||||||
|
expected: "2021-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: 2,
|
||||||
|
expected: "2021-01-03 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: 3,
|
||||||
|
expected: "2021-01-04 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
days: 4,
|
||||||
|
expected: "2021-01-05 00:00:00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
before2Days := AddDay(now, -2)
|
for _, tt := range tests {
|
||||||
diff2 := before2Days.Sub(now)
|
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||||
assert.Equal(float64(-48), diff2.Hours())
|
result := AddDay(date, int64(tt.days))
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddHour(t *testing.T) {
|
func TestAddHour(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAddHour")
|
assert := internal.NewAssert(t, "TestAddHour")
|
||||||
|
|
||||||
now := time.Now()
|
tests := []struct {
|
||||||
after2Hours := AddHour(now, 2)
|
inputDate string
|
||||||
diff1 := after2Hours.Sub(now)
|
hours int
|
||||||
assert.Equal(float64(2), diff1.Hours())
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 1,
|
||||||
|
expected: "2021-01-01 01:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: -1,
|
||||||
|
expected: "2020-12-31 23:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 0,
|
||||||
|
expected: "2021-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 24,
|
||||||
|
expected: "2021-01-02 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 25,
|
||||||
|
expected: "2021-01-02 01:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 48,
|
||||||
|
expected: "2021-01-03 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
hours: 49,
|
||||||
|
expected: "2021-01-03 01:00:00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||||
|
result := AddHour(date, int64(tt.hours))
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
|
|
||||||
before2Hours := AddHour(now, -2)
|
|
||||||
diff2 := before2Hours.Sub(now)
|
|
||||||
assert.Equal(float64(-2), diff2.Hours())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddMinute(t *testing.T) {
|
func TestAddMinute(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestAddMinute")
|
assert := internal.NewAssert(t, "TestAddMinute")
|
||||||
|
|
||||||
now := time.Now()
|
tests := []struct {
|
||||||
after2Minutes := AddMinute(now, 2)
|
inputDate string
|
||||||
diff1 := after2Minutes.Sub(now)
|
minutes int
|
||||||
assert.Equal(float64(2), diff1.Minutes())
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 1,
|
||||||
|
expected: "2021-01-01 00:01:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: -1,
|
||||||
|
expected: "2020-12-31 23:59:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 0,
|
||||||
|
expected: "2021-01-01 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 60,
|
||||||
|
expected: "2021-01-01 01:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 61,
|
||||||
|
expected: "2021-01-01 01:01:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 1440,
|
||||||
|
expected: "2021-01-02 00:00:00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01 00:00:00",
|
||||||
|
minutes: 1441,
|
||||||
|
expected: "2021-01-02 00:01:00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
before2Minutes := AddMinute(now, -2)
|
for _, tt := range tests {
|
||||||
diff2 := before2Minutes.Sub(now)
|
date, _ := time.Parse("2006-01-02 15:04:05", tt.inputDate)
|
||||||
assert.Equal(float64(-2), diff2.Minutes())
|
result := AddMinute(date, int64(tt.minutes))
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddWeek(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddWeek")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
inputDate string
|
||||||
|
weeks int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: 1,
|
||||||
|
expected: "2021-01-08",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: -1,
|
||||||
|
expected: "2020-12-25",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: 0,
|
||||||
|
expected: "2021-01-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: 52,
|
||||||
|
expected: "2021-12-31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: 53,
|
||||||
|
expected: "2022-01-07",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
weeks: 104,
|
||||||
|
expected: "2022-12-30",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||||
|
result := AddWeek(date, int64(tt.weeks))
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddMonth(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddMonth")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
inputDate string
|
||||||
|
months int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: 1,
|
||||||
|
expected: "2021-02-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: -1,
|
||||||
|
expected: "2020-12-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: 0,
|
||||||
|
expected: "2021-01-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: 12,
|
||||||
|
expected: "2022-01-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: 13,
|
||||||
|
expected: "2022-02-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2021-01-01",
|
||||||
|
months: 24,
|
||||||
|
expected: "2023-01-01",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||||
|
result := AddMonth(date, int64(tt.months))
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddDaySafe(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddDaySafe")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
inputDate string
|
||||||
|
days int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"2025-01-31", 10, "2025-02-10"},
|
||||||
|
{"2025-01-01", 30, "2025-01-31"},
|
||||||
|
{"2025-01-31", 1, "2025-02-01"},
|
||||||
|
{"2025-02-28", 1, "2025-03-01"},
|
||||||
|
{"2024-02-29", 1, "2024-03-01"},
|
||||||
|
{"2024-02-29", 365, "2025-02-28"},
|
||||||
|
|
||||||
|
{"2025-01-31", -10, "2025-01-21"},
|
||||||
|
{"2025-01-01", -30, "2024-12-02"},
|
||||||
|
{"2025-02-01", -1, "2025-01-31"},
|
||||||
|
{"2025-03-01", -1, "2025-02-28"},
|
||||||
|
{"2024-03-01", -1, "2024-02-29"},
|
||||||
|
|
||||||
|
{"2025-01-31", -31, "2024-12-31"},
|
||||||
|
{"2025-12-31", 1, "2026-01-01"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||||
|
result := AddDaySafe(date, tt.days)
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddMonthSafe(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddMonthSafe")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
inputDate string
|
||||||
|
months int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2025-01-31",
|
||||||
|
months: 1,
|
||||||
|
expected: "2025-02-28",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2025-01-31",
|
||||||
|
months: -1,
|
||||||
|
expected: "2024-12-31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2025-12-31",
|
||||||
|
months: 1,
|
||||||
|
expected: "2026-01-31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2025-01-31",
|
||||||
|
months: -1,
|
||||||
|
expected: "2024-12-31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2024-02-29",
|
||||||
|
months: 1,
|
||||||
|
expected: "2024-03-29",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2024-02-29",
|
||||||
|
months: -1,
|
||||||
|
expected: "2024-01-29",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||||
|
result := AddMonthSafe(date, tt.months)
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddYearSafe(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddYearSafe")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
inputDate string
|
||||||
|
years int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputDate: "2020-02-29",
|
||||||
|
years: 1,
|
||||||
|
expected: "2021-02-28",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2020-02-29",
|
||||||
|
years: 2,
|
||||||
|
expected: "2022-02-28",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2020-02-29",
|
||||||
|
years: -1,
|
||||||
|
expected: "2019-02-28",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputDate: "2020-02-29",
|
||||||
|
years: -2,
|
||||||
|
expected: "2018-02-28",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
date, _ := time.Parse("2006-01-02", tt.inputDate)
|
||||||
|
result := AddYearSafe(date, tt.years)
|
||||||
|
assert.Equal(tt.expected, result.Format("2006-01-02"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetNowDate(t *testing.T) {
|
func TestGetNowDate(t *testing.T) {
|
||||||
@@ -578,3 +927,19 @@ func TestMaxMin(t *testing.T) {
|
|||||||
assert.Equal(oneMinuteAgo, min)
|
assert.Equal(oneMinuteAgo, min)
|
||||||
assert.Equal(oneMinuteAfter, max)
|
assert.Equal(oneMinuteAfter, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBetweenSeconds(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||||
|
|
||||||
|
today := time.Now()
|
||||||
|
tomorrow := AddDay(today, 1)
|
||||||
|
yesterday := AddDay(today, -1)
|
||||||
|
|
||||||
|
result1 := BetweenSeconds(today, tomorrow)
|
||||||
|
result2 := BetweenSeconds(today, yesterday)
|
||||||
|
|
||||||
|
assert.Equal(int64(86400), result1)
|
||||||
|
assert.Equal(int64(-86400), result2)
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,9 +23,14 @@ import (
|
|||||||
## 目录
|
## 目录
|
||||||
|
|
||||||
- [AddDay](#AddDay)
|
- [AddDay](#AddDay)
|
||||||
|
- [AddWeek](#AddWeek)
|
||||||
|
- [AddMonth](#AddMonth)
|
||||||
- [AddHour](#AddHour)
|
- [AddHour](#AddHour)
|
||||||
- [AddMinute](#AddMinute)
|
- [AddMinute](#AddMinute)
|
||||||
- [AddYear](#AddYear)
|
- [AddYear](#AddYear)
|
||||||
|
- [AddDaySafe](#AddDaySafe)
|
||||||
|
- [AddMonthSafe](#AddMonthSafe)
|
||||||
|
- [AddYearSafe](#AddYearSafe)
|
||||||
- [BeginOfMinute](#BeginOfMinute)
|
- [BeginOfMinute](#BeginOfMinute)
|
||||||
- [BeginOfHour](#BeginOfHour)
|
- [BeginOfHour](#BeginOfHour)
|
||||||
- [BeginOfDay](#BeginOfDay)
|
- [BeginOfDay](#BeginOfDay)
|
||||||
@@ -109,7 +114,7 @@ import (
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func AddDay(t time.Time, day int64) time.Time
|
func AddDay(t time.Time, days int64) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
||||||
@@ -124,20 +129,89 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
tomorrow := datetime.AddDay(now, 1)
|
after1Day := datetime.AddDay(date, 1)
|
||||||
diff1 := tomorrow.Sub(now)
|
before1Day := datetime.AddDay(date, -1)
|
||||||
|
|
||||||
yesterday := datetime.AddDay(now, -1)
|
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := yesterday.Sub(now)
|
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 24h0m0s
|
// 2021-01-02 00:00:00
|
||||||
// -24h0m0s
|
// 2020-12-31 00:00:00
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddWeek">AddWeek</span>
|
||||||
|
|
||||||
|
<p>将日期加/减星期数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddWeek(t time.Time, weeks int64) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Weeks := datetime.AddWeek(date, 2)
|
||||||
|
before2Weeks := datetime.AddWeek(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-01-15
|
||||||
|
// 2020-12-18
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddMonth">AddMonth</span>
|
||||||
|
|
||||||
|
<p>将日期加/减月数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddMonth(t time.Time, months int64) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Months := datetime.AddMonth(date, 2)
|
||||||
|
before2Months := datetime.AddMonth(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Months.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Months.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-03-01
|
||||||
|
// 2020-11-01
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -148,7 +222,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func AddHour(t time.Time, hour int64) time.Time
|
func AddHour(t time.Time, hours int64) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rcMjd7OCsi5)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rcMjd7OCsi5)</span></b>
|
||||||
@@ -163,20 +237,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Hours := datetime.AddHour(now, 2)
|
after2Hours := datetime.AddHour(date, 2)
|
||||||
diff1 := after2Hours.Sub(now)
|
before2Hours := datetime.AddHour(date, -2)
|
||||||
|
|
||||||
before2Hours := datetime.AddHour(now, -2)
|
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Hours.Sub(now)
|
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2h0m0s
|
// 2021-01-01 02:00:00
|
||||||
// -2h0m0s
|
// 2020-12-31 22:00:00
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -187,7 +258,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func AddMinute(t time.Time, minute int64) time.Time
|
func AddMinute(t time.Time, minutes int64) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nT1heB1KUUK)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nT1heB1KUUK)</span></b>
|
||||||
@@ -202,20 +273,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Minutes := datetime.AddMinute(now, 2)
|
after2Minutes := datetime.AddMinute(date, 2)
|
||||||
diff1 := after2Minutes.Sub(now)
|
before2Minutes := datetime.AddMinute(date, -2)
|
||||||
|
|
||||||
before2Minutes := datetime.AddMinute(now, -2)
|
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Minutes.Sub(now)
|
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2m0s
|
// 2021-01-01 00:02:00
|
||||||
// -2m0s
|
// 2020-12-31 23:58:00
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -226,7 +294,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func AddYear(t time.Time, year int64) time.Time
|
func AddYear(t time.Time, years int64) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MqW2ujnBx10)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MqW2ujnBx10)</span></b>
|
||||||
@@ -241,20 +309,137 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
after1Year := datetime.AddYear(now, 1)
|
after2Years := AddYear(date, 2)
|
||||||
diff1 := after1Year.Sub(now)
|
before2Years := AddYear(date, -2)
|
||||||
|
|
||||||
before1Year := datetime.AddYear(now, -1)
|
fmt.Println(after2Years.Format("2006-01-02"))
|
||||||
diff2 := before1Year.Sub(now)
|
fmt.Println(before2Years.Format("2006-01-02"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 8760h0m0s
|
// 2023-01-01
|
||||||
// -8760h0m0s
|
// 2019-01-01
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddDaySafe">AddDaySafe</span>
|
||||||
|
|
||||||
|
<p>增加/减少指定的天数,并确保日期是有效日期。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddDaySafe(t time.Time, days int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result1 := datetime.AddDaySafe(leapYearDate1, 1)
|
||||||
|
|
||||||
|
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||||
|
result2 := datetime.AddDaySafe(leapYearDate2, -1)
|
||||||
|
|
||||||
|
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||||
|
result3 := datetime.AddDaySafe(nonLeapYearDate1, 1)
|
||||||
|
|
||||||
|
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||||
|
result4 := datetime.AddDaySafe(nonLeaYearDate2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
fmt.Println(result3.Format("2006-01-02"))
|
||||||
|
fmt.Println(result4.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2024-03-01
|
||||||
|
// 2024-02-29
|
||||||
|
// 2025-03-01
|
||||||
|
// 2025-02-28
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddMonthSafe">AddMonthSafe</span>
|
||||||
|
|
||||||
|
<p>增加/减少指定的月份,并确保日期是有效日期。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddMonthSafe(t time.Time, months int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||||
|
result1 := datetime.AddMonthSafe(date1, 1)
|
||||||
|
|
||||||
|
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result2 := datetime.AddMonthSafe(date2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2025-02-28
|
||||||
|
// 2024-01-29
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddYearSafe">AddYearSafe</span>
|
||||||
|
|
||||||
|
<p>增加/减少指定的年份,并确保日期是有效日期。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddYearSafe(t time.Time, years int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||||
|
|
||||||
|
result1 := datetime.AddYearSafe(date, 1)
|
||||||
|
result2 := datetime.AddYearSafe(date, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-02-28
|
||||||
|
// 2019-02-28
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
401
docs/api/packages/eventbus.md
Normal file
401
docs/api/packages/eventbus.md
Normal file
@@ -0,0 +1,401 @@
|
|||||||
|
# EventBus
|
||||||
|
|
||||||
|
EventbBus是一个事件总线,用于在应用程序中处理事件。
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go](https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [NewEventBus](#NewEventBus)
|
||||||
|
- [Subscribe](#Subscribe)
|
||||||
|
- [Unsubscribe](#Unsubscribe)
|
||||||
|
- [Publish](#Publish)
|
||||||
|
- [ClearListeners](#ClearListeners)
|
||||||
|
- [ClearListenersByTopic](#ClearListenersByTopic)
|
||||||
|
- [GetListenersCount](#GetListenersCount)
|
||||||
|
- [GetAllListenersCount](#GetAllListenersCount)
|
||||||
|
- [GetEvents](#GetEvents)
|
||||||
|
- [SetErrorHandler](#SetErrorHandler)
|
||||||
|
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
### <span id="NewEventBus">NewEventBus</span>
|
||||||
|
|
||||||
|
<p>创建EventBus实例。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewEventBus[T any]() *EventBus[T]
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Subscribe">Subscribe</span>
|
||||||
|
|
||||||
|
<p>订阅具有特定事件主题和监听函数的事件。支持异步,事件优先级,事件过滤器。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := func(eventData int) bool {
|
||||||
|
return eventData == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, filter)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Unsubscribe">Unsubscribe</span>
|
||||||
|
|
||||||
|
<p>取消订阅具有特定事件主题的事件。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T))
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Unsubscribe("event1", listener)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Publish">Publish</span>
|
||||||
|
|
||||||
|
<p>发布一个带有特定事件主题和数据负载的事件。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Publish(event Event[T])
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ClearListeners">ClearListeners</span>
|
||||||
|
|
||||||
|
<p>清空所有事件监听器。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) ClearListeners()
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListeners()
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ClearListenersByTopic">ClearListenersByTopic</span>
|
||||||
|
|
||||||
|
<p>清空特定事件监听器。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) ClearListenersByTopic(topic string)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListenersByTopic("event1")
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetListenersCount">GetListenersCount</span>
|
||||||
|
|
||||||
|
<p>获取特定事件的监听器数量。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetListenersCount(topic string) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetListenersCount("event1")
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetAllListenersCount">GetAllListenersCount</span>
|
||||||
|
|
||||||
|
<p>获取所有事件的监听器数量。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetAllListenersCount() int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetAllListenersCount()
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetEvents">GetEvents</span>
|
||||||
|
|
||||||
|
<p>获取所有事件的topic。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetEvents() []string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
events := eb.GetEvents()
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
fmt.Println(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// event1
|
||||||
|
// event2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="SetErrorHandler">SetErrorHandler</span>
|
||||||
|
|
||||||
|
<p>设置事件的错误处理函数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) SetErrorHandler(handler func(err error))
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.SetErrorHandler(func(err error) {
|
||||||
|
fmt.Println(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
panic("error")
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -44,6 +44,7 @@ import (
|
|||||||
- [Every](#Every)
|
- [Every](#Every)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [EqualWith](#EqualWith)
|
- [EqualWith](#EqualWith)
|
||||||
|
- [EqualUnordered](#EqualUnordered)
|
||||||
- [Filter](#Filter)
|
- [Filter](#Filter)
|
||||||
- [FilterConcurrent](#FilterConcurrent)
|
- [FilterConcurrent](#FilterConcurrent)
|
||||||
- [Find<sup>deprecated</sup>](#Find)
|
- [Find<sup>deprecated</sup>](#Find)
|
||||||
@@ -69,6 +70,7 @@ import (
|
|||||||
- [FlatMap](#FlatMap)
|
- [FlatMap](#FlatMap)
|
||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
|
- [ReverseCopy](#ReverseCopy)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
- [ReduceConcurrent](#ReduceConcurrent)
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
@@ -77,6 +79,7 @@ import (
|
|||||||
- [ReplaceAll](#ReplaceAll)
|
- [ReplaceAll](#ReplaceAll)
|
||||||
- [Repeat](#Repeat)
|
- [Repeat](#Repeat)
|
||||||
- [Shuffle](#Shuffle)
|
- [Shuffle](#Shuffle)
|
||||||
|
- [ShuffleCopy](#ShuffleCopy)
|
||||||
- [IsAscending](#IsAscending)
|
- [IsAscending](#IsAscending)
|
||||||
- [IsDescending](#IsDescending)
|
- [IsDescending](#IsDescending)
|
||||||
- [IsSorted](#IsSorted)
|
- [IsSorted](#IsSorted)
|
||||||
@@ -874,6 +877,37 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EqualUnordered">EqualUnordered</span>
|
||||||
|
|
||||||
|
<p>检查两个切片是否相等,元素数量相同,值相等,不考虑元素顺序。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EqualUnordered[T comparable](slice1, slice2 []T) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||||
|
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Filter">Filter</span>
|
### <span id="Filter">Filter</span>
|
||||||
|
|
||||||
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
<p>返回切片中通过predicate函数真值测试的所有元素</p>
|
||||||
@@ -1728,6 +1762,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ReverseCopy">ReverseCopy</span>
|
||||||
|
|
||||||
|
<p>反转切片中的元素顺序, 不改变原slice。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReverseCopy[T any](slice []T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
strs := []string{"a", "b", "c", "d"}
|
||||||
|
|
||||||
|
reversedStrs := slice.ReverseCopy(strs)
|
||||||
|
|
||||||
|
fmt.Println(reversedStrs)
|
||||||
|
fmt.Println(strs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [d c b a]
|
||||||
|
// [a b c d]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Reduce">Reduce</span>
|
### <span id="Reduce">Reduce</span>
|
||||||
|
|
||||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果。</p>
|
<p>将切片中的元素依次运行iteratee函数,返回运行结果。</p>
|
||||||
@@ -1962,7 +2028,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Shuffle">Shuffle</span>
|
### <span id="Shuffle">Shuffle</span>
|
||||||
|
|
||||||
<p>随机打乱切片中的元素顺序</p>
|
<p>随机打乱切片中的元素顺序。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -1989,6 +2055,37 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ShuffleCopy">ShuffleCopy</span>
|
||||||
|
|
||||||
|
<p>随机打乱切片中的元素顺序, 不改变原切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ShuffleCopy[T any](slice []T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
|
result := slice.ShuffleCopy(nums)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(nums)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [3 1 5 4 2] (random order)
|
||||||
|
// [1 2 3 4 5]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsAscending">IsAscending</span>
|
### <span id="IsAscending">IsAscending</span>
|
||||||
|
|
||||||
<p>检查切片元素是否按升序排列。</p>
|
<p>检查切片元素是否按升序排列。</p>
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import (
|
|||||||
- [TemplateReplace](#TemplateReplace)
|
- [TemplateReplace](#TemplateReplace)
|
||||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||||
- [ExtractContent](#ExtractContent)
|
- [ExtractContent](#ExtractContent)
|
||||||
|
- [FindAllOccurrences](#FindAllOccurrences)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -1708,7 +1709,7 @@ func main() {
|
|||||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -1741,7 +1742,7 @@ func main() {
|
|||||||
func ExtractContent(s, start, end string) []string
|
func ExtractContent(s, start, end string) []string
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Ay9UIk7Rum9)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Ay9UIk7Rum9)</span></b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -1760,3 +1761,31 @@ func main() {
|
|||||||
// [content1 content2 content1]
|
// [content1 content2 content1]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="FindAllOccurrences">FindAllOccurrences</span>
|
||||||
|
|
||||||
|
<p>返回子字符串在字符串中所有出现的位置。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func FindAllOccurrences(str, substr string) []int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := strutil.FindAllOccurrences("ababab", "ab")
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [0 2 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -49,6 +49,7 @@ import (
|
|||||||
- [IsIp](#IsIp)
|
- [IsIp](#IsIp)
|
||||||
- [IsIpV4](#IsIpV4)
|
- [IsIpV4](#IsIpV4)
|
||||||
- [IsIpV6](#IsIpV6)
|
- [IsIpV6](#IsIpV6)
|
||||||
|
- [IsIpPort](#IsIpPort)
|
||||||
- [IsStrongPassword](#IsStrongPassword)
|
- [IsStrongPassword](#IsStrongPassword)
|
||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
@@ -990,6 +991,43 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsIpPort">IsIpPort</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否是ip:port格式。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsIpPort(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsIpPort("127.0.0.1:8080")
|
||||||
|
result2 := validator.IsIpPort("[0:0:0:0:0:0:0:1]:8080")
|
||||||
|
result3 := validator.IsIpPort(":8080")
|
||||||
|
result4 := validator.IsIpPort("::0:0:0:0:")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsStrongPassword">IsStrongPassword</span>
|
### <span id="IsStrongPassword">IsStrongPassword</span>
|
||||||
|
|
||||||
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))。</p>
|
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))。</p>
|
||||||
|
|||||||
@@ -24,9 +24,14 @@ import (
|
|||||||
## Index
|
## Index
|
||||||
|
|
||||||
- [AddDay](#AddDay)
|
- [AddDay](#AddDay)
|
||||||
|
- [AddWeek](#AddWeek)
|
||||||
|
- [AddMonth](#AddMonth)
|
||||||
- [AddHour](#AddHour)
|
- [AddHour](#AddHour)
|
||||||
- [AddMinute](#AddMinute)
|
- [AddMinute](#AddMinute)
|
||||||
- [AddYear](#AddYear)
|
- [AddYear](#AddYear)
|
||||||
|
- [AddDaySafe](#AddDaySafe)
|
||||||
|
- [AddMonthSafe](#AddMonthSafe)
|
||||||
|
- [AddYearSafe](#AddYearSafe)
|
||||||
- [BeginOfMinute](#BeginOfMinute)
|
- [BeginOfMinute](#BeginOfMinute)
|
||||||
- [BeginOfHour](#BeginOfHour)
|
- [BeginOfHour](#BeginOfHour)
|
||||||
- [BeginOfDay](#BeginOfDay)
|
- [BeginOfDay](#BeginOfDay)
|
||||||
@@ -111,7 +116,7 @@ import (
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func AddDay(t time.Time, day int64) time.Time
|
func AddDay(t time.Time, days int64) time.Time
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
||||||
@@ -126,20 +131,89 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
tomorrow := datetime.AddDay(now, 1)
|
after1Day := datetime.AddDay(date, 1)
|
||||||
diff1 := tomorrow.Sub(now)
|
before1Day := datetime.AddDay(date, -1)
|
||||||
|
|
||||||
yesterday := datetime.AddDay(now, -1)
|
fmt.Println(after1Day.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := yesterday.Sub(now)
|
fmt.Println(before1Day.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 24h0m0s
|
// 2021-01-02 00:00:00
|
||||||
// -24h0m0s
|
// 2020-12-31 00:00:00
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddWeek">AddWeek</span>
|
||||||
|
|
||||||
|
<p>Add or sub weeks to time.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddWeek(t time.Time, weeks int64) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Weeks := datetime.AddWeek(date, 2)
|
||||||
|
before2Weeks := datetime.AddWeek(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Weeks.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Weeks.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-01-15
|
||||||
|
// 2020-12-18
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddMonth">AddMonth</span>
|
||||||
|
|
||||||
|
<p>Add or sub months to time.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddMonth(t time.Time, months int64) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
|
after2Months := datetime.AddMonth(date, 2)
|
||||||
|
before2Months := datetime.AddMonth(date, -2)
|
||||||
|
|
||||||
|
fmt.Println(after2Months.Format("2006-01-02"))
|
||||||
|
fmt.Println(before2Months.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-03-01
|
||||||
|
// 2020-11-01
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -165,20 +239,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Hours := datetime.AddHour(now, 2)
|
after2Hours := datetime.AddHour(date, 2)
|
||||||
diff1 := after2Hours.Sub(now)
|
before2Hours := datetime.AddHour(date, -2)
|
||||||
|
|
||||||
before2Hours := datetime.AddHour(now, -2)
|
fmt.Println(after2Hours.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Hours.Sub(now)
|
fmt.Println(before2Hours.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2h0m0s
|
// 2021-01-01 02:00:00
|
||||||
// -2h0m0s
|
// 2020-12-31 22:00:00
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -204,20 +275,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02 15:04:05", "2021-01-01 00:00:00")
|
||||||
|
|
||||||
after2Minutes := datetime.AddMinute(now, 2)
|
after2Minutes := datetime.AddMinute(date, 2)
|
||||||
diff1 := after2Minutes.Sub(now)
|
before2Minutes := datetime.AddMinute(date, -2)
|
||||||
|
|
||||||
before2Minutes := datetime.AddMinute(now, -2)
|
fmt.Println(after2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
diff2 := before2Minutes.Sub(now)
|
fmt.Println(before2Minutes.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 2m0s
|
// 2021-01-01 00:02:00
|
||||||
// -2m0s
|
// 2020-12-31 23:58:00
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -243,20 +311,137 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
now := time.Now()
|
date, _ := time.Parse("2006-01-02", "2021-01-01")
|
||||||
|
|
||||||
after1Year := datetime.AddYear(now, 1)
|
after2Years := AddYear(date, 2)
|
||||||
diff1 := after1Year.Sub(now)
|
before2Years := AddYear(date, -2)
|
||||||
|
|
||||||
before1Year := datetime.AddYear(now, -1)
|
fmt.Println(after2Years.Format("2006-01-02"))
|
||||||
diff2 := before1Year.Sub(now)
|
fmt.Println(before2Years.Format("2006-01-02"))
|
||||||
|
|
||||||
fmt.Println(diff1)
|
|
||||||
fmt.Println(diff2)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 8760h0m0s
|
// 2023-01-01
|
||||||
// -8760h0m0s
|
// 2019-01-01
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddDaySafe">AddDaySafe</span>
|
||||||
|
|
||||||
|
<p>Add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddDaySafe(t time.Time, days int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result1 := datetime.AddDaySafe(leapYearDate1, 1)
|
||||||
|
|
||||||
|
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
|
||||||
|
result2 := datetime.AddDaySafe(leapYearDate2, -1)
|
||||||
|
|
||||||
|
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
|
||||||
|
result3 := datetime.AddDaySafe(nonLeapYearDate1, 1)
|
||||||
|
|
||||||
|
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
|
||||||
|
result4 := datetime.AddDaySafe(nonLeaYearDate2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
fmt.Println(result3.Format("2006-01-02"))
|
||||||
|
fmt.Println(result4.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2024-03-01
|
||||||
|
// 2024-02-29
|
||||||
|
// 2025-03-01
|
||||||
|
// 2025-02-28
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddMonthSafe">AddMonthSafe</span>
|
||||||
|
|
||||||
|
<p>Add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddMonthSafe(t time.Time, months int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date1, _ := time.Parse("2006-01-02", "2025-01-31")
|
||||||
|
result1 := datetime.AddMonthSafe(date1, 1)
|
||||||
|
|
||||||
|
date2, _ := time.Parse("2006-01-02", "2024-02-29")
|
||||||
|
result2 := datetime.AddMonthSafe(date2, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2025-02-28
|
||||||
|
// 2024-01-29
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AddYearSafe">AddYearSafe</span>
|
||||||
|
|
||||||
|
<p>Add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AddYearSafe(t time.Time, years int) time.Time
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"github.com/duke-git/lancet/v2/datetime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
date, _ := time.Parse("2006-01-02", "2020-02-29")
|
||||||
|
|
||||||
|
result1 := datetime.AddYearSafe(date, 1)
|
||||||
|
result2 := datetime.AddYearSafe(date, -1)
|
||||||
|
|
||||||
|
fmt.Println(result1.Format("2006-01-02"))
|
||||||
|
fmt.Println(result2.Format("2006-01-02"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2021-02-28
|
||||||
|
// 2019-02-28
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1342,7 +1527,7 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
||||||
|
|
||||||
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
|
|||||||
401
docs/en/api/packages/eventbus.md
Normal file
401
docs/en/api/packages/eventbus.md
Normal file
@@ -0,0 +1,401 @@
|
|||||||
|
# EventBus
|
||||||
|
|
||||||
|
EventBus is an event bus used for handling events within an application.
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go](https://github.com/duke-git/lancet/blob/main/eventbus/eventbus.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [NewEventBus](#NewEventBus)
|
||||||
|
- [Subscribe](#Subscribe)
|
||||||
|
- [Unsubscribe](#Unsubscribe)
|
||||||
|
- [Publish](#Publish)
|
||||||
|
- [ClearListeners](#ClearListeners)
|
||||||
|
- [ClearListenersByTopic](#ClearListenersByTopic)
|
||||||
|
- [GetListenersCount](#GetListenersCount)
|
||||||
|
- [GetAllListenersCount](#GetAllListenersCount)
|
||||||
|
- [GetEvents](#GetEvents)
|
||||||
|
- [SetErrorHandler](#SetErrorHandler)
|
||||||
|
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### <span id="NewEventBus">NewEventBus</span>
|
||||||
|
|
||||||
|
<p>Create an EventBus instance.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewEventBus[T any]() *EventBus[T]
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Subscribe">Subscribe</span>
|
||||||
|
|
||||||
|
<p>Subscribes to an event with a specific event topic and listener function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := func(eventData int) bool {
|
||||||
|
return eventData == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, filter)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Unsubscribe">Unsubscribe</span>
|
||||||
|
|
||||||
|
<p>Unsubscribes from an event with a specific event topic and listener function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T))
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Unsubscribe("event1", listener)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Publish">Publish</span>
|
||||||
|
|
||||||
|
<p>Publishes an event with a specific event topic and data payload.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) Publish(event Event[T])
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ClearListeners">ClearListeners</span>
|
||||||
|
|
||||||
|
<p>Clears all the listeners.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) ClearListeners()
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListeners()
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ClearListenersByTopic">ClearListenersByTopic</span>
|
||||||
|
|
||||||
|
<p>Clears all the listeners by topic.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) ClearListenersByTopic(topic string)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListenersByTopic("event1")
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetListenersCount">GetListenersCount</span>
|
||||||
|
|
||||||
|
<p>Returns the number of listeners for a specific event topic.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetListenersCount(topic string) int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetListenersCount("event1")
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetAllListenersCount">GetAllListenersCount</span>
|
||||||
|
|
||||||
|
<p>Returns the total number of all listeners.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetAllListenersCount() int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetAllListenersCount()
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="GetEvents">GetEvents</span>
|
||||||
|
|
||||||
|
<p>Returns all the events topics.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) GetEvents() []string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
events := eb.GetEvents()
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
fmt.Println(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// event1
|
||||||
|
// event2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="SetErrorHandler">SetErrorHandler</span>
|
||||||
|
|
||||||
|
<p>Sets the error handler function.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (eb *EventBus[T]) SetErrorHandler(handler func(err error))
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/eventbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eb := eventbus.NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.SetErrorHandler(func(err error) {
|
||||||
|
fmt.Println(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
panic("error")
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -43,6 +43,7 @@ import (
|
|||||||
- [DropRightWhile](#DropRightWhile)
|
- [DropRightWhile](#DropRightWhile)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [EqualWith](#EqualWith)
|
- [EqualWith](#EqualWith)
|
||||||
|
- [EqualUnordered](#EqualUnordered)
|
||||||
- [Every](#Every)
|
- [Every](#Every)
|
||||||
- [Filter](#Filter)
|
- [Filter](#Filter)
|
||||||
- [FilterConcurrent](#FilterConcurrent)
|
- [FilterConcurrent](#FilterConcurrent)
|
||||||
@@ -69,6 +70,7 @@ import (
|
|||||||
- [FlatMap](#FlatMap)
|
- [FlatMap](#FlatMap)
|
||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
|
- [ReverseCopy](#ReverseCopy)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
- [ReduceConcurrent](#ReduceConcurrent)
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
@@ -77,6 +79,7 @@ import (
|
|||||||
- [ReplaceAll](#ReplaceAll)
|
- [ReplaceAll](#ReplaceAll)
|
||||||
- [Repeat](#Repeat)
|
- [Repeat](#Repeat)
|
||||||
- [Shuffle](#Shuffle)
|
- [Shuffle](#Shuffle)
|
||||||
|
- [ShuffleCopy](#ShuffleCopy)
|
||||||
- [IsAscending](#IsAscending)
|
- [IsAscending](#IsAscending)
|
||||||
- [IsDescending](#IsDescending)
|
- [IsDescending](#IsDescending)
|
||||||
- [IsSorted](#IsSorted)
|
- [IsSorted](#IsSorted)
|
||||||
@@ -839,6 +842,37 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EqualUnordered">EqualUnordered</span>
|
||||||
|
|
||||||
|
<p>Checks if two slices are equal: the same length and all elements value are equal (unordered).</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EqualUnordered[T comparable](slice1, slice2 []T) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||||
|
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Every">Every</span>
|
### <span id="Every">Every</span>
|
||||||
|
|
||||||
<p>Return true if all of the values in the slice pass the predicate function.</p>
|
<p>Return true if all of the values in the slice pass the predicate function.</p>
|
||||||
@@ -1724,6 +1758,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ReverseCopy">ReverseCopy</span>
|
||||||
|
|
||||||
|
<p>Return a new slice of element order is reversed to the given slice.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReverseCopy[T any](slice []T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
strs := []string{"a", "b", "c", "d"}
|
||||||
|
|
||||||
|
reversedStrs := slice.ReverseCopy(strs)
|
||||||
|
|
||||||
|
fmt.Println(reversedStrs)
|
||||||
|
fmt.Println(strs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [d c b a]
|
||||||
|
// [a b c d]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Reduce">Reduce</span>
|
### <span id="Reduce">Reduce</span>
|
||||||
|
|
||||||
<p>Reduce slice.</p>
|
<p>Reduce slice.</p>
|
||||||
@@ -1986,6 +2052,37 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ShuffleCopy">ShuffleCopy</span>
|
||||||
|
|
||||||
|
<p>Return a new slice with elements shuffled.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ShuffleCopy[T any](slice []T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
|
result := slice.ShuffleCopy(nums)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(nums)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [3 1 5 4 2] (random order)
|
||||||
|
// [1 2 3 4 5]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsAscending">IsAscending</span>
|
### <span id="IsAscending">IsAscending</span>
|
||||||
|
|
||||||
<p>Checks if a slice is ascending order.</p>
|
<p>Checks if a slice is ascending order.</p>
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ import (
|
|||||||
- [Rotate](#Rotate)
|
- [Rotate](#Rotate)
|
||||||
- [TemplateReplace](#TemplateReplace)
|
- [TemplateReplace](#TemplateReplace)
|
||||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||||
- [ExtractContent](#RegexMatchAllGroups)
|
- [ExtractContent](#ExtractContent)
|
||||||
|
- [FindAllOccurrences](#FindAllOccurrences)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -1762,3 +1763,31 @@ func main() {
|
|||||||
// [content1 content2 content1]
|
// [content1 content2 content1]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="FindAllOccurrences">FindAllOccurrences</span>
|
||||||
|
|
||||||
|
<p>Returns the positions of all occurrences of a substring in a string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func FindAllOccurrences(str, substr string) []int
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result := strutil.FindAllOccurrences("ababab", "ab")
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [0 2 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -49,6 +49,7 @@ import (
|
|||||||
- [IsIp](#IsIp)
|
- [IsIp](#IsIp)
|
||||||
- [IsIpV4](#IsIpV4)
|
- [IsIpV4](#IsIpV4)
|
||||||
- [IsIpV6](#IsIpV6)
|
- [IsIpV6](#IsIpV6)
|
||||||
|
- [IsIpPort](#IsIpPort)
|
||||||
- [IsStrongPassword](#IsStrongPassword)
|
- [IsStrongPassword](#IsStrongPassword)
|
||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
@@ -992,6 +993,43 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsIpPort">IsIpPort</span>
|
||||||
|
|
||||||
|
<p>Check if the string is ip:port</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsIpPort(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsIpPort("127.0.0.1:8080")
|
||||||
|
result2 := validator.IsIpPort("[0:0:0:0:0:0:0:1]:8080")
|
||||||
|
result3 := validator.IsIpPort(":8080")
|
||||||
|
result4 := validator.IsIpPort("::0:0:0:0:")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsStrongPassword">IsStrongPassword</span>
|
### <span id="IsStrongPassword">IsStrongPassword</span>
|
||||||
|
|
||||||
<p>Check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?gt<)).</p>
|
<p>Check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?gt<)).</p>
|
||||||
|
|||||||
194
eventbus/eventbus.go
Normal file
194
eventbus/eventbus.go
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
// Copyright 2025 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package eventbus implements a simple event bus.
|
||||||
|
package eventbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is the struct that is passed to the event listener, now it directly uses the generic Payload type.
|
||||||
|
type Event[T any] struct {
|
||||||
|
Topic string
|
||||||
|
Payload T
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventBus is the struct that holds the listeners and the error handler.
|
||||||
|
type EventBus[T any] struct {
|
||||||
|
// listeners map[string][]*EventListener[T]
|
||||||
|
listeners sync.Map
|
||||||
|
mu sync.RWMutex
|
||||||
|
errorHandler func(err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventListener is the struct that holds the listener function and its priority.
|
||||||
|
type EventListener[T any] struct {
|
||||||
|
priority int
|
||||||
|
listener func(eventData T)
|
||||||
|
async bool
|
||||||
|
filter func(eventData T) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventBus creates a new EventBus.
|
||||||
|
// Play: todo
|
||||||
|
func NewEventBus[T any]() *EventBus[T] {
|
||||||
|
return &EventBus[T]{
|
||||||
|
listeners: sync.Map{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe subscribes to an event with a specific event topic and listener function.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) Subscribe(topic string, listener func(eventData T), async bool, priority int, filter func(eventData T) bool) {
|
||||||
|
eb.mu.Lock()
|
||||||
|
defer eb.mu.Unlock()
|
||||||
|
|
||||||
|
el := &EventListener[T]{
|
||||||
|
priority: priority,
|
||||||
|
listener: listener,
|
||||||
|
async: async,
|
||||||
|
filter: filter,
|
||||||
|
}
|
||||||
|
|
||||||
|
listenersInterface, _ := eb.listeners.LoadOrStore(topic, []*EventListener[T]{})
|
||||||
|
listeners := listenersInterface.([]*EventListener[T])
|
||||||
|
|
||||||
|
listeners = append(listeners, el)
|
||||||
|
sort.Slice(listeners, func(i, j int) bool {
|
||||||
|
return listeners[i].priority > listeners[j].priority
|
||||||
|
})
|
||||||
|
|
||||||
|
eb.listeners.Store(topic, listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe unsubscribes from an event with a specific event topic and listener function.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) Unsubscribe(topic string, listener func(eventData T)) {
|
||||||
|
eb.mu.Lock()
|
||||||
|
defer eb.mu.Unlock()
|
||||||
|
|
||||||
|
listenersInterface, ok := eb.listeners.Load(topic)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners := listenersInterface.([]*EventListener[T])
|
||||||
|
listenerPtr := fmt.Sprintf("%p", listener)
|
||||||
|
|
||||||
|
var updatedListeners []*EventListener[T]
|
||||||
|
for _, l := range listeners {
|
||||||
|
if fmt.Sprintf("%p", l.listener) != listenerPtr {
|
||||||
|
updatedListeners = append(updatedListeners, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.listeners.Store(topic, updatedListeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish publishes an event with a specific event topic and data payload.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) Publish(event Event[T]) {
|
||||||
|
eb.mu.RLock()
|
||||||
|
defer eb.mu.RUnlock()
|
||||||
|
|
||||||
|
listenersInterface, exists := eb.listeners.Load(event.Topic)
|
||||||
|
if !exists {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners := listenersInterface.([]*EventListener[T])
|
||||||
|
|
||||||
|
for _, listener := range listeners {
|
||||||
|
if listener.filter != nil && !listener.filter(event.Payload) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if listener.async {
|
||||||
|
go eb.publishToListener(listener, event)
|
||||||
|
} else {
|
||||||
|
eb.publishToListener(listener, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eb *EventBus[T]) publishToListener(listener *EventListener[T], event Event[T]) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil && eb.errorHandler != nil {
|
||||||
|
eb.errorHandler(fmt.Errorf("%v", r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
listener.listener(event.Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetErrorHandler sets the error handler function.
|
||||||
|
func (eb *EventBus[T]) SetErrorHandler(handler func(err error)) {
|
||||||
|
eb.errorHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearListeners clears all the listeners.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) ClearListeners() {
|
||||||
|
eb.mu.Lock()
|
||||||
|
defer eb.mu.Unlock()
|
||||||
|
|
||||||
|
eb.listeners = sync.Map{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearListenersByTopic clears all the listeners by topic.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) ClearListenersByTopic(topic string) {
|
||||||
|
eb.mu.Lock()
|
||||||
|
defer eb.mu.Unlock()
|
||||||
|
|
||||||
|
eb.listeners.Delete(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetListenersCount returns the number of listeners for a specific event topic.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) GetListenersCount(topic string) int {
|
||||||
|
eb.mu.RLock()
|
||||||
|
defer eb.mu.RUnlock()
|
||||||
|
|
||||||
|
listenersInterface, ok := eb.listeners.Load(topic)
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners := listenersInterface.([]*EventListener[T])
|
||||||
|
return len(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllListenersCount returns the total number of listeners.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) GetAllListenersCount() int {
|
||||||
|
eb.mu.RLock()
|
||||||
|
defer eb.mu.RUnlock()
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
eb.listeners.Range(func(key, value interface{}) bool {
|
||||||
|
count += len(value.([]*EventListener[T]))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEvents returns all the events topics.
|
||||||
|
// Play: todo
|
||||||
|
func (eb *EventBus[T]) GetEvents() []string {
|
||||||
|
eb.mu.RLock()
|
||||||
|
defer eb.mu.RUnlock()
|
||||||
|
|
||||||
|
var events []string
|
||||||
|
|
||||||
|
eb.listeners.Range(func(key, value interface{}) bool {
|
||||||
|
events = append(events, key.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return events
|
||||||
|
}
|
||||||
229
eventbus/eventbus_example_test.go
Normal file
229
eventbus/eventbus_example_test.go
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
package eventbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleEventBus_Subscribe() {
|
||||||
|
eb := NewEventBus[string]()
|
||||||
|
eb.Subscribe("event1", func(eventData string) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_Unsubscribe() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Unsubscribe("event1", listener)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_Subscribe_withFilter() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := func(eventData int) bool {
|
||||||
|
return eventData == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, filter)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_Subscribe_withPriority() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 1, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_Subscribe_async() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
fmt.Println(eventData)
|
||||||
|
wg.Done()
|
||||||
|
}, true, 1, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_Publish() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
fmt.Println(eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_ClearListeners() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListeners()
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_ClearListenersByTopic() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.ClearListenersByTopic("event1")
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
fmt.Println(receivedData)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_GetListenersCount() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetListenersCount("event1")
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_SetErrorHandler() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.SetErrorHandler(func(err error) {
|
||||||
|
fmt.Println(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
panic("error")
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_GetAllListenersCount() {
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
count := eb.GetAllListenersCount()
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleEventBus_GetEvents() {
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
events := eb.GetEvents()
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
fmt.Println(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// event1
|
||||||
|
// event2
|
||||||
|
}
|
||||||
219
eventbus/eventbus_test.go
Normal file
219
eventbus/eventbus_test.go
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
package eventbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEventBus_Subscribe(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_Subscribe")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
assert.Equal(1, eventData)
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_Unsubscribe(t *testing.T) {
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_Unsubscribe")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, nil)
|
||||||
|
eb.Unsubscribe("event1", listener)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
assert.Equal(0, receivedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_Subscribe_withFilter(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_Subscribe_withFilter")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData := 0
|
||||||
|
listener := func(eventData int) {
|
||||||
|
receivedData = eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := func(eventData int) bool {
|
||||||
|
return eventData == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener, false, 0, filter)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||||
|
|
||||||
|
assert.Equal(1, receivedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_Subscribe_withPriority(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_Subscribe_withPriority")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
var receivedData []int
|
||||||
|
listener1 := func(eventData int) {
|
||||||
|
receivedData = append(receivedData, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
listener2 := func(eventData int) {
|
||||||
|
receivedData = append(receivedData, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
eb.Subscribe("event1", listener1, false, 1, nil)
|
||||||
|
eb.Subscribe("event1", listener2, false, 2, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
|
||||||
|
assert.Equal([]int{2, 1}, receivedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_Subscribe_async(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_Subscribe_async")
|
||||||
|
|
||||||
|
eb := NewEventBus[string]()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData string) {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
assert.Equal("hello", eventData)
|
||||||
|
wg.Done()
|
||||||
|
}, true, 1, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_ErrorHandler(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_ErrorHandler")
|
||||||
|
|
||||||
|
eb := NewEventBus[string]()
|
||||||
|
|
||||||
|
eb.SetErrorHandler(func(err error) {
|
||||||
|
assert.Equal("error", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData string) {
|
||||||
|
panic("error")
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Publish(Event[string]{Topic: "event1", Payload: "hello"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_ClearListeners(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_ClearListeners")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData1 := 0
|
||||||
|
receivedData2 := 0
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
receivedData1 = eventData
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Subscribe("event2", func(eventData int) {
|
||||||
|
receivedData2 = eventData
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.ClearListeners()
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 2})
|
||||||
|
|
||||||
|
assert.Equal(0, receivedData1)
|
||||||
|
assert.Equal(0, receivedData2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_ClearListenersByTopic(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_ClearListenersByTopic")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
receivedData1 := 0
|
||||||
|
receivedData2 := 0
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {
|
||||||
|
receivedData1 = eventData
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.Subscribe("event2", func(eventData int) {
|
||||||
|
receivedData2 = eventData
|
||||||
|
}, false, 0, nil)
|
||||||
|
|
||||||
|
eb.ClearListenersByTopic("event1")
|
||||||
|
|
||||||
|
eb.Publish(Event[int]{Topic: "event1", Payload: 1})
|
||||||
|
eb.Publish(Event[int]{Topic: "event2", Payload: 2})
|
||||||
|
|
||||||
|
assert.Equal(0, receivedData1)
|
||||||
|
assert.Equal(2, receivedData2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_GetListenersCount(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_GetListenersCount")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
assert.Equal(2, eb.GetListenersCount("event1"))
|
||||||
|
assert.Equal(1, eb.GetListenersCount("event2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_GetAllListenersCount(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_GetAllListenersCount")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
assert.Equal(3, eb.GetAllListenersCount())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventBus_GetEvents(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestEventBus_GetEvents")
|
||||||
|
|
||||||
|
eb := NewEventBus[int]()
|
||||||
|
|
||||||
|
eb.Subscribe("event1", func(eventData int) {}, false, 0, nil)
|
||||||
|
eb.Subscribe("event2", func(eventData int) {}, false, 0, nil)
|
||||||
|
|
||||||
|
events := eb.GetEvents()
|
||||||
|
|
||||||
|
assert.Equal(2, len(events))
|
||||||
|
assert.EqualValues([]string{"event1", "event2"}, events)
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/validator"
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileReader is a reader supporting offset seeking and reading one
|
// FileReader is a reader supporting offset seeking and reading one
|
||||||
@@ -422,8 +424,15 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
defer zipReader.Close()
|
defer zipReader.Close()
|
||||||
|
|
||||||
for _, f := range zipReader.File {
|
for _, f := range zipReader.File {
|
||||||
|
decodeName := f.Name
|
||||||
|
if f.Flags == 0 {
|
||||||
|
i := bytes.NewReader([]byte(f.Name))
|
||||||
|
decoder := transform.NewReader(i, simplifiedchinese.GB18030.NewDecoder())
|
||||||
|
content, _ := io.ReadAll(decoder)
|
||||||
|
decodeName = string(content)
|
||||||
|
}
|
||||||
// issue#62: fix ZipSlip bug
|
// issue#62: fix ZipSlip bug
|
||||||
path, err := safeFilepathJoin(destPath, f.Name)
|
path, err := safeFilepathJoin(destPath, decodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,10 +145,14 @@ func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
|||||||
|
|
||||||
// Max return max value of numbers.
|
// Max return max value of numbers.
|
||||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
func Max[T constraints.Ordered](items ...T) T {
|
||||||
max := numbers[0]
|
if len(items) < 1 {
|
||||||
|
panic("mathutil.Max: empty list")
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range numbers {
|
max := items[0]
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
if max < v {
|
if max < v {
|
||||||
max = v
|
max = v
|
||||||
}
|
}
|
||||||
@@ -181,10 +185,14 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
|||||||
|
|
||||||
// Min return min value of numbers.
|
// Min return min value of numbers.
|
||||||
// Play: https://go.dev/play/p/21BER_mlGUj
|
// Play: https://go.dev/play/p/21BER_mlGUj
|
||||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
func Min[T constraints.Ordered](items ...T) T {
|
||||||
min := numbers[0]
|
if len(items) < 1 {
|
||||||
|
panic("mathutil.min: empty list")
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range numbers {
|
min := items[0]
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
if min > v {
|
if min > v {
|
||||||
min = v
|
min = v
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ func TestMax(t *testing.T) {
|
|||||||
assert.Equal(0, Max(0, 0))
|
assert.Equal(0, Max(0, 0))
|
||||||
assert.Equal(3, Max(1, 2, 3))
|
assert.Equal(3, Max(1, 2, 3))
|
||||||
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
||||||
|
assert.Equal("abc", Max("a", "ab", "abc"))
|
||||||
|
|
||||||
type Integer int
|
type Integer int
|
||||||
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
||||||
@@ -212,6 +213,8 @@ func TestMin(t *testing.T) {
|
|||||||
assert.Equal(0, Min(0, 0))
|
assert.Equal(0, Min(0, 0))
|
||||||
assert.Equal(1, Min(1, 2, 3))
|
assert.Equal(1, Min(1, 2, 3))
|
||||||
assert.Equal(1.1, Min(1.2, 1.4, 1.1, 1.4))
|
assert.Equal(1.1, Min(1.2, 1.4, 1.1, 1.4))
|
||||||
|
|
||||||
|
assert.Equal("a", Min("a", "ab", "abc"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinBy(t *testing.T) {
|
func TestMinBy(t *testing.T) {
|
||||||
|
|||||||
@@ -126,12 +126,24 @@ func RandFloat(min, max float64, precision int) float64 {
|
|||||||
|
|
||||||
n := rand.Float64()*(max-min) + min
|
n := rand.Float64()*(max-min) + min
|
||||||
|
|
||||||
return mathutil.RoundToFloat(n, precision)
|
return mathutil.FloorToFloat(n, precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandFloats generate a slice of random float64 numbers of length that do not repeat.
|
// RandFloats generate a slice of random float64 numbers of length that do not repeat.
|
||||||
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
||||||
func RandFloats(length int, min, max float64, precision int) []float64 {
|
func RandFloats(length int, min, max float64, precision int) []float64 {
|
||||||
|
if max < min {
|
||||||
|
min, max = max, min
|
||||||
|
}
|
||||||
|
|
||||||
|
maxLength := int((max - min) * math.Pow10(precision))
|
||||||
|
if maxLength == 0 {
|
||||||
|
maxLength = 1
|
||||||
|
}
|
||||||
|
if length > maxLength {
|
||||||
|
length = maxLength
|
||||||
|
}
|
||||||
|
|
||||||
nums := make([]float64, length)
|
nums := make([]float64, length)
|
||||||
used := make(map[float64]struct{}, length)
|
used := make(map[float64]struct{}, length)
|
||||||
for i := 0; i < length; {
|
for i := 0; i < length; {
|
||||||
|
|||||||
@@ -197,6 +197,14 @@ func TestRandFloats(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(len(numbers), 5)
|
assert.Equal(len(numbers), 5)
|
||||||
|
|
||||||
|
numbers2 := RandFloats(10, 3.14, 3.2, 2)
|
||||||
|
for _, n := range numbers2 {
|
||||||
|
assert.GreaterOrEqual(n, 3.14)
|
||||||
|
assert.Less(n, 3.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(len(numbers2), 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRandIntSlice(t *testing.T) {
|
func TestRandIntSlice(t *testing.T) {
|
||||||
|
|||||||
@@ -220,6 +220,28 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EqualUnordered checks if two slices are equal: the same length and all elements' value are equal (unordered).
|
||||||
|
// Play: todo
|
||||||
|
func EqualUnordered[T comparable](slice1, slice2 []T) bool {
|
||||||
|
if len(slice1) != len(slice2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
seen := make(map[T]int)
|
||||||
|
for _, v := range slice1 {
|
||||||
|
seen[v]++
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range slice2 {
|
||||||
|
if seen[v] == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
seen[v]--
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Every return true if all of the values in the slice pass the predicate function.
|
// Every return true if all of the values in the slice pass the predicate function.
|
||||||
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
||||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||||
@@ -980,7 +1002,19 @@ func Reverse[T any](slice []T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shuffle the slice.
|
// ReverseCopy return a new slice of element order is reversed to the given slice.
|
||||||
|
// Play: todo
|
||||||
|
func ReverseCopy[T any](slice []T) []T {
|
||||||
|
result := make([]T, len(slice))
|
||||||
|
|
||||||
|
for i, j := 0, len(slice)-1; i < len(slice); i, j = i+1, j-1 {
|
||||||
|
result[i] = slice[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle return a new slice with elements shuffled.
|
||||||
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
||||||
func Shuffle[T any](slice []T) []T {
|
func Shuffle[T any](slice []T) []T {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
@@ -992,6 +1026,20 @@ func Shuffle[T any](slice []T) []T {
|
|||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShuffleCopy return a new slice with elements shuffled.
|
||||||
|
// Play: todo
|
||||||
|
func ShuffleCopy[T any](slice []T) []T {
|
||||||
|
result := make([]T, len(slice))
|
||||||
|
copy(result, slice)
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
rand.Shuffle(len(result), func(i, j int) {
|
||||||
|
result[i], result[j] = result[j], result[i]
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// IsAscending checks if a slice is ascending order.
|
// IsAscending checks if a slice is ascending order.
|
||||||
// Play: https://go.dev/play/p/9CtsFjet4SH
|
// Play: https://go.dev/play/p/9CtsFjet4SH
|
||||||
func IsAscending[T constraints.Ordered](slice []T) bool {
|
func IsAscending[T constraints.Ordered](slice []T) bool {
|
||||||
|
|||||||
@@ -937,6 +937,41 @@ func ExampleReverse() {
|
|||||||
// [d c b a]
|
// [d c b a]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleReverseCopy() {
|
||||||
|
strs := []string{"a", "b", "c", "d"}
|
||||||
|
|
||||||
|
reversedStrs := ReverseCopy(strs)
|
||||||
|
|
||||||
|
fmt.Println(reversedStrs)
|
||||||
|
fmt.Println(strs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [d c b a]
|
||||||
|
// [a b c d]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleShuffle() {
|
||||||
|
strs := []string{"a", "b", "c", "d"}
|
||||||
|
Shuffle(strs)
|
||||||
|
|
||||||
|
fmt.Println(len(strs))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 4
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleShuffleCopy() {
|
||||||
|
strs := []string{"a", "b", "c", "d"}
|
||||||
|
shuffledStrs := ShuffleCopy(strs)
|
||||||
|
|
||||||
|
fmt.Println(len(shuffledStrs))
|
||||||
|
fmt.Println(strs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 4
|
||||||
|
// [a b c d]
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleIsAscending() {
|
func ExampleIsAscending() {
|
||||||
|
|
||||||
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
result1 := IsAscending([]int{1, 2, 3, 4, 5})
|
||||||
@@ -1300,3 +1335,15 @@ func ExampleConcatBy() {
|
|||||||
// Alice | Bob | Charlie
|
// Alice | Bob | Charlie
|
||||||
// 90
|
// 90
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleEqualUnordered() {
|
||||||
|
result1 := EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
|
||||||
|
result2 := EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -1114,6 +1115,17 @@ func TestReverse(t *testing.T) {
|
|||||||
assert.Equal([]string{"e", "d", "c", "b", "a"}, s2)
|
assert.Equal([]string{"e", "d", "c", "b", "a"}, s2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReverseCopy(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert := internal.NewAssert(t, "TestReverseCopy")
|
||||||
|
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
reversedNumbers := ReverseCopy(numbers)
|
||||||
|
|
||||||
|
assert.Equal([]int{5, 4, 3, 2, 1}, reversedNumbers)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, numbers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDifference(t *testing.T) {
|
func TestDifference(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1329,6 +1341,18 @@ func TestShuffle(t *testing.T) {
|
|||||||
assert.Equal(5, len(result))
|
assert.Equal(5, len(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShuffleCopy(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestShuffleCopy")
|
||||||
|
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
result := ShuffleCopy(numbers)
|
||||||
|
|
||||||
|
assert.Equal(5, len(result))
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, numbers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestIndexOf(t *testing.T) {
|
func TestIndexOf(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1794,6 +1818,8 @@ func TestFilterConcurrent(t *testing.T) {
|
|||||||
nums := []int{1, 2, 3, 4, 5, 6}
|
nums := []int{1, 2, 3, 4, 5, 6}
|
||||||
expected := []int{4, 5, 6}
|
expected := []int{4, 5, 6}
|
||||||
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
|
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
|
||||||
|
sort.Ints(actual)
|
||||||
|
sort.Ints(expected)
|
||||||
assert.Equal(expected, actual)
|
assert.Equal(expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1926,3 +1952,25 @@ func TestConcatBy(t *testing.T) {
|
|||||||
assert.Equal(90, result.Age)
|
assert.Equal(90, result.Age)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEqualUnordered(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestEqualUnordered")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
slice1, slice2 []int
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{[]int{}, []int{}, true},
|
||||||
|
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||||
|
{[]int{1, 2, 3}, []int{3, 2, 1}, true},
|
||||||
|
{[]int{1, 2, 3}, []int{1, 2, 3, 4}, false},
|
||||||
|
{[]int{1, 2, 3}, []int{1, 2}, false},
|
||||||
|
{[]int{1, 2, 3}, []int{1, 2, 4}, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
assert.Equal(test.expected, EqualUnordered(test.slice1, test.slice2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -738,14 +738,14 @@ func RegexMatchAllGroups(pattern, str string) [][]string {
|
|||||||
|
|
||||||
// ExtractContent extracts the content between the start and end strings in the source string.
|
// ExtractContent extracts the content between the start and end strings in the source string.
|
||||||
// Play: https://go.dev/play/p/Ay9UIk7Rum9
|
// Play: https://go.dev/play/p/Ay9UIk7Rum9
|
||||||
func ExtractContent(s, start, end string) []string {
|
func ExtractContent(str, start, end string) []string {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if _, after, ok := strings.Cut(s, start); ok {
|
if _, after, ok := strings.Cut(str, start); ok {
|
||||||
if before, _, ok := strings.Cut(after, end); ok {
|
if before, _, ok := strings.Cut(after, end); ok {
|
||||||
result = append(result, before)
|
result = append(result, before)
|
||||||
s = after
|
str = after
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -756,3 +756,20 @@ func ExtractContent(s, start, end string) []string {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindAllOccurrences returns the positions of all occurrences of a substring in a string.
|
||||||
|
// Play: todo
|
||||||
|
func FindAllOccurrences(str, substr string) []int {
|
||||||
|
var positions []int
|
||||||
|
|
||||||
|
for i := 0; i < len(str); {
|
||||||
|
index := strings.Index(str[i:], substr)
|
||||||
|
if index == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
positions = append(positions, i+index)
|
||||||
|
i += index + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return positions
|
||||||
|
}
|
||||||
|
|||||||
@@ -763,5 +763,13 @@ func ExampleExtractContent() {
|
|||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [content1 content2 content1]
|
// [content1 content2 content1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFindAllOccurrences() {
|
||||||
|
result := FindAllOccurrences("ababab", "ab")
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [0 2 4]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -937,3 +937,32 @@ func TestExtractContent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindAllOccurrences(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFindAllOccurrences")
|
||||||
|
|
||||||
|
var empty []int
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
substr string
|
||||||
|
expected []int
|
||||||
|
}{
|
||||||
|
{"", "", empty},
|
||||||
|
{"", "a", empty},
|
||||||
|
{"a", "", []int{0}},
|
||||||
|
{"a", "a", []int{0}},
|
||||||
|
{"aa", "a", []int{0, 1}},
|
||||||
|
{"ababab", "ab", []int{0, 2, 4}},
|
||||||
|
{"ababab", "ba", []int{1, 3}},
|
||||||
|
{"ababab", "c", empty},
|
||||||
|
{"ababab", "ababab", []int{0}},
|
||||||
|
{"ababab", "abababc", empty},
|
||||||
|
{"ababab", "abababa", empty},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
assert.Equal(tt.expected, FindAllOccurrences(tt.input, tt.substr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -207,6 +207,18 @@ func IsIp(ipstr string) bool {
|
|||||||
return ip != nil
|
return ip != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsIpPort check if the string is ip:port.
|
||||||
|
// Play:
|
||||||
|
func IsIpPort(str string) bool {
|
||||||
|
host, port, err := net.SplitHostPort(str)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
return ip != nil && IsPort(port)
|
||||||
|
}
|
||||||
|
|
||||||
// IsIpV4 check if the string is a ipv4 address.
|
// IsIpV4 check if the string is a ipv4 address.
|
||||||
// Play: https://go.dev/play/p/zBGT99EjaIu
|
// Play: https://go.dev/play/p/zBGT99EjaIu
|
||||||
func IsIpV4(ipstr string) bool {
|
func IsIpV4(ipstr string) bool {
|
||||||
|
|||||||
@@ -348,6 +348,24 @@ func ExampleIsIp() {
|
|||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleIsIpPort() {
|
||||||
|
result1 := IsIpPort("127.0.0.1:8080")
|
||||||
|
result2 := IsIpPort("[0:0:0:0:0:0:0:1]:8080")
|
||||||
|
result3 := IsIpPort(":8080")
|
||||||
|
result4 := IsIpPort("::0:0:0:0:")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleIsIpV4() {
|
func ExampleIsIpV4() {
|
||||||
result1 := IsIpV4("127.0.0.1")
|
result1 := IsIpV4("127.0.0.1")
|
||||||
result2 := IsIpV4("::0:0:0:0:0:0:1")
|
result2 := IsIpV4("::0:0:0:0:0:0:1")
|
||||||
|
|||||||
@@ -225,6 +225,23 @@ func TestIsIp(t *testing.T) {
|
|||||||
assert.Equal(false, IsIp("127"))
|
assert.Equal(false, IsIp("127"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsIpPort(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestIsIpPort")
|
||||||
|
|
||||||
|
assert.Equal(true, IsIpPort("[0:0:0:0:0:0:0:1]:8080")) // valid IPv6 and port
|
||||||
|
assert.Equal(true, IsIpPort("127.0.0.1:8080")) // valid IP and port
|
||||||
|
|
||||||
|
assert.Equal(false, IsIpPort("")) // empty string
|
||||||
|
assert.Equal(false, IsIpPort(":8080")) // only port
|
||||||
|
assert.Equal(false, IsIpPort("127.0.0.1")) // valid IP without port
|
||||||
|
assert.Equal(false, IsIpPort("0:0:0:0:0:0:0:1")) // valid IPv6 without port
|
||||||
|
assert.Equal(false, IsIpPort("256.256.256.256:8080")) // invalid IP with valid port
|
||||||
|
assert.Equal(false, IsIpPort("256.256.256.256:abc")) // invalid IP and invalid port
|
||||||
|
assert.Equal(false, IsIpPort("127.0.0.1:70000")) // valid IP with invalid port
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsIpV4(t *testing.T) {
|
func TestIsIpV4(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -315,7 +332,7 @@ func TestIsChinesePhone(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(true, IsChinesePhone("010-32116675"))
|
assert.Equal(true, IsChinesePhone("010-32116675"))
|
||||||
assert.Equal(true, IsChinesePhone("0464-8756213"))
|
assert.Equal(true, IsChinesePhone("0464-8756213"))
|
||||||
assert.Equal(true, IsChinesePhone("0731-82251545")) //长沙晚报电话
|
assert.Equal(true, IsChinesePhone("0731-82251545")) // 长沙晚报电话
|
||||||
assert.Equal(false, IsChinesePhone("123-87562"))
|
assert.Equal(false, IsChinesePhone("123-87562"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user