mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-11 00:02:28 +08:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e29b56c3c3 | ||
|
|
c357fc68c8 | ||
|
|
bc25e7a037 | ||
|
|
217350042b | ||
|
|
e56a8a1ef5 | ||
|
|
6453f755a6 | ||
|
|
027abd6ad5 | ||
|
|
91503b1656 | ||
|
|
e2522cd29b | ||
|
|
da69b77892 | ||
|
|
05772d8d7d | ||
|
|
3b497532f3 | ||
|
|
1cd3be508c | ||
|
|
a41d461910 | ||
|
|
cde5946bf0 | ||
|
|
c28803b25e | ||
|
|
f09e521783 | ||
|
|
0aa41f337d | ||
|
|
48814a720a | ||
|
|
04b79b3dfe | ||
|
|
302007ebdf | ||
|
|
965e5fbcda | ||
|
|
70d0adde42 | ||
|
|
0b80074bb7 | ||
|
|
90945a0399 | ||
|
|
47dccd63af | ||
|
|
4ae7e59829 | ||
|
|
8f0c60cade | ||
|
|
3f6aef1432 | ||
|
|
a714e04470 | ||
|
|
7456621153 | ||
|
|
73ac9825e9 | ||
|
|
930bb9c839 | ||
|
|
3d8f1be212 | ||
|
|
13a4ed59fa | ||
|
|
c799d10ce9 | ||
|
|
5ab322ade2 | ||
|
|
d0ffc61842 | ||
|
|
5e66bc6227 | ||
|
|
7261b281ad | ||
|
|
f79693804b | ||
|
|
534c7a0abc | ||
|
|
4eaff47d38 | ||
|
|
3e019522c7 | ||
|
|
0734f220b3 | ||
|
|
2d2c277090 | ||
|
|
ef1e548dfc | ||
|
|
924589d2da | ||
|
|
77f32f4cc6 | ||
|
|
1755dd249b | ||
|
|
7a25688ec1 | ||
|
|
51a6912eb3 | ||
|
|
28d0428b50 | ||
|
|
6a9eb645bb | ||
|
|
3857b342f6 | ||
|
|
71aa91a58d | ||
|
|
081908bce3 |
92
README.md
92
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)
|
||||||
@@ -251,7 +251,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||||
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
|
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
|
||||||
|
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||||
|
|
||||||
### 5. Cryptor package is for data encryption and decryption.
|
### 5. Cryptor package is for data encryption and decryption.
|
||||||
|
|
||||||
@@ -456,9 +456,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
|
||||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -593,7 +590,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
### 11. Maputil package includes some functions to manipulate map.
|
### 11. Maputil package includes some functions to manipulate map.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -610,14 +606,19 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||||
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
|
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||||
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
|
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
|
||||||
|
[[play](https://go.dev/play/p/P3-9MdcXegR)]
|
||||||
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
|
||||||
|
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
|
||||||
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||||
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
|
||||||
|
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
|
||||||
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
||||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||||
@@ -626,6 +627,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||||
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
|
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
|
||||||
|
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||||
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
||||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||||
@@ -637,16 +639,22 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||||
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
|
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||||
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
|
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
|
||||||
|
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||||
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
|
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
|
||||||
|
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||||
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
|
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
|
||||||
|
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||||
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
|
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
|
||||||
|
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||||
- **<big>Transform</big>** : transform a map to another type map.
|
- **<big>Transform</big>** : transform a map to another type map.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
|
||||||
|
[[play](https://go.dev/play/p/P6ovfToM3zj)]
|
||||||
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||||
@@ -695,6 +703,20 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>Range</big>** : Creates a slice of numbers from start with specified count, element step is 1.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
|
||||||
|
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
||||||
|
- **<big>RangeWithStep</big>** : Creates a slice of numbers from start to end with specified step.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
|
||||||
|
[[play](https://go.dev/play/p/akLWz0EqOSM)]
|
||||||
|
- **<big>AngleToRadian</big>** : converts angle value to radian value.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#AngleToRadian)]
|
||||||
|
- **<big>RadianToAngle</big>** : converts radian value to angle value.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RadianToAngle)]
|
||||||
|
- **<big>PointDistance</big>** : get two points distance.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#PointDistance)]
|
||||||
|
- **<big>IsPrime</big>** : checks if number is prime number.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#IsPrime)]
|
||||||
|
|
||||||
### 13. Netutil package contains functions to get net information and send http request.
|
### 13. Netutil package contains functions to get net information and send http request.
|
||||||
|
|
||||||
@@ -759,8 +781,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 14. Random package implements some basic functions to generate random int and string.
|
### 14. Random package implements some basic functions to generate random int and string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -834,6 +854,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||||
- **<big>ContainBy</big>** : returns true if predicate function return true.
|
- **<big>ContainBy</big>** : returns true if predicate function return true.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
|
||||||
|
[[play](https://go.dev/play/p/49tkHfX4GNc)]
|
||||||
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
||||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||||
@@ -890,6 +911,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||||
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
|
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
|
||||||
|
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||||
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||||
@@ -904,9 +926,13 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||||
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
|
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
|
||||||
|
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||||
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
|
- **<big>ForEachWithBreak</big>** : iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEachWithBreak)]
|
||||||
|
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||||
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
|
||||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||||
@@ -1013,7 +1039,40 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
||||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||||
|
|
||||||
### 17. Strutil package contains some functions to manipulate string.
|
### 17. Structs package provides several high level functions to manipulate struct, tag, and field.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/structs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- **<big>New</big>** : creates a `Struct` instance.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#New)]
|
||||||
|
- **<big>ToMap</big>** : converts a valid struct to a map.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#ToMap)]
|
||||||
|
- **<big>Fields</big>** : get all fields of a given struct, that the fields are abstract struct field.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Fields)]
|
||||||
|
- **<big>IsStruct</big>** : check if the struct is valid.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#IsStruct)]
|
||||||
|
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Tag)]
|
||||||
|
- **<big>Name</big>** : get the field name.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Name)]
|
||||||
|
- **<big>Value</big>** : get the `Field` underlying value.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Value)]
|
||||||
|
- **<big>Kind</big>** : get the field's kind
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Kind)]
|
||||||
|
- **<big>IsEmbedded</big>** : check if the field is an embedded field.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsEmbedded)]
|
||||||
|
- **<big>IsExported</big>** : check if the field is exporte
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsExported)]
|
||||||
|
- **<big>IsZero</big>** : check if the field is zero value
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsZero)]
|
||||||
|
- **<big>IsSlice</big>** : check if the field is a slice
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
|
||||||
|
|
||||||
|
### 18. Strutil package contains some functions to manipulate string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -1055,6 +1114,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||||
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
|
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
|
||||||
|
[[play](https://go.dev/play/p/NzImQq-VF8q)]
|
||||||
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
||||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||||
@@ -1084,8 +1144,12 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||||
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
|
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
|
||||||
|
[[play](https://go.dev/play/p/KLiX4WiysMM)]
|
||||||
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
|
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
|
||||||
|
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||||
|
- **<big>RemoveNonPrintable</big>** : remove non-printable characters from a string.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveNonPrintable)]
|
||||||
|
|
||||||
### 19. System package contain some functions about os, runtime, shell command.
|
### 19. System package contain some functions about os, runtime, shell command.
|
||||||
|
|
||||||
@@ -1123,7 +1187,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
||||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||||
|
|
||||||
### 19. Validator package contains some functions for data validation.
|
### 20. Validator package contains some functions for data validation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -1215,14 +1279,19 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsGBK</big>** : check if data encoding is gbk.
|
- **<big>IsGBK</big>** : check if data encoding is gbk.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
|
||||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||||
|
- **<big>IsASCII</big>** : checks if string is all ASCII char.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsASCII)]
|
||||||
|
- **<big>IsPrintable</big>** : checks if string is all printable chars.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
|
||||||
|
|
||||||
### 20. xerror package implements helpers for errors.
|
### 21. xerror package implements helpers for errors.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Function list:
|
#### Function list:
|
||||||
|
|
||||||
- **<big>New</big>** : creates a new XError pointer instance with message.
|
- **<big>New</big>** : creates a new XError pointer instance with message.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
|
||||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||||
@@ -1263,7 +1332,6 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
|
||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
|
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
|
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
|
||||||
|
|||||||
105
README_zh-CN.md
105
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)
|
||||||
@@ -250,7 +250,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||||
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
|
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
|
||||||
|
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||||
|
|
||||||
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||||
|
|
||||||
@@ -356,8 +356,6 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
||||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 6. datetime 日期时间处理包,格式化日期,比较日期。
|
### 6. datetime 日期时间处理包,格式化日期,比较日期。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -457,8 +455,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
||||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 7. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
### 7. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -491,9 +487,6 @@ 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/datastructure/hashmap_zh-CN.md)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 8. fileutil 包含文件基本操作。
|
### 8. fileutil 包含文件基本操作。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -596,7 +589,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
### 11. maputil 包括一些操作 map 的函数.
|
### 11. maputil 包括一些操作 map 的函数.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -613,14 +605,19 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||||
- **<big>FilterByKeys</big>** : 迭代 map, 返回一个新 map,其 key 都是给定的 key 值。
|
- **<big>FilterByKeys</big>** : 迭代 map, 返回一个新 map,其 key 都是给定的 key 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||||
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map,其 value 都是给定的 value 值。
|
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map,其 value 都是给定的 value 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
|
||||||
|
[[play](https://go.dev/play/p/P3-9MdcXegR)]
|
||||||
- **<big>OmitBy</big>** : Filter 的反向操作, 迭代 map 中的每对 key 和 value, 删除符合 predicate 函数的 key, value, 返回新 map。
|
- **<big>OmitBy</big>** : Filter 的反向操作, 迭代 map 中的每对 key 和 value, 删除符合 predicate 函数的 key, value, 返回新 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
|
||||||
|
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
|
||||||
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map,其 key 不包括给定的 key 值。
|
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map,其 key 不包括给定的 key 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||||
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map,其 value 不包括给定的 value 值。
|
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map,其 value 不包括给定的 value 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
|
||||||
|
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
|
||||||
- **<big>Intersect</big>** : 多个 map 的交集操作。
|
- **<big>Intersect</big>** : 多个 map 的交集操作。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
||||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||||
@@ -629,6 +626,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||||
- **<big>KeysBy</big>** : 创建一个切片,其元素是每个 map 的 key 调用 mapper 函数的结果。
|
- **<big>KeysBy</big>** : 创建一个切片,其元素是每个 map 的 key 调用 mapper 函数的结果。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
|
||||||
|
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||||
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
||||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||||
@@ -640,16 +638,22 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||||
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 map 的 value 调用 mapper 函数的结果。
|
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 map 的 value 调用 mapper 函数的结果。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||||
- **<big>MapKeys</big>** : 操作 map 的每个 key,然后转为新的 map。
|
- **<big>MapKeys</big>** : 操作 map 的每个 key,然后转为新的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
|
||||||
|
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||||
- **<big>MapValues</big>** : 操作 map 的每个 value,然后转为新的 map。
|
- **<big>MapValues</big>** : 操作 map 的每个 value,然后转为新的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
|
||||||
|
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||||
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
|
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
|
||||||
|
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||||
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
|
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
|
||||||
|
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||||
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
|
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
|
||||||
|
[[play](https://go.dev/play/p/P6ovfToM3zj)]
|
||||||
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||||
@@ -698,6 +702,20 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>Range</big>** : 根据指定的起始值和数量,创建一个数字切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Range)]
|
||||||
|
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
||||||
|
- **<big>RangeWithStep</big>** : 根据指定的起始值,结束值,步长,创建一个数字切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RangeWithStep)]
|
||||||
|
[[play](https://go.dev/play/p/akLWz0EqOSM)]
|
||||||
|
- **<big>AngleToRadian</big>** : 将角度值转为弧度值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#AngleToRadian)]
|
||||||
|
- **<big>RadianToAngle</big>** : 将弧度值转为角度值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RadianToAngle)]
|
||||||
|
- **<big>PointDistance</big>** : 计算两个坐标点的距离。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#PointDistance)]
|
||||||
|
- **<big>IsPrime</big>** : 判断质数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#IsPrime)]
|
||||||
|
|
||||||
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||||
|
|
||||||
@@ -762,9 +780,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -798,8 +813,6 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
||||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -824,8 +837,6 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
||||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 16. slice 包含操作切片的方法集合。
|
### 16. slice 包含操作切片的方法集合。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -833,6 +844,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
|
|
||||||
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
||||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||||
@@ -841,6 +853,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||||
- **<big>ContainBy</big>** : 根据 predicate 函数判断切片是否包含某个值。
|
- **<big>ContainBy</big>** : 根据 predicate 函数判断切片是否包含某个值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
|
||||||
|
[[play](https://go.dev/play/p/49tkHfX4GNc)]
|
||||||
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
|
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
||||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||||
@@ -897,6 +910,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||||
- **<big>FilterMap</big>** : 返回一个将 filter 和 map 操作应用于给定切片的切片。
|
- **<big>FilterMap</big>** : 返回一个将 filter 和 map 操作应用于给定切片的切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
|
||||||
|
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
||||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||||
@@ -911,9 +925,13 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||||
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
|
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
|
||||||
|
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
|
- **<big>ForEachWithBreak</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数,当 iteratee 函数返回 false 时,终止遍历。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEachWithBreak)]
|
||||||
|
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||||
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
||||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||||
@@ -1020,8 +1038,42 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||||
|
|
||||||
|
### 17. structs 提供操作 struct, tag, field 的相关函数。
|
||||||
|
|
||||||
### 17. strutil 包含字符串处理的相关函数。
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/structs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- **<big>New</big>** : `Struct`结构体的构造函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#New)]
|
||||||
|
- **<big>ToMap</big>** : 将一个合法的 struct 对象转换为 map[string]any。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)]
|
||||||
|
- **<big>Fields</big>** : 获取一个 struct 对象的属性列表。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||||
|
- **<big>Field</big>** : 根据属性名获取一个 struct 对象的属性。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||||
|
- **<big>IsStruct</big>** : 判断是否为一个合法的 struct 对象。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)]
|
||||||
|
- **<big>Tag</big>** : 获取`Field`的`Tag`,默认的 tag key 是 json。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Tag)]
|
||||||
|
- **<big>Name</big>** : 获取属性名。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Name)]
|
||||||
|
- **<big>Value</big>** : 获取`Field`属性的值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Value)]
|
||||||
|
- **<big>Kind</big>** : 获取属性 Kind。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Kind)]
|
||||||
|
- **<big>IsEmbedded</big>** : 判断属性是否为嵌入。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsEmbedded)]
|
||||||
|
- **<big>IsExported</big>** : 判断属性是否导出。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsExported)]
|
||||||
|
- **<big>IsZero</big>** : 判断属性是否为零值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsZero)]
|
||||||
|
- **<big>IsSlice</big>** : 判断属性是否是切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
|
||||||
|
|
||||||
|
### 18. strutil 包含字符串处理的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -1064,6 +1116,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||||
- **<big>Pad</big>** : 如果字符串长度短于 size,则在左右两侧填充字符串。
|
- **<big>Pad</big>** : 如果字符串长度短于 size,则在左右两侧填充字符串。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
|
||||||
|
[[play](https://go.dev/play/p/NzImQq-VF8q)]
|
||||||
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
||||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||||
@@ -1093,10 +1146,14 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||||
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
|
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
|
||||||
|
[[play](https://go.dev/play/p/KLiX4WiysMM)]
|
||||||
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
|
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
|
||||||
|
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||||
|
- **<big>RemoveNonPrintable</big>** : 删除字符串中不可打印的字符。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveNonPrintable)]
|
||||||
|
|
||||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
### 19. system 包含 os, runtime, shell command 的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/system"
|
import "github.com/duke-git/lancet/v2/system"
|
||||||
@@ -1132,7 +1189,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
||||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||||
|
|
||||||
### 19. validator 验证器包,包含常用字符串格式验证函数。
|
### 20. validator 验证器包,包含常用字符串格式验证函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -1224,9 +1281,12 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk(汉字内部代码扩展规范)。
|
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk(汉字内部代码扩展规范)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
||||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||||
|
- **<big>IsASCII</big>** : 验证字符串全部为 ASCII 字符。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsASCII)]
|
||||||
|
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
|
||||||
|
|
||||||
|
### 21. xerror 包实现一些错误处理函数
|
||||||
### 20. xerror 包实现一些错误处理函数
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
@@ -1274,7 +1334,6 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
|
||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
|
|
||||||
|
|
||||||
## 如何贡献代码
|
## 如何贡献代码
|
||||||
|
|
||||||
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||||
package concurrency
|
package concurrency
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -235,31 +235,7 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
|
|||||||
// map key is specified same as struct field tag `json` value.
|
// map key is specified same as struct field tag `json` value.
|
||||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||||
func StructToMap(value any) (map[string]any, error) {
|
func StructToMap(value any) (map[string]any, error) {
|
||||||
v := reflect.ValueOf(value)
|
return structs.ToMap(value)
|
||||||
t := reflect.TypeOf(value)
|
|
||||||
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]any)
|
|
||||||
|
|
||||||
fieldNum := t.NumField()
|
|
||||||
pattern := `^[A-Z]`
|
|
||||||
regex := regexp.MustCompile(pattern)
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
name := t.Field(i).Name
|
|
||||||
tag := t.Field(i).Tag.Get("json")
|
|
||||||
if regex.MatchString(name) && tag != "" {
|
|
||||||
//result[name] = v.Field(i).Interface()
|
|
||||||
result[tag] = v.Field(i).Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapToSlice convert map to slice based on iteratee function.
|
// MapToSlice convert map to slice based on iteratee function.
|
||||||
@@ -343,11 +319,11 @@ func DeepClone[T any](src T) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/FOVY3XJL-6B
|
||||||
func CopyProperties[T, U any](dst T, src U) (err error) {
|
func CopyProperties[T, U any](dst T, src U) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
err = errors.New(fmt.Sprintf("%v", e))
|
err = fmt.Errorf("%v", e)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ func ExampleDeepClone() {
|
|||||||
Float float64
|
Float float64
|
||||||
Bool bool
|
Bool bool
|
||||||
Nil interface{}
|
Nil interface{}
|
||||||
unexported string
|
// unexported string
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []interface{}{
|
cases := []interface{}{
|
||||||
@@ -323,12 +323,18 @@ func ExampleCopyProperties() {
|
|||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||||
|
|
||||||
employee1 := Employee{}
|
employee1 := Employee{}
|
||||||
CopyProperties(&employee1, &user)
|
err := CopyProperties(&employee1, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||||
|
|
||||||
CopyProperties(&employee2, &user)
|
err = CopyProperties(&employee2, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println(employee1)
|
fmt.Println(employee1)
|
||||||
fmt.Println(employee2)
|
fmt.Println(employee2)
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ func TestToMap(t *testing.T) {
|
|||||||
func TestStructToMap(t *testing.T) {
|
func TestStructToMap(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestStructToMap")
|
assert := internal.NewAssert(t, "TestStructToMap")
|
||||||
|
|
||||||
|
t.Run("StructToMap", func(_ *testing.T) {
|
||||||
type People struct {
|
type People struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
age int
|
age int
|
||||||
@@ -189,9 +190,26 @@ func TestStructToMap(t *testing.T) {
|
|||||||
100,
|
100,
|
||||||
}
|
}
|
||||||
pm, _ := StructToMap(p)
|
pm, _ := StructToMap(p)
|
||||||
|
var expected = map[string]any{"name": "test"}
|
||||||
expected := map[string]any{"name": "test"}
|
|
||||||
assert.Equal(expected, pm)
|
assert.Equal(expected, pm)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name,omitempty"` // json tag with attribute
|
||||||
|
Phone string `json:"phone"` // json tag without attribute
|
||||||
|
Sex string `json:"-"` // ignore
|
||||||
|
age int // no tag
|
||||||
|
}
|
||||||
|
p := People{
|
||||||
|
Phone: "1111",
|
||||||
|
Sex: "male",
|
||||||
|
age: 100,
|
||||||
|
}
|
||||||
|
pm, _ := StructToMap(p)
|
||||||
|
var expected = map[string]any{"phone": "1111"}
|
||||||
|
assert.Equal(expected, pm)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapToSlice(t *testing.T) {
|
func TestMapToSlice(t *testing.T) {
|
||||||
@@ -264,7 +282,7 @@ func TestDeepClone(t *testing.T) {
|
|||||||
Float float64
|
Float float64
|
||||||
Bool bool
|
Bool bool
|
||||||
Nil interface{}
|
Nil interface{}
|
||||||
unexported string
|
// unexported string
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []interface{}{
|
cases := []interface{}{
|
||||||
|
|||||||
@@ -171,3 +171,25 @@ func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
|
|||||||
|
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EachWithBreak iterates over elements of a set and invokes function for each element,
|
||||||
|
// when iteratee return false, will break the for each loop.
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
|
||||||
|
for _, v := range s.Values() {
|
||||||
|
if !iteratee(v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool) {
|
||||||
|
if len(s) > 0 {
|
||||||
|
items := s.Values()
|
||||||
|
item := items[len(s)-1]
|
||||||
|
delete(s, item)
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|||||||
@@ -192,3 +192,40 @@ func TestSet_Minus(t *testing.T) {
|
|||||||
assert.Equal(NewSet(1), set1.Minus(set2))
|
assert.Equal(NewSet(1), set1.Minus(set2))
|
||||||
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEachWithBreak(t *testing.T) {
|
||||||
|
// s := NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
// var sum int
|
||||||
|
|
||||||
|
// s.EachWithBreak(func(n int) bool {
|
||||||
|
// if n > 3 {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// sum += n
|
||||||
|
// return true
|
||||||
|
// })
|
||||||
|
|
||||||
|
// assert := internal.NewAssert(t, "TestEachWithBreak")
|
||||||
|
// assert.Equal(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func TestPop(t *testing.T) {
|
||||||
|
// assert := internal.NewAssert(t, "TestPop")
|
||||||
|
|
||||||
|
// s := NewSet[int]()
|
||||||
|
|
||||||
|
// val, ok := s.Pop()
|
||||||
|
// assert.Equal(0, val)
|
||||||
|
// assert.Equal(false, ok)
|
||||||
|
|
||||||
|
// s.Add(1)
|
||||||
|
// s.Add(2)
|
||||||
|
// s.Add(3)
|
||||||
|
|
||||||
|
// // s = NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
// val, ok = s.Pop()
|
||||||
|
// assert.Equal(3, val)
|
||||||
|
// assert.Equal(true, ok)
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Concurrency
|
# Concurrency
|
||||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Concurrency
|
# Concurrency
|
||||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Set
|
# Set
|
||||||
|
|
||||||
Set is a data container, like list, but elements of set is not duplicate.
|
Set is a data container, like list, but elements of set is not duplicate.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -7,10 +8,10 @@ Set is a data container, like list, but elements of set is not duplicate.
|
|||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
@@ -34,19 +35,19 @@ import (
|
|||||||
- [Size](#Size)
|
- [Size](#Size)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [Iterate](#Iterate)
|
- [Iterate](#Iterate)
|
||||||
|
- [EachWithBreak](#EachWithBreak)
|
||||||
- [IsEmpty](#IsEmpty)
|
- [IsEmpty](#IsEmpty)
|
||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [Intersection](#Intersection)
|
- [Intersection](#Intersection)
|
||||||
- [SymmetricDifference](#SymmetricDifference)
|
- [SymmetricDifference](#SymmetricDifference)
|
||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### <span id="NewSet">NewSet</span>
|
### <span id="NewSet">NewSet</span>
|
||||||
|
|
||||||
<p>Create a set instance</p>
|
<p>Create a set instance</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -55,6 +56,7 @@ import (
|
|||||||
type Set[T comparable] map[T]bool
|
type Set[T comparable] map[T]bool
|
||||||
func NewSet[T comparable](items ...T) Set[T]
|
func NewSet[T comparable](items ...T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -71,8 +73,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||||
|
|
||||||
<p>Create a set from slice</p>
|
<p>Create a set from slice</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -80,6 +82,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -96,9 +99,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Values">Values</span>
|
### <span id="Values">Values</span>
|
||||||
|
|
||||||
<p>Return slice of all set data</p>
|
<p>Return slice of all set data</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -106,6 +108,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Values() []T
|
func (s Set[T]) Values() []T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -122,10 +125,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Add">Add</span>
|
### <span id="Add">Add</span>
|
||||||
|
|
||||||
<p>Add items to set</p>
|
<p>Add items to set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -133,6 +134,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Add(items ...T)
|
func (s Set[T]) Add(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -151,8 +153,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||||
|
|
||||||
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
|
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -160,6 +162,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExist(item T) bool
|
func (s Set[T]) AddIfNotExist(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -183,8 +186,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||||
|
|
||||||
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
|
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -192,6 +195,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -221,8 +225,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delete">Delete</span>
|
### <span id="Delete">Delete</span>
|
||||||
|
|
||||||
<p>Delete item in set</p>
|
<p>Delete item in set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -230,6 +234,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Delete(items ...T)
|
func (s Set[T]) Delete(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -249,9 +254,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Contain">Contain</span>
|
### <span id="Contain">Contain</span>
|
||||||
|
|
||||||
<p>Check if item is in set or not</p>
|
<p>Check if item is in set or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -259,6 +263,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Contain(item T) bool
|
func (s Set[T]) Contain(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -278,10 +283,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ContainAll">ContainAll</span>
|
### <span id="ContainAll">ContainAll</span>
|
||||||
|
|
||||||
<p>Checks if set contains another set</p>
|
<p>Checks if set contains another set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -289,6 +292,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -309,9 +313,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Size">Size</span>
|
### <span id="Size">Size</span>
|
||||||
|
|
||||||
<p>Get the number of elements in set</p>
|
<p>Get the number of elements in set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -319,6 +322,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Size() int
|
func (s Set[T]) Size() int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -336,9 +340,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Clone">Clone</span>
|
### <span id="Clone">Clone</span>
|
||||||
|
|
||||||
<p>Make a copy of set</p>
|
<p>Make a copy of set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -346,6 +349,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Clone() Set[T]
|
func (s Set[T]) Clone() Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -365,10 +369,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Equal">Equal</span>
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
<p>Check if two sets has same elements or not</p>
|
<p>Check if two sets has same elements or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -376,6 +378,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Equal(other Set[T]) bool
|
func (s Set[T]) Equal(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -396,9 +399,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Iterate">Iterate</span>
|
### <span id="Iterate">Iterate</span>
|
||||||
|
|
||||||
<p>Call function by every element of set</p>
|
<p>Call function by every element of set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -406,6 +408,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Iterate(fn func(item T))
|
func (s Set[T]) Iterate(fn func(item T))
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -427,9 +430,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EachWithBreak">EachWithBreak</span>
|
||||||
|
|
||||||
|
<p>Iterates over elements of a set and invokes function for each element, when iteratee return false, will break the for each loop.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
s.EachWithBreak(func(n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum) //6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsEmpty">IsEmpty</span>
|
### <span id="IsEmpty">IsEmpty</span>
|
||||||
|
|
||||||
<p>Check if the set is empty or not</p>
|
<p>Check if the set is empty or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -437,6 +476,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) IsEmpty() bool
|
func (s Set[T]) IsEmpty() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -456,9 +496,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>Create a new set contain all element of set s and other</p>
|
<p>Create a new set contain all element of set s and other</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -466,6 +505,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -485,9 +525,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Intersection">Intersection</span>
|
### <span id="Intersection">Intersection</span>
|
||||||
|
|
||||||
<p>Create a new set whose element both be contained in set s and other</p>
|
<p>Create a new set whose element both be contained in set s and other</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -495,6 +534,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -514,11 +554,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||||
|
|
||||||
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
|
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -526,6 +563,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -545,11 +583,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Minus">Minus</span>
|
### <span id="Minus">Minus</span>
|
||||||
|
|
||||||
<p>Create an set of whose element in origin set but not in compared set</p>
|
<p>Create an set of whose element in origin set but not in compared set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -557,6 +592,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -580,5 +616,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pop">Pop</span>
|
||||||
|
|
||||||
|
<p>Delete the top element of set then return it, if set is empty, return nil-value of T and false.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet[int]()
|
||||||
|
s.Add(1)
|
||||||
|
s.Add(2)
|
||||||
|
s.Add(3)
|
||||||
|
|
||||||
|
val, ok = s.Pop()
|
||||||
|
|
||||||
|
fmt.Println(val) // 3
|
||||||
|
fmt.Println(ok) // true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Set
|
# Set
|
||||||
|
|
||||||
Set 集合数据结构,类似列表。Set 中元素不重复。
|
Set 集合数据结构,类似列表。Set 中元素不重复。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -7,10 +8,10 @@ Set集合数据结构,类似列表。Set中元素不重复。
|
|||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法
|
## 用法
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
@@ -40,13 +41,12 @@ import (
|
|||||||
- [SymmetricDifference](#SymmetricDifference)
|
- [SymmetricDifference](#SymmetricDifference)
|
||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
### <span id="NewSet">NewSet</span>
|
### <span id="NewSet">NewSet</span>
|
||||||
|
|
||||||
<p>返回Set结构体对象</p>
|
<p>返回Set结构体对象</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -55,6 +55,7 @@ import (
|
|||||||
type Set[T comparable] map[T]bool
|
type Set[T comparable] map[T]bool
|
||||||
func NewSet[T comparable](items ...T) Set[T]
|
func NewSet[T comparable](items ...T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -71,9 +72,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||||
|
|
||||||
<p>基于切片创建集合</p>
|
<p>基于切片创建集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -81,6 +81,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -97,9 +98,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Values">Values</span>
|
### <span id="Values">Values</span>
|
||||||
|
|
||||||
<p>获取集合中所有元素的切片</p>
|
<p>获取集合中所有元素的切片</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -107,6 +107,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Values() []T
|
func (s Set[T]) Values() []T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -123,10 +124,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Add">Add</span>
|
### <span id="Add">Add</span>
|
||||||
|
|
||||||
<p>向集合中添加元素</p>
|
<p>向集合中添加元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -134,6 +133,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Add(items ...T)
|
func (s Set[T]) Add(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -152,8 +152,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||||
|
|
||||||
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
|
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -161,6 +161,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExist(item T) bool
|
func (s Set[T]) AddIfNotExist(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -184,8 +185,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||||
|
|
||||||
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
|
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -193,6 +194,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -222,9 +224,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delete">Delete</span>
|
### <span id="Delete">Delete</span>
|
||||||
|
|
||||||
<p>删除集合中元素</p>
|
<p>删除集合中元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -232,6 +233,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Delete(items ...T)
|
func (s Set[T]) Delete(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -251,9 +253,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Contain">Contain</span>
|
### <span id="Contain">Contain</span>
|
||||||
|
|
||||||
<p>判断集合是否包含某个值</p>
|
<p>判断集合是否包含某个值</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -261,6 +262,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Contain(item T) bool
|
func (s Set[T]) Contain(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -280,10 +282,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ContainAll">ContainAll</span>
|
### <span id="ContainAll">ContainAll</span>
|
||||||
|
|
||||||
<p>判断集合是否包含另一个集合</p>
|
<p>判断集合是否包含另一个集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -291,6 +291,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -311,9 +312,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Size">Size</span>
|
### <span id="Size">Size</span>
|
||||||
|
|
||||||
<p>获取集合中元素的个数</p>
|
<p>获取集合中元素的个数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -321,6 +321,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Size() int
|
func (s Set[T]) Size() int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -338,9 +339,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Clone">Clone</span>
|
### <span id="Clone">Clone</span>
|
||||||
|
|
||||||
<p>克隆一个集合</p>
|
<p>克隆一个集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -348,6 +348,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Clone() Set[T]
|
func (s Set[T]) Clone() Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -367,10 +368,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Equal">Equal</span>
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
<p>比较两个集合是否相等,包含相同元素为相等</p>
|
<p>比较两个集合是否相等,包含相同元素为相等</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -378,6 +377,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Equal(other Set[T]) bool
|
func (s Set[T]) Equal(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -398,9 +398,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Iterate">Iterate</span>
|
### <span id="Iterate">Iterate</span>
|
||||||
|
|
||||||
<p>迭代结合,在每个元素上调用函数</p>
|
<p>迭代结合,在每个元素上调用函数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -408,6 +407,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Iterate(fn func(item T))
|
func (s Set[T]) Iterate(fn func(item T))
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -429,9 +429,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EachWithBreak">EachWithBreak</span>
|
||||||
|
|
||||||
|
<p>遍历集合的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
s.EachWithBreak(func(n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum) //6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsEmpty">IsEmpty</span>
|
### <span id="IsEmpty">IsEmpty</span>
|
||||||
|
|
||||||
<p>判断集合是否为空</p>
|
<p>判断集合是否为空</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -439,6 +475,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) IsEmpty() bool
|
func (s Set[T]) IsEmpty() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -458,9 +495,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>求两个集合的并集</p>
|
<p>求两个集合的并集</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -468,6 +504,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -487,9 +524,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Intersection">Intersection</span>
|
### <span id="Intersection">Intersection</span>
|
||||||
|
|
||||||
<p>求两个集合的交集</p>
|
<p>求两个集合的交集</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -497,6 +533,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -516,8 +553,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||||
|
|
||||||
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -525,6 +562,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -544,11 +582,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Minus">Minus</span>
|
### <span id="Minus">Minus</span>
|
||||||
|
|
||||||
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
|
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -556,6 +591,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -579,5 +615,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pop">Pop</span>
|
||||||
|
|
||||||
|
<p>删除并返回集合中的顶部元素</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet[int]()
|
||||||
|
s.Add(1)
|
||||||
|
s.Add(2)
|
||||||
|
s.Add(3)
|
||||||
|
|
||||||
|
val, ok = s.Pop()
|
||||||
|
|
||||||
|
fmt.Println(val) // 3
|
||||||
|
fmt.Println(ok) // true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
227
docs/mathutil.md
227
docs/mathutil.md
@@ -34,6 +34,12 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [Range](#Range)
|
||||||
|
- [RangeWithStep](#RangeWithStep)
|
||||||
|
- [AngleToRadian](#AngleToRadian)
|
||||||
|
- [RadianToAngle](#RadianToAngle)
|
||||||
|
- [PointDistance](#PointDistance)
|
||||||
|
- [IsPrime](#IsPrime)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -476,3 +482,224 @@ func main() {
|
|||||||
// 0.125
|
// 0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
|
<p>Creates a slice of numbers from start with specified count, element step is 1.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Range(1, 4)
|
||||||
|
result2 := mathutil.Range(1, -4)
|
||||||
|
result3 := mathutil.Range(-4, 4)
|
||||||
|
result4 := mathutil.Range(1.0, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [-4 -3 -2 -1]
|
||||||
|
// [1 2 3 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RangeWithStep">RangeWithStep</span>
|
||||||
|
|
||||||
|
<p>Creates a slice of numbers from start to end with specified step.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RangeWithStep(1, 4, 1)
|
||||||
|
result2 := mathutil.RangeWithStep(1, -1, 0)
|
||||||
|
result3 := mathutil.RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3]
|
||||||
|
// []
|
||||||
|
// [-4 -2 0]
|
||||||
|
// [1 2.1 3.2]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
|
<p>Converts angle value to radian value.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AngleToRadian(angle float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.AngleToRadian(45)
|
||||||
|
result2 := mathutil.AngleToRadian(90)
|
||||||
|
result3 := mathutil.AngleToRadian(180)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0.7853981633974483
|
||||||
|
// 1.5707963267948966
|
||||||
|
// 3.141592653589793
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RadianToAngle">RadianToAngle</span>
|
||||||
|
|
||||||
|
<p>Converts radian value to angle value.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RadianToAngle(radian float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RadianToAngle(math.Pi)
|
||||||
|
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 180
|
||||||
|
// 90
|
||||||
|
// 45
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PointDistance">PointDistance</span>
|
||||||
|
|
||||||
|
<p>Caculates two points distance.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsPrime">IsPrime</span>
|
||||||
|
|
||||||
|
<p>Checks if number is prime number.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrime(n int) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.IsPrime(-1)
|
||||||
|
result2 := mathutil.IsPrime(0)
|
||||||
|
result3 := mathutil.IsPrime(1)
|
||||||
|
result4 := mathutil.IsPrime(2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -34,6 +34,12 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [Range](#Range)
|
||||||
|
- [RangeWithStep](#RangeWithStep)
|
||||||
|
- [AngleToRadian](#AngleToRadian)
|
||||||
|
- [RadianToAngle](#RadianToAngle)
|
||||||
|
- [PointDistance](#PointDistance)
|
||||||
|
- [IsPrime](#IsPrime)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -476,3 +482,223 @@ func main() {
|
|||||||
// 0.125
|
// 0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
|
<p>根据指定的起始值和数量,创建一个数字切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Range(1, 4)
|
||||||
|
result2 := mathutil.Range(1, -4)
|
||||||
|
result3 := mathutil.Range(-4, 4)
|
||||||
|
result4 := mathutil.Range(1.0, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [-4 -3 -2 -1]
|
||||||
|
// [1 2 3 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RangeWithStep">RangeWithStep</span>
|
||||||
|
|
||||||
|
<p>根据指定的起始值,结束值,步长,创建一个数字切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RangeWithStep(1, 4, 1)
|
||||||
|
result2 := mathutil.RangeWithStep(1, -1, 0)
|
||||||
|
result3 := mathutil.RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3]
|
||||||
|
// []
|
||||||
|
// [-4 -2 0]
|
||||||
|
// [1 2.1 3.2]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AngleToRadian">AngleToRadian</span>
|
||||||
|
|
||||||
|
<p>将角度值转为弧度值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AngleToRadian(angle float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.AngleToRadian(45)
|
||||||
|
result2 := mathutil.AngleToRadian(90)
|
||||||
|
result3 := mathutil.AngleToRadian(180)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0.7853981633974483
|
||||||
|
// 1.5707963267948966
|
||||||
|
// 3.141592653589793
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RadianToAngle">RadianToAngle</span>
|
||||||
|
|
||||||
|
<p>将弧度值转为角度值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RadianToAngle(radian float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RadianToAngle(math.Pi)
|
||||||
|
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 180
|
||||||
|
// 90
|
||||||
|
// 45
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="PointDistance">PointDistance</span>
|
||||||
|
|
||||||
|
<p>计算两个坐标点的距离</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsPrime">IsPrime</span>
|
||||||
|
|
||||||
|
<p>判断质数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrime(n int) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.IsPrime(-1)
|
||||||
|
result2 := mathutil.IsPrime(0)
|
||||||
|
result3 := mathutil.IsPrime(1)
|
||||||
|
result4 := mathutil.IsPrime(2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
}
|
||||||
@@ -591,20 +591,28 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
}
|
}
|
||||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
queryValues := netutil.StructToUrlValues(item)
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
fmt.Println(todoValues.Get("id"))
|
||||||
|
fmt.Println(todoValues.Get("userId"))
|
||||||
fmt.Println(todoValues.Get("name"))
|
fmt.Println(todoValues.Get("name"))
|
||||||
|
fmt.Println(todoValues.Get("status"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -593,20 +593,28 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
}
|
}
|
||||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
queryValues := netutil.StructToUrlValues(item)
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
fmt.Println(todoValues.Get("id"))
|
||||||
|
fmt.Println(todoValues.Get("userId"))
|
||||||
fmt.Println(todoValues.Get("name"))
|
fmt.Println(todoValues.Get("name"))
|
||||||
|
fmt.Println(todoValues.Get("status"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import (
|
|||||||
- [Flatten](#Flatten)
|
- [Flatten](#Flatten)
|
||||||
- [FlattenDeep](#FlattenDeep)
|
- [FlattenDeep](#FlattenDeep)
|
||||||
- [ForEach](#ForEach)
|
- [ForEach](#ForEach)
|
||||||
|
- [ForEachWithBreak](#ForEachWithBreak)
|
||||||
- [GroupBy](#GroupBy)
|
- [GroupBy](#GroupBy)
|
||||||
- [GroupWith](#GroupWith)
|
- [GroupWith](#GroupWith)
|
||||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||||
@@ -1001,6 +1002,44 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
|
<p>Iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="GroupBy">GroupBy</span>
|
### <span id="GroupBy">GroupBy</span>
|
||||||
|
|
||||||
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
|
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import (
|
|||||||
- [Flatten](#Flatten)
|
- [Flatten](#Flatten)
|
||||||
- [FlattenDeep](#FlattenDeep)
|
- [FlattenDeep](#FlattenDeep)
|
||||||
- [ForEach](#ForEach)
|
- [ForEach](#ForEach)
|
||||||
|
- [ForEachWithBreak](#ForEachWithBreak)
|
||||||
- [GroupBy](#GroupBy)
|
- [GroupBy](#GroupBy)
|
||||||
- [GroupWith](#GroupWith)
|
- [GroupWith](#GroupWith)
|
||||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||||
@@ -541,7 +542,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Drop">Drop</span>
|
### <span id="Drop">Drop</span>
|
||||||
|
|
||||||
<p>从切片的头部删除n个元素。</p>
|
<p>从切片的头部删除n个元素。</p>
|
||||||
@@ -1003,6 +1003,44 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
|
<p>遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="GroupBy">GroupBy</span>
|
### <span id="GroupBy">GroupBy</span>
|
||||||
|
|
||||||
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
||||||
|
|||||||
353
docs/structs/field.md
Normal file
353
docs/structs/field.md
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
# Field
|
||||||
|
|
||||||
|
Field is abstract struct field for provide several high level functions
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index:
|
||||||
|
- [Tag](#Tag)
|
||||||
|
- [Name](#Name)
|
||||||
|
- [Value](#Value)
|
||||||
|
- [Kind](#Kind)
|
||||||
|
- [IsEmbedded](#IsEmbedded)
|
||||||
|
- [IsExported](#IsExported)
|
||||||
|
- [IsZero](#IsZero)
|
||||||
|
- [IsSlice](#IsSlice)
|
||||||
|
|
||||||
|
> Note:Since `Field` inherits from `Struct`, it also has all the methods of 'Struct', as follows:
|
||||||
|
|
||||||
|
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#ToMap)
|
||||||
|
- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Fields)
|
||||||
|
- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Field)
|
||||||
|
- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation:
|
||||||
|
|
||||||
|
### <span id="Tag">Tag</span>
|
||||||
|
|
||||||
|
<p>Get a `Tag` of the `Field`, `Tag` is a abstract struct field tag</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Tag() *Tag
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
|
||||||
|
fmt.Println(tag.Name)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Value">Value</span>
|
||||||
|
|
||||||
|
<p>Get the `Field` underlying value</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Value() any
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(n.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 111
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsEmbedded">IsEmbedded</span>
|
||||||
|
|
||||||
|
<p>Check if the field is an embedded field</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsEmbedded() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := structs.New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsEmbedded())
|
||||||
|
fmt.Println(a.IsEmbedded())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsExported">IsExported</span>
|
||||||
|
|
||||||
|
<p>Check if the field is exported</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsExported() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsExported())
|
||||||
|
fmt.Println(a.IsExported())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZero">IsZero</span>
|
||||||
|
|
||||||
|
<p>Check if the field is zero value</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsZero() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsZero())
|
||||||
|
fmt.Println(a.IsZero())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Name">Name</span>
|
||||||
|
|
||||||
|
<p>Get the field name</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Name() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Name())
|
||||||
|
fmt.Println(a.Name())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Name
|
||||||
|
// Age
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Kind">Kind</span>
|
||||||
|
|
||||||
|
<p>Get the field's kind</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Kind() reflect.Kind
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Kind())
|
||||||
|
fmt.Println(a.Kind())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsSlice">IsSlice</span>
|
||||||
|
|
||||||
|
<p>Check if the field is a slice</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsSlice() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := structs.New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
fmt.Println(a.IsSlice())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
353
docs/structs/field_zh-CN.md
Normal file
353
docs/structs/field_zh-CN.md
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
# Field
|
||||||
|
|
||||||
|
Field 包封装了一个抽象的`Field`结构体,提供了操作`struct`属性的相关函数
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录:
|
||||||
|
- [Tag](#Tag)
|
||||||
|
- [Name](#Name)
|
||||||
|
- [Value](#Value)
|
||||||
|
- [Kind](#Kind)
|
||||||
|
- [IsEmbedded](#IsEmbedded)
|
||||||
|
- [IsExported](#IsExported)
|
||||||
|
- [IsZero](#IsZero)
|
||||||
|
- [IsSlice](#IsSlice)
|
||||||
|
|
||||||
|
> 注意:由于`Field`继承于`Struct`,所以同样拥有`Struct`所有方法,如下:
|
||||||
|
|
||||||
|
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)
|
||||||
|
- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)
|
||||||
|
- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Field)
|
||||||
|
- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## API 文档:
|
||||||
|
|
||||||
|
### <span id="Tag">Tag</span>
|
||||||
|
|
||||||
|
<p>获取`Field`的`Tag`,默认的tag key是json</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Tag() *Tag
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
|
||||||
|
fmt.Println(tag.Name)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Value">Value</span>
|
||||||
|
|
||||||
|
<p>获取`Field`属性的值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Value() any
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(n.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 111
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsEmbedded">IsEmbedded</span>
|
||||||
|
|
||||||
|
<p>判断属性是否为嵌入</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsEmbedded() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := structs.New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsEmbedded())
|
||||||
|
fmt.Println(a.IsEmbedded())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsExported">IsExported</span>
|
||||||
|
|
||||||
|
<p>判断属性是否导出</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsExported() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsExported())
|
||||||
|
fmt.Println(a.IsExported())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZero">IsZero</span>
|
||||||
|
|
||||||
|
<p>判断属性是否为零值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsZero() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsZero())
|
||||||
|
fmt.Println(a.IsZero())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Name">Name</span>
|
||||||
|
|
||||||
|
<p>获取属性名</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Name() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Name())
|
||||||
|
fmt.Println(a.Name())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Name
|
||||||
|
// Age
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Kind">Kind</span>
|
||||||
|
|
||||||
|
<p>获取属性Kind</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Kind() reflect.Kind
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Kind())
|
||||||
|
fmt.Println(a.Kind())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsSlice">IsSlice</span>
|
||||||
|
|
||||||
|
<p>判断属性是否是切片</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsSlice() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := structs.New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
fmt.Println(a.IsSlice())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
213
docs/structs/struct.md
Normal file
213
docs/structs/struct.md
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
# Structs
|
||||||
|
|
||||||
|
Struct is abstract struct for provide several high level functions
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index:
|
||||||
|
- [New](#New)
|
||||||
|
- [ToMap](#ToMap)
|
||||||
|
- [Fields](#Fields)
|
||||||
|
- [Field](#Field)
|
||||||
|
- [IsStruct](#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation:
|
||||||
|
|
||||||
|
### <span id="New">New</span>
|
||||||
|
|
||||||
|
<p>The constructor function of the `Struct` </p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func New(value any, tagName ...string) *Struct
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
// to do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToMap">ToMap</span>
|
||||||
|
|
||||||
|
<p>convert a valid struct to a map</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) ToMap() (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
> In addition, provided a convenient static function ToMap
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToMap(v any) (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
// use constructor function
|
||||||
|
s1 := structs.New(p1)
|
||||||
|
m1, _ := s1.ToMap()
|
||||||
|
|
||||||
|
fmt.Println(m1)
|
||||||
|
|
||||||
|
// use static function
|
||||||
|
m2, _ := structs.ToMap(p1)
|
||||||
|
|
||||||
|
fmt.Println(m2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// map[name:11]
|
||||||
|
// map[name:11]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Fields">Fields</span>
|
||||||
|
|
||||||
|
<p>Get all fields of a given struct, that the fields are abstract struct field</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Fields() []*Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
|
||||||
|
fmt.Println(len(fields))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Field">Field</span>
|
||||||
|
|
||||||
|
<p>Get an abstract field of a struct by given field name </p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Field(name string) *Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
f := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(f.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 11
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsStruct">IsStruct</span>
|
||||||
|
|
||||||
|
<p>Check if the struct is valid</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) IsStruct() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
|
||||||
|
fmt.Println(s.IsStruct())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
212
docs/structs/struct_zh-CN.md
Normal file
212
docs/structs/struct_zh-CN.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# Structs
|
||||||
|
|
||||||
|
structs 包封装了一个抽象的`Struct`结构体,提供了操作`struct`的相关函数
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录:
|
||||||
|
- [New](#New)
|
||||||
|
- [ToMap](#ToMap)
|
||||||
|
- [Fields](#Fields)
|
||||||
|
- [Field](#Field)
|
||||||
|
- [IsStruct](#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## API 文档:
|
||||||
|
|
||||||
|
### <span id="New">New</span>
|
||||||
|
|
||||||
|
<p>`Struct`结构体的构造函数</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func New(value any, tagName ...string) *Struct
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
// to do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToMap">ToMap</span>
|
||||||
|
|
||||||
|
<p>将一个合法的struct对象转换为map[string]any</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) ToMap() (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>除此之外,提供一个便捷的静态方法ToMap</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToMap(v any) (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s1 := structs.New(p1)
|
||||||
|
m1, _ := s1.ToMap()
|
||||||
|
|
||||||
|
fmt.Println(m1)
|
||||||
|
|
||||||
|
// 如果不需要Struct更多的方法,可以直接使用ToMap
|
||||||
|
m2, _ := structs.ToMap(p1)
|
||||||
|
|
||||||
|
fmt.Println(m2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// map[name:11]
|
||||||
|
// map[name:11]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Fields">Fields</span>
|
||||||
|
|
||||||
|
<p>获取一个struct对象的属性列表</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Fields() []*Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
|
||||||
|
fmt.Println(len(fields))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Field">Field</span>
|
||||||
|
|
||||||
|
<p>根据属性名获取一个struct对象的属性</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Field(name string) *Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
f := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(f.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 11
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsStruct">IsStruct</span>
|
||||||
|
|
||||||
|
<p>判断是否为一个合法的struct对象</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) IsStruct() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
|
||||||
|
fmt.Println(s.IsStruct())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -45,6 +45,7 @@ import (
|
|||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
- [SplitWords](#SplitWords)
|
- [SplitWords](#SplitWords)
|
||||||
- [WordCount](#WordCount)
|
- [WordCount](#WordCount)
|
||||||
|
- [RemoveNonPrintable](#RemoveNonPrintable)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -938,3 +939,34 @@ func main() {
|
|||||||
// 0
|
// 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
|
||||||
|
|
||||||
|
<p>Remove non-printable characters from a string.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RemoveNonPrintable(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := strutil.RemoveNonPrintable("hello\u00a0 \u200bworld\n")
|
||||||
|
result2 := strutil.RemoveNonPrintable("你好😄")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
// 你好😄
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -45,6 +45,7 @@ import (
|
|||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
- [SplitWords](#SplitWords)
|
- [SplitWords](#SplitWords)
|
||||||
- [WordCount](#WordCount)
|
- [WordCount](#WordCount)
|
||||||
|
- [RemoveNonPrintable](#RemoveNonPrintable)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -937,3 +938,34 @@ func main() {
|
|||||||
// 0
|
// 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
|
||||||
|
|
||||||
|
<p>删除字符串中不可打印的字符。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RemoveNonPrintable(str string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := strutil.RemoveNonPrintable("hello\u00a0 \u200bworld\n")
|
||||||
|
result2 := strutil.RemoveNonPrintable("你好😄")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
// 你好😄
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
- [IsAlpha](#IsAlpha)
|
- [IsAlpha](#IsAlpha)
|
||||||
- [IsAllUpper](#IsAllUpper)
|
- [IsAllUpper](#IsAllUpper)
|
||||||
- [IsAllLower](#IsAllLower)
|
- [IsAllLower](#IsAllLower)
|
||||||
|
- [IsASCII](#IsASCII)
|
||||||
- [IsBase64](#IsBase64)
|
- [IsBase64](#IsBase64)
|
||||||
- [IsChineseMobile](#IsChineseMobile)
|
- [IsChineseMobile](#IsChineseMobile)
|
||||||
- [IsChineseIdNum](#IsChineseIdNum)
|
- [IsChineseIdNum](#IsChineseIdNum)
|
||||||
@@ -50,6 +51,7 @@ import (
|
|||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
- [IsGBK](#IsGBK)
|
- [IsGBK](#IsGBK)
|
||||||
|
- [IsPrintable](#IsPrintable)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -293,6 +295,46 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsASCII">IsASCII</span>
|
||||||
|
|
||||||
|
<p>Checks if string is all ASCII char.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsASCII(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsASCII("ABC")
|
||||||
|
result2 := validator.IsASCII("123")
|
||||||
|
result3 := validator.IsASCII("")
|
||||||
|
result4 := validator.IsASCII("😄")
|
||||||
|
result5 := validator.IsASCII("你好")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsBase64">IsBase64</span>
|
### <span id="IsBase64">IsBase64</span>
|
||||||
|
|
||||||
<p>Check if the string is base64 string.</p>
|
<p>Check if the string is base64 string.</p>
|
||||||
@@ -990,3 +1032,44 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsPrintable">IsPrintable</span>
|
||||||
|
|
||||||
|
<p>Checks if string is all printable chars.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrintable(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsPrintable("ABC")
|
||||||
|
result2 := validator.IsPrintable("{id: 123}")
|
||||||
|
result3 := validator.IsPrintable("")
|
||||||
|
result4 := validator.IsPrintable("😄")
|
||||||
|
result5 := validator.IsPrintable("\u0000")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
- [IsAlpha](#IsAlpha)
|
- [IsAlpha](#IsAlpha)
|
||||||
- [IsAllUpper](#IsAllUpper)
|
- [IsAllUpper](#IsAllUpper)
|
||||||
- [IsAllLower](#IsAllLower)
|
- [IsAllLower](#IsAllLower)
|
||||||
|
- [IsASCII](#IsASCII)
|
||||||
- [IsBase64](#IsBase64)
|
- [IsBase64](#IsBase64)
|
||||||
- [IsChineseMobile](#IsChineseMobile)
|
- [IsChineseMobile](#IsChineseMobile)
|
||||||
- [IsChineseIdNum](#IsChineseIdNum)
|
- [IsChineseIdNum](#IsChineseIdNum)
|
||||||
@@ -50,6 +51,7 @@ import (
|
|||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
- [IsGBK](#IsGBK)
|
- [IsGBK](#IsGBK)
|
||||||
|
- [IsPrintable](#IsPrintable)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -293,6 +295,46 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsASCII">IsASCII</span>
|
||||||
|
|
||||||
|
<p>验证字符串全部为ASCII字符。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsASCII(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsASCII("ABC")
|
||||||
|
result2 := validator.IsASCII("123")
|
||||||
|
result3 := validator.IsASCII("")
|
||||||
|
result4 := validator.IsASCII("😄")
|
||||||
|
result5 := validator.IsASCII("你好")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsBase64">IsBase64</span>
|
### <span id="IsBase64">IsBase64</span>
|
||||||
|
|
||||||
<p>验证字符串是否是base64编码</p>
|
<p>验证字符串是否是base64编码</p>
|
||||||
@@ -990,3 +1032,44 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsPrintable">IsPrintable</span>
|
||||||
|
|
||||||
|
<p>检查字符串是否全部为可打印字符。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsPrintable(str string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := validator.IsPrintable("ABC")
|
||||||
|
result2 := validator.IsPrintable("{id: 123}")
|
||||||
|
result3 := validator.IsPrintable("")
|
||||||
|
result4 := validator.IsPrintable("😄")
|
||||||
|
result5 := validator.IsPrintable("\u0000")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -79,16 +79,18 @@ func (a *Assert) LessOrEqual(expected, actual any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsNil check if value is nil
|
// IsNil check if value is nil
|
||||||
func (a *Assert) IsNil(value any) {
|
func (a *Assert) IsNil(v any) {
|
||||||
if value != nil {
|
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||||
makeTestFailed(a.T, a.CaseName, nil, value)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeTestFailed(a.T, a.CaseName, nil, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotNil check if value is not nil
|
// IsNotNil check if value is not nil
|
||||||
func (a *Assert) IsNotNil(value any) {
|
func (a *Assert) IsNotNil(v any) {
|
||||||
if value == nil {
|
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||||
makeTestFailed(a.T, a.CaseName, "not nil", value)
|
makeTestFailed(a.T, a.CaseName, "not nil", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
internal/error_join.go
Normal file
51
internal/error_join.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
// Note: this file is copyed from the go standart repo (https://github.com/golang/go/blob/master/src/errors/join.go).
|
||||||
|
// just in order to adapt under go1.9
|
||||||
|
// do not use it outside lancet lib.
|
||||||
|
|
||||||
|
// Join returns an error that wraps the given errors.
|
||||||
|
// Any nil error values are discarded.
|
||||||
|
// Join returns nil if errs contains no non-nil values.
|
||||||
|
// The error formats as the concatenation of the strings obtained
|
||||||
|
// by calling the Error method of each element of errs, with a newline
|
||||||
|
// between each string.
|
||||||
|
func JoinError(errs ...error) error {
|
||||||
|
n := 0
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e := &joinError{
|
||||||
|
errs: make([]error, 0, n),
|
||||||
|
}
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
e.errs = append(e.errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
type joinError struct {
|
||||||
|
errs []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *joinError) Error() string {
|
||||||
|
var b []byte
|
||||||
|
for i, err := range e.errs {
|
||||||
|
if i > 0 {
|
||||||
|
b = append(b, '\n')
|
||||||
|
}
|
||||||
|
b = append(b, err.Error()...)
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *joinError) Unwrap() []error {
|
||||||
|
return e.errs
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ func Values[K comparable, V any](m map[K]V) []V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
|
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/hI371iB8Up8
|
||||||
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
||||||
keys := make([]T, 0, len(m))
|
keys := make([]T, 0, len(m))
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
|
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/sg9-oRidh8f
|
||||||
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
|
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
|
||||||
keys := make([]T, 0, len(m))
|
keys := make([]T, 0, len(m))
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
|
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/7ov6BJHbVqh
|
||||||
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterByValues iterates over map, return a new map whose values are all given values.
|
// FilterByValues iterates over map, return a new map whose values are all given values.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/P3-9MdcXegR
|
||||||
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/YJM4Hj5hNwm
|
||||||
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/jXGrWDBfSRp
|
||||||
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/XB7Y10uw20_U
|
||||||
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ type Entry[K comparable, V any] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Entries transforms a map into array of key/value pairs.
|
// Entries transforms a map into array of key/value pairs.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/Ltb11LNcElY
|
||||||
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
||||||
entries := make([]Entry[K, V], 0, len(m))
|
entries := make([]Entry[K, V], 0, len(m))
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FromEntries creates a map based on a slice of key/value pairs
|
// FromEntries creates a map based on a slice of key/value pairs
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/fTdu4sCNjQO
|
||||||
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
||||||
result := make(map[K]V, len(entries))
|
result := make(map[K]V, len(entries))
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transform a map to another type map.
|
// Transform a map to another type map.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/P6ovfToM3zj
|
||||||
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
|
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
|
||||||
result := make(map[K2]V2, len(m))
|
result := make(map[K2]V2, len(m))
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iterat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MapKeys transforms a map to other type map by manipulating it's keys.
|
// MapKeys transforms a map to other type map by manipulating it's keys.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/8scDxWeBDKd
|
||||||
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
|
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
|
||||||
result := make(map[T]V, len(m))
|
result := make(map[T]V, len(m))
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MapValues transforms a map to other type map by manipulating it's values.
|
// MapValues transforms a map to other type map by manipulating it's values.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/g92aY3fc7Iw
|
||||||
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
|
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
|
||||||
result := make(map[K]T, len(m))
|
result := make(map[K]T, len(m))
|
||||||
|
|
||||||
|
|||||||
@@ -183,3 +183,76 @@ func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
|||||||
}
|
}
|
||||||
return sum / n
|
return sum / n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||||
|
// Play: https://go.dev/play/p/9ke2opxa8ZP
|
||||||
|
func Range[T constraints.Integer | constraints.Float](start T, count int) []T {
|
||||||
|
size := count
|
||||||
|
if count < 0 {
|
||||||
|
size = -count
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]T, size)
|
||||||
|
|
||||||
|
for i, j := 0, start; i < size; i, j = i+1, j+1 {
|
||||||
|
result[i] = j
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeWithStep creates a slice of numbers from start to end with specified step.
|
||||||
|
// Play: https://go.dev/play/p/akLWz0EqOSM
|
||||||
|
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T {
|
||||||
|
result := []T{}
|
||||||
|
|
||||||
|
if start >= end || step == 0 {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := start; i < end; i += step {
|
||||||
|
result = append(result, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// AngleToRadian converts angle value to radian value.
|
||||||
|
// Play: todo
|
||||||
|
func AngleToRadian(angle float64) float64 {
|
||||||
|
radian := angle * (math.Pi / 180)
|
||||||
|
return radian
|
||||||
|
}
|
||||||
|
|
||||||
|
// RadianToAngle converts radian value to angle value.
|
||||||
|
// Play: todo
|
||||||
|
func RadianToAngle(radian float64) float64 {
|
||||||
|
angle := radian * (180 / math.Pi)
|
||||||
|
return angle
|
||||||
|
}
|
||||||
|
|
||||||
|
// PointDistance get two points distance.
|
||||||
|
// Play: todo
|
||||||
|
func PointDistance(x1, y1, x2, y2 float64) float64 {
|
||||||
|
a := x1 - x2
|
||||||
|
b := y1 - y2
|
||||||
|
c := math.Pow(a, 2) + math.Pow(b, 2)
|
||||||
|
|
||||||
|
return math.Sqrt(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrimes checks if number is prime number.
|
||||||
|
// Play: todo
|
||||||
|
func IsPrime(n int) bool {
|
||||||
|
if n < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
|
||||||
|
if n%i == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package mathutil
|
package mathutil
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
func ExampleExponent() {
|
func ExampleExponent() {
|
||||||
result1 := Exponent(10, 0)
|
result1 := Exponent(10, 0)
|
||||||
@@ -185,3 +188,96 @@ func ExampleMinBy() {
|
|||||||
// ab
|
// ab
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleRange() {
|
||||||
|
result1 := Range(1, 4)
|
||||||
|
result2 := Range(1, -4)
|
||||||
|
result3 := Range(-4, 4)
|
||||||
|
result4 := Range(1.0, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [-4 -3 -2 -1]
|
||||||
|
// [1 2 3 4]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRangeWithStep() {
|
||||||
|
result1 := RangeWithStep(1, 4, 1)
|
||||||
|
result2 := RangeWithStep(1, -1, 0)
|
||||||
|
result3 := RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3]
|
||||||
|
// []
|
||||||
|
// [-4 -2 0]
|
||||||
|
// [1 2.1 3.2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAngleToRadian() {
|
||||||
|
result1 := AngleToRadian(45)
|
||||||
|
result2 := AngleToRadian(90)
|
||||||
|
result3 := AngleToRadian(180)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0.7853981633974483
|
||||||
|
// 1.5707963267948966
|
||||||
|
// 3.141592653589793
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRadianToAngle() {
|
||||||
|
result1 := RadianToAngle(math.Pi)
|
||||||
|
result2 := RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 180
|
||||||
|
// 90
|
||||||
|
// 45
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExamplePointDistance() {
|
||||||
|
result1 := PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleIsPrime() {
|
||||||
|
result1 := IsPrime(-1)
|
||||||
|
result2 := IsPrime(0)
|
||||||
|
result3 := IsPrime(1)
|
||||||
|
result4 := IsPrime(2)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mathutil
|
package mathutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
@@ -137,3 +138,76 @@ func TestMinBy(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.Equal("", res3)
|
assert.Equal("", res3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRange(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRange")
|
||||||
|
|
||||||
|
result1 := Range(1, 4)
|
||||||
|
result2 := Range(1, -4)
|
||||||
|
result3 := Range(-4, 4)
|
||||||
|
result4 := Range(1.0, 4)
|
||||||
|
result5 := Range(1, 0)
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, result1)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, result2)
|
||||||
|
assert.Equal([]int{-4, -3, -2, -1}, result3)
|
||||||
|
assert.Equal([]float64{1.0, 2.0, 3.0, 4.0}, result4)
|
||||||
|
assert.Equal([]int{}, result5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRangeWithStep(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRangeWithStep")
|
||||||
|
|
||||||
|
result1 := RangeWithStep(1, 4, 1)
|
||||||
|
result2 := RangeWithStep(1, -1, 0)
|
||||||
|
result3 := RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3}, result1)
|
||||||
|
assert.Equal([]int{}, result2)
|
||||||
|
assert.Equal([]int{-4, -2, 0}, result3)
|
||||||
|
assert.Equal([]float64{1.0, 2.1, 3.2}, result4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAngleToRadian(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestAngleToRadian")
|
||||||
|
|
||||||
|
result1 := AngleToRadian(45)
|
||||||
|
result2 := AngleToRadian(90)
|
||||||
|
result3 := AngleToRadian(180)
|
||||||
|
|
||||||
|
assert.Equal(0.7853981633974483, result1)
|
||||||
|
assert.Equal(1.5707963267948966, result2)
|
||||||
|
assert.Equal(3.141592653589793, result3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRadianToAngle(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestAngleToRadian")
|
||||||
|
|
||||||
|
result1 := RadianToAngle(math.Pi)
|
||||||
|
result2 := RadianToAngle(math.Pi / 2)
|
||||||
|
result3 := RadianToAngle(math.Pi / 4)
|
||||||
|
|
||||||
|
assert.Equal(float64(180), result1)
|
||||||
|
assert.Equal(float64(90), result2)
|
||||||
|
assert.Equal(float64(45), result3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPointDistance(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPointDistance")
|
||||||
|
|
||||||
|
result1 := PointDistance(1, 1, 4, 5)
|
||||||
|
|
||||||
|
assert.Equal(float64(5), result1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsPrime(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsPrime")
|
||||||
|
|
||||||
|
assert.Equal(false, IsPrime(-1))
|
||||||
|
assert.Equal(false, IsPrime(0))
|
||||||
|
assert.Equal(false, IsPrime(1))
|
||||||
|
assert.Equal(true, IsPrime(2))
|
||||||
|
assert.Equal(true, IsPrime(3))
|
||||||
|
assert.Equal(false, IsPrime(4))
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,12 +21,11 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ func (client *HttpClient) setTLS(rawUrl string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setHeader set http rquest header
|
// setHeader set http request header
|
||||||
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
|
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
|
||||||
if headers == nil {
|
if headers == nil {
|
||||||
headers = make(http.Header)
|
headers = make(http.Header)
|
||||||
@@ -278,29 +277,15 @@ func validateRequest(req *HttpRequest) error {
|
|||||||
// StructToUrlValues convert struct to url valuse,
|
// StructToUrlValues convert struct to url valuse,
|
||||||
// only convert the field which is exported and has `json` tag.
|
// only convert the field which is exported and has `json` tag.
|
||||||
// Play: https://go.dev/play/p/pFqMkM40w9z
|
// Play: https://go.dev/play/p/pFqMkM40w9z
|
||||||
func StructToUrlValues(targetStruct any) url.Values {
|
func StructToUrlValues(targetStruct any) (url.Values, error) {
|
||||||
rv := reflect.ValueOf(targetStruct)
|
|
||||||
rt := reflect.TypeOf(targetStruct)
|
|
||||||
|
|
||||||
if rt.Kind() == reflect.Ptr {
|
|
||||||
rt = rt.Elem()
|
|
||||||
}
|
|
||||||
if rt.Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
|
|
||||||
}
|
|
||||||
|
|
||||||
result := url.Values{}
|
result := url.Values{}
|
||||||
|
s, err := convertor.StructToMap(targetStruct)
|
||||||
fieldNum := rt.NumField()
|
if err != nil {
|
||||||
pattern := `^[A-Z]`
|
return nil, err
|
||||||
regex := regexp.MustCompile(pattern)
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
name := rt.Field(i).Name
|
|
||||||
tag := rt.Field(i).Tag.Get("json")
|
|
||||||
if regex.MatchString(name) && tag != "" {
|
|
||||||
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
|
|
||||||
}
|
}
|
||||||
|
for k, v := range s {
|
||||||
|
result.Add(k, fmt.Sprintf("%v", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,28 +219,29 @@ func TestStructToUrlValues(t *testing.T) {
|
|||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
UserId int `json:"userId"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item1 := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
UserId: 1,
|
UserId: 123,
|
||||||
|
Name: "",
|
||||||
|
}
|
||||||
|
todoValues, err := StructToUrlValues(item1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("params is invalid: %v", err)
|
||||||
}
|
}
|
||||||
todoValues := StructToUrlValues(todoQuery)
|
|
||||||
|
|
||||||
assert.Equal("1", todoValues.Get("id"))
|
assert.Equal("1", todoValues.Get("id"))
|
||||||
assert.Equal("1", todoValues.Get("userId"))
|
assert.Equal("123", todoValues.Get("userId"))
|
||||||
|
assert.Equal("", todoValues.Get("name"))
|
||||||
|
|
||||||
request := &HttpRequest{
|
item2 := TodoQuery{
|
||||||
RawURL: "https://jsonplaceholder.typicode.com/todos",
|
Id: 2,
|
||||||
Method: "GET",
|
UserId: 456,
|
||||||
QueryParams: todoValues,
|
|
||||||
}
|
}
|
||||||
|
queryValues2, _ := StructToUrlValues(item2)
|
||||||
|
|
||||||
httpClient := NewHttpClient()
|
assert.Equal("2", queryValues2.Get("id"))
|
||||||
resp, err := httpClient.SendRequest(request)
|
assert.Equal("456", queryValues2.Get("userId"))
|
||||||
if err != nil || resp.StatusCode != 200 {
|
assert.Equal("", queryValues2.Get("name"))
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
t.Log("response: ", string(body))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,20 +124,44 @@ func ExampleHttpClient_DecodeResponse() {
|
|||||||
func ExampleStructToUrlValues() {
|
func ExampleStructToUrlValues() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item1 := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
|
}
|
||||||
|
queryValues1, err := StructToUrlValues(item1)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
todoValues := StructToUrlValues(todoQuery)
|
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
item2 := TodoQuery{
|
||||||
fmt.Println(todoValues.Get("name"))
|
Id: 2,
|
||||||
|
UserId: 456,
|
||||||
|
}
|
||||||
|
queryValues2, _ := StructToUrlValues(item2)
|
||||||
|
|
||||||
|
fmt.Println(queryValues1.Get("id"))
|
||||||
|
fmt.Println(queryValues1.Get("userId"))
|
||||||
|
fmt.Println(queryValues1.Get("name"))
|
||||||
|
fmt.Println(queryValues1.Get("status"))
|
||||||
|
|
||||||
|
fmt.Println(queryValues2.Get("id"))
|
||||||
|
fmt.Println(queryValues2.Get("userId"))
|
||||||
|
fmt.Println(queryValues2.Get("name"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// 2
|
||||||
|
// 456
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleConvertMapToQueryString() {
|
func ExampleConvertMapToQueryString() {
|
||||||
|
|||||||
14
pointer/pointer.go
Normal file
14
pointer/pointer.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// ExtractPointer returns the underlying value by the given interface type
|
||||||
|
func ExtractPointer(value any) any {
|
||||||
|
t := reflect.TypeOf(value)
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
|
if t.Kind() != reflect.Pointer {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ExtractPointer(v.Elem().Interface())
|
||||||
|
}
|
||||||
18
pointer/pointer_test.go
Normal file
18
pointer/pointer_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractPointer(t *testing.T) {
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestExtractPointer")
|
||||||
|
|
||||||
|
a := 1
|
||||||
|
b := &a
|
||||||
|
c := &b
|
||||||
|
d := &c
|
||||||
|
|
||||||
|
assert.Equal(1, ExtractPointer(d))
|
||||||
|
}
|
||||||
279
promise/promise.go
Normal file
279
promise/promise.go
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package promise contains some functions to support async programming.
|
||||||
|
package promise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
|
||||||
|
// ref : chebyrash/promise (https://github.com/chebyrash/promise)
|
||||||
|
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||||
|
type Promise[T any] struct {
|
||||||
|
runnable func(resolve func(T), reject func(error))
|
||||||
|
result T
|
||||||
|
err error
|
||||||
|
|
||||||
|
pending bool
|
||||||
|
|
||||||
|
mu *sync.Mutex
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// New create a new promise instance.
|
||||||
|
func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T] {
|
||||||
|
if runnable == nil {
|
||||||
|
panic("runnable function should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &Promise[T]{
|
||||||
|
runnable: runnable,
|
||||||
|
pending: true,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
|
||||||
|
defer p.run()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) run() {
|
||||||
|
p.wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
p.reject(errors.New(fmt.Sprint(err)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
p.runnable(p.resolve, p.reject)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve returns a Promise that has been resolved with a given value.
|
||||||
|
func Resolve[T any](resolution T) *Promise[T] {
|
||||||
|
return &Promise[T]{
|
||||||
|
result: resolution,
|
||||||
|
pending: false,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) resolve(value T) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.result = value
|
||||||
|
p.pending = false
|
||||||
|
|
||||||
|
p.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject returns a Promise that has been rejected with a given error.
|
||||||
|
func Reject[T any](err error) *Promise[T] {
|
||||||
|
return &Promise[T]{
|
||||||
|
err: err,
|
||||||
|
pending: false,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) reject(err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.err = err
|
||||||
|
p.pending = false
|
||||||
|
|
||||||
|
p.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then allows chain calls to other promise methods.
|
||||||
|
func Then[T1, T2 any](promise *Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
|
||||||
|
return New(func(resolve2 func(T2), reject func(error)) {
|
||||||
|
result, err := promise.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve2(resolve1(result))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then allows chain calls to other promise methods.
|
||||||
|
func (p *Promise[T]) Then(resolve func(value T) T) *Promise[T] {
|
||||||
|
return New(func(_resolve func(T), reject func(error)) {
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_resolve(resolve(result))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch allows to chain promises.
|
||||||
|
func Catch[T any](promise *Promise[T], rejection func(err error) error) *Promise[T] {
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
result, err := promise.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(rejection(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch chain an existing promise with an intermediate reject function.
|
||||||
|
func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] {
|
||||||
|
return New(func(resolve func(T), rej func(error)) {
|
||||||
|
resutl, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
rej(reject(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(resutl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Await blocks until the 'runable' to finish execution.
|
||||||
|
func (p *Promise[T]) Await() (T, error) {
|
||||||
|
p.wg.Wait()
|
||||||
|
return p.result, p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type tuple[T1, T2 any] struct {
|
||||||
|
_1 T1
|
||||||
|
_2 T2
|
||||||
|
}
|
||||||
|
|
||||||
|
// All resolves when all of the promises have resolved, reject immediately upon any of the input promises rejecting.
|
||||||
|
func All[T any](promises []*Promise[T]) *Promise[[]T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func([]T), reject func(error)) {
|
||||||
|
valsChan := make(chan tuple[T, int], len(promises))
|
||||||
|
errsChan := make(chan error, 1)
|
||||||
|
|
||||||
|
for idx, p := range promises {
|
||||||
|
idx := idx
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- tuple[T, int]{_1: data, _2: idx}
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- err
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resolutions := make([]T, len(promises))
|
||||||
|
for idx := 0; idx < len(promises); idx++ {
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolutions[val._2] = val._1
|
||||||
|
case err := <-errsChan:
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(resolutions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Race will settle the first fullfiled promise among muti promises.
|
||||||
|
func Race[T any](promises []*Promise[T]) *Promise[T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
valsChan := make(chan T, 1)
|
||||||
|
errsChan := make(chan error, 1)
|
||||||
|
|
||||||
|
for _, p := range promises {
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- data
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- err
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolve(val)
|
||||||
|
case err := <-errsChan:
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any resolves as soon as any of the input's Promises resolve, with the value of the resolved Promise.
|
||||||
|
// Any rejects if all of the given Promises are rejected with a combination of all errors.
|
||||||
|
func Any[T any](promises []*Promise[T]) *Promise[T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
valsChan := make(chan T, 1)
|
||||||
|
errsChan := make(chan tuple[error, int], len(promises))
|
||||||
|
|
||||||
|
for idx, p := range promises {
|
||||||
|
idx := idx
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- data
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- tuple[error, int]{_1: err, _2: idx}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := make([]error, len(promises))
|
||||||
|
for idx := 0; idx < len(promises); idx++ {
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolve(val)
|
||||||
|
return
|
||||||
|
case err := <-errsChan:
|
||||||
|
errs[err._2] = err._1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errCombo := errs[0]
|
||||||
|
for _, err := range errs[1:] {
|
||||||
|
errCombo = internal.JoinError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(errCombo)
|
||||||
|
})
|
||||||
|
}
|
||||||
195
promise/promise_example_test.go
Normal file
195
promise/promise_example_test.go
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
package promise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNew() {
|
||||||
|
p := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello")
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(val)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleThen() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello ")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Then(p1, func(s string) string {
|
||||||
|
return s + "world"
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := p2.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExamplePromise_Then() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello ")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Then(func(s string) string {
|
||||||
|
return s + "world"
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := p2.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCatch() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Catch(p1, func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := p1.Await()
|
||||||
|
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
result2, err := p2.Await()
|
||||||
|
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error1
|
||||||
|
//
|
||||||
|
// error1
|
||||||
|
// error2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExamplePromise_Catch() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Catch(func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := p1.Await()
|
||||||
|
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
result2, err := p2.Await()
|
||||||
|
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error1
|
||||||
|
//
|
||||||
|
// error1
|
||||||
|
// error2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAll() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("c")
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2, p3}
|
||||||
|
p := All(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [a b c]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAny() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error"))
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2, p3}
|
||||||
|
p := Any(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// fast
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRace() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2}
|
||||||
|
p := Race(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// fast
|
||||||
|
}
|
||||||
302
promise/promise_test.go
Normal file
302
promise/promise_test.go
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
package promise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolve(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestResolve")
|
||||||
|
|
||||||
|
p := Resolve("abc")
|
||||||
|
|
||||||
|
assert.Equal("abc", p.result)
|
||||||
|
assert.Equal(false, p.pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReject(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReject")
|
||||||
|
|
||||||
|
err := errors.New("error")
|
||||||
|
p := Reject[string](err)
|
||||||
|
|
||||||
|
assert.Equal("error", p.err.Error())
|
||||||
|
assert.Equal(false, p.pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThen(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestThen")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("abc")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Then(p1, func(data string) string {
|
||||||
|
return data + "de"
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("abc", val)
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("abcde", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromise_Then(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Then")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(int), reject func(error)) {
|
||||||
|
resolve(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Then(func(n int) int {
|
||||||
|
return n + 2
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(1, val)
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(3, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCatch(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCatch")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Catch(p1, func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1", err.Error())
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1\nerror2", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromise_Catch(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Catch")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Catch(func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1", err.Error())
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1\nerror2", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAll(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_All")
|
||||||
|
|
||||||
|
t.Run("AllPromisesFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("c")
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal([]string{"a", "b", "c"}, val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := All(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error3"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAny(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Any")
|
||||||
|
|
||||||
|
t.Run("AnyFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Any([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal("fast", val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := Any(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Any([]*Promise[string]{p1, p2})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRace(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Race")
|
||||||
|
|
||||||
|
t.Run("PromisesFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal("a", val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := Race(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
assert.Equal("", val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error3"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Contain check if the target value is in the slice or not.
|
// Contain check if the target value is in the slice or not.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/_454yEHcNjf
|
||||||
func Contain[T comparable](slice []T, target T) bool {
|
func Contain[T comparable](slice []T, target T) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
if item == target {
|
if item == target {
|
||||||
@@ -34,6 +34,7 @@ func Contain[T comparable](slice []T, target T) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ContainBy returns true if predicate function return true.
|
// ContainBy returns true if predicate function return true.
|
||||||
|
// Play: https://go.dev/play/p/49tkHfX4GNc
|
||||||
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
|
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
if predicate(item) {
|
if predicate(item) {
|
||||||
@@ -420,6 +421,17 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||||
|
// when iteratee return false, will break the for each loop.
|
||||||
|
// Play: https://go.dev/play/p/qScs39f3D9W
|
||||||
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
||||||
|
for i, v := range slice {
|
||||||
|
if !iteratee(i, v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Map creates an slice of values by running each element of slice thru iteratee function.
|
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||||
// Play: https://go.dev/play/p/biaTefqPquw
|
// Play: https://go.dev/play/p/biaTefqPquw
|
||||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||||
@@ -436,7 +448,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
|||||||
// iteratee callback function should returntwo values:
|
// iteratee callback function should returntwo values:
|
||||||
// 1, mapping result.
|
// 1, mapping result.
|
||||||
// 2, whether the result element should be included or not
|
// 2, whether the result element should be included or not
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/J94SZ_9MiIe
|
||||||
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
|
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
|
||||||
result := []U{}
|
result := []U{}
|
||||||
|
|
||||||
@@ -450,7 +462,7 @@ func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
|
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/_QARWlWs1N_F
|
||||||
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
|
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
|
||||||
result := make([]U, 0, len(slice))
|
result := make([]U, 0, len(slice))
|
||||||
|
|
||||||
@@ -1082,7 +1094,7 @@ func IndexOf[T comparable](arr []T, val T) int {
|
|||||||
// LastIndexOf returns the index at which the last occurrence of the item is found in a slice or return -1 if the then cannot be found.
|
// LastIndexOf returns the index at which the last occurrence of the item is found in a slice or return -1 if the then cannot be found.
|
||||||
// Play: https://go.dev/play/p/DokM4cf1IKH
|
// Play: https://go.dev/play/p/DokM4cf1IKH
|
||||||
func LastIndexOf[T comparable](slice []T, item T) int {
|
func LastIndexOf[T comparable](slice []T, item T) int {
|
||||||
for i := len(slice) - 1; i > 0; i-- {
|
for i := len(slice) - 1; i >= 0; i-- {
|
||||||
if item == slice[i] {
|
if item == slice[i] {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,6 +379,25 @@ func ExampleForEach() {
|
|||||||
// [2 3 4]
|
// [2 3 4]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleForEachWithBreak() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleMap() {
|
func ExampleMap() {
|
||||||
nums := []int{1, 2, 3}
|
nums := []int{1, 2, 3}
|
||||||
|
|
||||||
|
|||||||
@@ -307,6 +307,23 @@ func TestForEach(t *testing.T) {
|
|||||||
assert.Equal(expected, numbersAddTwo)
|
assert.Equal(expected, numbersAddTwo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestForEachWithBreak(t *testing.T) {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestForEach")
|
||||||
|
assert.Equal(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
func TestMap(t *testing.T) {
|
||||||
nums := []int{1, 2, 3, 4}
|
nums := []int{1, 2, 3, 4}
|
||||||
multiplyTwo := func(i, num int) int {
|
multiplyTwo := func(i, num int) int {
|
||||||
@@ -856,8 +873,9 @@ func TestIndexOf(t *testing.T) {
|
|||||||
func TestLastIndexOf(t *testing.T) {
|
func TestLastIndexOf(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestLastIndexOf")
|
assert := internal.NewAssert(t, "TestLastIndexOf")
|
||||||
|
|
||||||
arr := []string{"a", "a", "b", "c"}
|
arr := []string{"a", "b", "b", "c"}
|
||||||
assert.Equal(1, LastIndexOf(arr, "a"))
|
assert.Equal(0, LastIndexOf(arr, "a"))
|
||||||
|
assert.Equal(2, LastIndexOf(arr, "b"))
|
||||||
assert.Equal(-1, LastIndexOf(arr, "d"))
|
assert.Equal(-1, LastIndexOf(arr, "d"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
|||||||
|
|
||||||
var zeroValue T
|
var zeroValue T
|
||||||
for next, item, ok := generator(), zeroValue, true; ok; {
|
for next, item, ok := generator(), zeroValue, true; ok; {
|
||||||
|
|
||||||
item, ok = next()
|
item, ok = next()
|
||||||
if ok {
|
if ok {
|
||||||
source = append(source, item)
|
source = append(source, item)
|
||||||
@@ -98,7 +99,7 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := int((end-start)/step) + 1
|
l := int((end-start)/step) + 1
|
||||||
source := make([]T, l, l)
|
source := make([]T, l)
|
||||||
|
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
source[i] = start + (T(i) * step)
|
source[i] = start + (T(i) * step)
|
||||||
@@ -160,7 +161,7 @@ func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
|
|||||||
|
|
||||||
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
||||||
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
||||||
source := make([]T, s.Count(), s.Count())
|
source := make([]T, s.Count())
|
||||||
|
|
||||||
for i, v := range s.source {
|
for i, v := range s.source {
|
||||||
source[i] = mapper(v)
|
source[i] = mapper(v)
|
||||||
|
|||||||
112
structs/field.go
Normal file
112
structs/field.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Field is abstract struct field for provide several high level functions
|
||||||
|
type Field struct {
|
||||||
|
Struct
|
||||||
|
field reflect.StructField
|
||||||
|
tag *Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func newField(v reflect.Value, f reflect.StructField, tagName string) *Field {
|
||||||
|
tag := f.Tag.Get(tagName)
|
||||||
|
field := &Field{
|
||||||
|
field: f,
|
||||||
|
tag: newTag(tag),
|
||||||
|
}
|
||||||
|
field.rvalue = v
|
||||||
|
field.rtype = v.Type()
|
||||||
|
field.TagName = tagName
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag returns the value that the key in the tag string.
|
||||||
|
func (f *Field) Tag() *Tag {
|
||||||
|
return f.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the underlying value of the field.
|
||||||
|
func (f *Field) Value() any {
|
||||||
|
return f.rvalue.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmbedded returns true if the given field is an embedded field.
|
||||||
|
func (f *Field) IsEmbedded() bool {
|
||||||
|
return len(f.field.Index) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExported returns true if the given field is exported.
|
||||||
|
func (f *Field) IsExported() bool {
|
||||||
|
return f.field.IsExported()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the given field is zero value.
|
||||||
|
func (f *Field) IsZero() bool {
|
||||||
|
z := reflect.Zero(f.rvalue.Type()).Interface()
|
||||||
|
v := f.Value()
|
||||||
|
return reflect.DeepEqual(z, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the given field
|
||||||
|
func (f *Field) Name() string {
|
||||||
|
return f.field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind returns the field's kind
|
||||||
|
func (f *Field) Kind() reflect.Kind {
|
||||||
|
return f.rvalue.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSlice check if a struct field type is slice or not
|
||||||
|
func (f *Field) IsSlice() bool {
|
||||||
|
k := f.rvalue.Kind()
|
||||||
|
return k == reflect.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapValue covert field value to map
|
||||||
|
func (f *Field) mapValue(value any) any {
|
||||||
|
val := pointer.ExtractPointer(value)
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
var ret any
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
s := New(val)
|
||||||
|
s.TagName = f.TagName
|
||||||
|
m, _ := s.ToMap()
|
||||||
|
ret = m
|
||||||
|
case reflect.Map:
|
||||||
|
mapEl := v.Type().Elem()
|
||||||
|
switch mapEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
// iterate the map
|
||||||
|
m := make(map[string]any, v.Len())
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
m[key.String()] = f.mapValue(v.MapIndex(key).Interface())
|
||||||
|
}
|
||||||
|
ret = m
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
sEl := v.Type().Elem()
|
||||||
|
switch sEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
slices := make([]any, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
slices[i] = f.mapValue(v.Index(i).Interface())
|
||||||
|
}
|
||||||
|
ret = slices
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
272
structs/field_test.go
Normal file
272
structs/field_test.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestField_Tag(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Tag")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
assert.Equal("name", tag.Name)
|
||||||
|
assert.Equal(true, tag.HasOption("omitempty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Value(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Value")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
assert.Equal("111", n.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsEmbedded(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsEmbedded())
|
||||||
|
assert.Equal(false, a.IsEmbedded())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsExported(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
assert.Equal(true, n.IsExported())
|
||||||
|
assert.Equal(false, a.IsExported())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsZero(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsZero")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsZero())
|
||||||
|
assert.Equal(false, a.IsZero())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Name(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Name")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal("Name", n.Name())
|
||||||
|
assert.Equal("Age", a.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Kind(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Kind")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal(reflect.String, n.Kind())
|
||||||
|
assert.Equal(reflect.Int, a.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsSlice(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsSlice")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
assert.Equal(true, a.IsSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_MapValue(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_MapValue")
|
||||||
|
|
||||||
|
t.Run("nested struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c1,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child any `json:"child"`
|
||||||
|
}
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &c1
|
||||||
|
c3 := &c2
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c3,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []int `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []int{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal([]int{1, 2, 3}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr array struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *[]*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: &[]*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested map in struct", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child map[string]any `json:"child"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}}, val)
|
||||||
|
})
|
||||||
|
}
|
||||||
117
structs/struct.go
Normal file
117
structs/struct.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// Package structs provide several high level functions to manipulate struct, tag, and field.
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// defaultTagName is the default tag for struct fields to lookup.
|
||||||
|
var defaultTagName = "json"
|
||||||
|
|
||||||
|
// Struct is abstract struct for provide several high level functions
|
||||||
|
type Struct struct {
|
||||||
|
raw any
|
||||||
|
rtype reflect.Type
|
||||||
|
rvalue reflect.Value
|
||||||
|
TagName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new *Struct
|
||||||
|
func New(value any, tagName ...string) *Struct {
|
||||||
|
value = pointer.ExtractPointer(value)
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
t := reflect.TypeOf(value)
|
||||||
|
|
||||||
|
tn := defaultTagName
|
||||||
|
|
||||||
|
if len(tagName) > 0 {
|
||||||
|
tn = tagName[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// if need: can also set defaultTagName to tn across structs package level
|
||||||
|
// defaultTagName = tn
|
||||||
|
|
||||||
|
return &Struct{
|
||||||
|
raw: value,
|
||||||
|
rtype: t,
|
||||||
|
rvalue: v,
|
||||||
|
TagName: tn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMap converts the given struct to a map[string]any, where the keys
|
||||||
|
// of the keys are the field names and the values of the map are the values
|
||||||
|
// of the fields. The default map key is the struct field name, but you can
|
||||||
|
// change it. The `json` key is the default tag key. Example:
|
||||||
|
//
|
||||||
|
// // default
|
||||||
|
// Name string `json:"name"`
|
||||||
|
//
|
||||||
|
// // ignore the field
|
||||||
|
// Name string // no tag
|
||||||
|
// Age string `json:"-"` // json ignore tag
|
||||||
|
// sex string // unexported field
|
||||||
|
// Goal int `json:"goal,omitempty"` // omitempty if the field is zero value
|
||||||
|
//
|
||||||
|
// // custom map key
|
||||||
|
// Name string `json:"myName"`
|
||||||
|
//
|
||||||
|
// ToMap convert the exported fields of a struct to map.
|
||||||
|
func (s *Struct) ToMap() (map[string]any, error) {
|
||||||
|
if !s.IsStruct() {
|
||||||
|
return nil, errInvalidStruct(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]any)
|
||||||
|
fields := s.Fields()
|
||||||
|
for _, f := range fields {
|
||||||
|
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if f.IsZero() && f.tag.HasOption("omitempty") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result[f.tag.Name] = f.mapValue(f.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields returns all the struct fields within a slice
|
||||||
|
func (s *Struct) Fields() []*Field {
|
||||||
|
var fields []*Field
|
||||||
|
fieldNum := s.rvalue.NumField()
|
||||||
|
for i := 0; i < fieldNum; i++ {
|
||||||
|
v := s.rvalue.Field(i)
|
||||||
|
sf := s.rtype.Field(i)
|
||||||
|
field := newField(v, sf, s.TagName)
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns a Field if the given field name was found
|
||||||
|
func (s *Struct) Field(name string) (*Field, bool) {
|
||||||
|
f, ok := s.rtype.FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return newField(s.rvalue.FieldByName(name), f, s.TagName), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStruct returns true if the given rvalue is a struct
|
||||||
|
func (s *Struct) IsStruct() bool {
|
||||||
|
k := s.rvalue.Kind()
|
||||||
|
if k == reflect.Invalid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return k == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMap convert struct to map, only convert exported struct field
|
||||||
|
// map key is specified same as struct field tag `json` value.
|
||||||
|
func ToMap(v any) (map[string]any, error) {
|
||||||
|
return New(v).ToMap()
|
||||||
|
}
|
||||||
7
structs/struct_internal.go
Normal file
7
structs/struct_internal.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func errInvalidStruct(v any) error {
|
||||||
|
return fmt.Errorf("invalid struct %v", v)
|
||||||
|
}
|
||||||
132
structs/struct_test.go
Normal file
132
structs/struct_test.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStruct_ToMap(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_ToMap")
|
||||||
|
|
||||||
|
t.Run("invalid struct", func(t *testing.T) {
|
||||||
|
m, _ := ToMap(1)
|
||||||
|
var expected map[string]any
|
||||||
|
assert.Equal(expected, m)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("StructToMap", func(_ *testing.T) {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p := &People{
|
||||||
|
"test",
|
||||||
|
100,
|
||||||
|
}
|
||||||
|
pm, _ := ToMap(p)
|
||||||
|
var expected = map[string]any{"name": "test"}
|
||||||
|
assert.Equal(expected, pm)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name,omitempty"` // json tag with attribute
|
||||||
|
Phone string `json:"phone"` // json tag without attribute
|
||||||
|
Sex string `json:"-"` // ignore by "-"
|
||||||
|
Age int // ignore by no tag
|
||||||
|
email string // ignore by unexported
|
||||||
|
IsWorking bool `json:"is_working"`
|
||||||
|
}
|
||||||
|
p1 := People{
|
||||||
|
Name: "AAA", // exist
|
||||||
|
Phone: "1111",
|
||||||
|
Sex: "male",
|
||||||
|
Age: 100,
|
||||||
|
email: "11@gmail.com",
|
||||||
|
}
|
||||||
|
p1m, _ := ToMap(p1)
|
||||||
|
var expect1 = map[string]any{"name": "AAA", "phone": "1111", "is_working": false}
|
||||||
|
assert.Equal(expect1, p1m)
|
||||||
|
|
||||||
|
p2 := People{
|
||||||
|
Name: "",
|
||||||
|
Phone: "2222",
|
||||||
|
Sex: "male",
|
||||||
|
Age: 0,
|
||||||
|
email: "22@gmail.com",
|
||||||
|
IsWorking: true,
|
||||||
|
}
|
||||||
|
p2m, _ := ToMap(p2)
|
||||||
|
var expect2 = map[string]any{"phone": "2222", "is_working": true}
|
||||||
|
assert.Equal(expect2, p2m)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStruct_Fields(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Fields")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int `json:"b"`
|
||||||
|
C []string `json:"c"`
|
||||||
|
D map[string]any `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
A: "1",
|
||||||
|
B: 11,
|
||||||
|
C: []string{"11", "22"},
|
||||||
|
D: map[string]any{"d1": 1, "d2": 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
assert.Equal(4, len(fields))
|
||||||
|
assert.Equal(reflect.String, fields[0].Kind())
|
||||||
|
assert.Equal(reflect.Int, fields[1].Kind())
|
||||||
|
assert.Equal(reflect.Slice, fields[2].Kind())
|
||||||
|
assert.Equal(reflect.Map, fields[3].Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStruct_Field(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Field")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int `json:"b"`
|
||||||
|
C []string `json:"c"`
|
||||||
|
D map[string]any `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
A: "1",
|
||||||
|
B: 11,
|
||||||
|
C: []string{"11", "22"},
|
||||||
|
D: map[string]any{"d1": 1, "d2": 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
a, ok := s.Field("A")
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(reflect.String, a.Kind())
|
||||||
|
assert.Equal("1", a.Value())
|
||||||
|
assert.Equal("a", a.tag.Name)
|
||||||
|
assert.Equal(false, a.tag.HasOption("omitempty"))
|
||||||
|
assert.Equal(false, a.tag.IsEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStruct_IsStruct(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestStruct_Field")
|
||||||
|
|
||||||
|
type Test1 struct{}
|
||||||
|
t1 := &Test1{}
|
||||||
|
t2 := 1
|
||||||
|
|
||||||
|
s1 := New(t1)
|
||||||
|
s2 := New(t2)
|
||||||
|
|
||||||
|
assert.Equal(true, s1.IsStruct())
|
||||||
|
assert.Equal(false, s2.IsStruct())
|
||||||
|
}
|
||||||
36
structs/tag.go
Normal file
36
structs/tag.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tag is abstract struct field tag
|
||||||
|
type Tag struct {
|
||||||
|
Name string
|
||||||
|
Options []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTag(tag string) *Tag {
|
||||||
|
res := strings.Split(tag, ",")
|
||||||
|
return &Tag{
|
||||||
|
Name: res[0],
|
||||||
|
Options: res[1:],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasOption check if a struct field tag has option setting.
|
||||||
|
func (t *Tag) HasOption(opt string) bool {
|
||||||
|
for _, o := range t.Options {
|
||||||
|
if o == opt {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty check if a struct field has tag setting.
|
||||||
|
func (t *Tag) IsEmpty() bool {
|
||||||
|
return validator.IsEmptyString(t.Name)
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ func LowerFirst(s string) string {
|
|||||||
|
|
||||||
// PadStart pads string on the left and right side if it's shorter than size.
|
// PadStart pads string on the left and right side if it's shorter than size.
|
||||||
// Padding characters are truncated if they exceed size.
|
// Padding characters are truncated if they exceed size.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/NzImQq-VF8q
|
||||||
func Pad(source string, size int, padStr string) string {
|
func Pad(source string, size int, padStr string) string {
|
||||||
return padAtPosition(source, size, padStr, 0)
|
return padAtPosition(source, size, padStr, 0)
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ func Substring(s string, offset int, length uint) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SplitWords splits a string into words, word only contains alphabetic characters.
|
// SplitWords splits a string into words, word only contains alphabetic characters.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/KLiX4WiysMM
|
||||||
func SplitWords(s string) []string {
|
func SplitWords(s string) []string {
|
||||||
var word string
|
var word string
|
||||||
var words []string
|
var words []string
|
||||||
@@ -331,7 +331,7 @@ func SplitWords(s string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WordCount return the number of meaningful word, word only contains alphabetic characters.
|
// WordCount return the number of meaningful word, word only contains alphabetic characters.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/bj7_odx3vRf
|
||||||
func WordCount(s string) int {
|
func WordCount(s string) int {
|
||||||
var r rune
|
var r rune
|
||||||
var size, count int
|
var size, count int
|
||||||
@@ -360,3 +360,16 @@ func WordCount(s string) int {
|
|||||||
|
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveNonPrintable remove non-printable characters from a string.
|
||||||
|
// Play: todo
|
||||||
|
func RemoveNonPrintable(str string) string {
|
||||||
|
result := strings.Map(func(r rune) rune {
|
||||||
|
if unicode.IsPrint(r) {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}, str)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -438,3 +438,14 @@ func ExampleWordCount() {
|
|||||||
// 0
|
// 0
|
||||||
// 0
|
// 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleRemoveNonPrintable() {
|
||||||
|
result1 := RemoveNonPrintable("hello\u00a0 \u200bworld\n")
|
||||||
|
result2 := RemoveNonPrintable("你好😄")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
// 你好😄
|
||||||
|
}
|
||||||
|
|||||||
@@ -342,3 +342,10 @@ func TestWordCount(t *testing.T) {
|
|||||||
assert.Equal(v, WordCount(k))
|
assert.Equal(v, WordCount(k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRemoveNonPrintable(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRemoveNonPrintable")
|
||||||
|
|
||||||
|
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
|
||||||
|
assert.Equal("你好😄", RemoveNonPrintable("你好😄"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,6 +58,31 @@ func IsAllLower(str string) bool {
|
|||||||
return str != ""
|
return str != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsASCII checks if string is all ASCII char.
|
||||||
|
// Play: todo
|
||||||
|
func IsASCII(str string) bool {
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if str[i] > unicode.MaxASCII {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrintable checks if string is all printable chars.
|
||||||
|
// Play: todo
|
||||||
|
func IsPrintable(str string) bool {
|
||||||
|
for _, r := range str {
|
||||||
|
if !unicode.IsPrint(r) {
|
||||||
|
if r == '\n' || r == '\r' || r == '\t' || r == '`' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ContainUpper check if the string contain at least one upper case letter A-Z.
|
// ContainUpper check if the string contain at least one upper case letter A-Z.
|
||||||
// Play: https://go.dev/play/p/CmWeBEk27-z
|
// Play: https://go.dev/play/p/CmWeBEk27-z
|
||||||
func ContainUpper(str string) bool {
|
func ContainUpper(str string) bool {
|
||||||
|
|||||||
@@ -407,3 +407,45 @@ func ExampleIsGBK() {
|
|||||||
// Output:
|
// Output:
|
||||||
// true
|
// true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleIsASCII() {
|
||||||
|
result1 := IsASCII("ABC")
|
||||||
|
result2 := IsASCII("123")
|
||||||
|
result3 := IsASCII("")
|
||||||
|
result4 := IsASCII("😄")
|
||||||
|
result5 := IsASCII("你好")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleIsPrintable() {
|
||||||
|
result1 := IsPrintable("ABC")
|
||||||
|
result2 := IsPrintable("{id: 123}")
|
||||||
|
result3 := IsPrintable("")
|
||||||
|
result4 := IsPrintable("😄")
|
||||||
|
result5 := IsPrintable("\u0000")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|||||||
@@ -401,3 +401,23 @@ func TestIsGBK(t *testing.T) {
|
|||||||
assert.Equal(true, IsGBK(gbkData))
|
assert.Equal(true, IsGBK(gbkData))
|
||||||
assert.Equal(false, utf8.Valid(gbkData))
|
assert.Equal(false, utf8.Valid(gbkData))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsASCII(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsASCII")
|
||||||
|
|
||||||
|
assert.Equal(true, IsASCII("ABC"))
|
||||||
|
assert.Equal(true, IsASCII("123"))
|
||||||
|
assert.Equal(true, IsASCII(""))
|
||||||
|
assert.Equal(false, IsASCII("😄"))
|
||||||
|
assert.Equal(false, IsASCII("你好"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsPrintable(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsPrintable")
|
||||||
|
|
||||||
|
assert.Equal(true, IsPrintable("ABC"))
|
||||||
|
assert.Equal(true, IsPrintable("{id: 123}"))
|
||||||
|
assert.Equal(true, IsPrintable(""))
|
||||||
|
assert.Equal(true, IsPrintable("😄"))
|
||||||
|
assert.Equal(false, IsPrintable("\u0000"))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user