mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-16 02:32:28 +08:00
Compare commits
33 Commits
v2.1.16
...
90945a0399
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
30
README.md
30
README.md
@@ -251,7 +251,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||
- **<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)]
|
||||
|
||||
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||
|
||||
### 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)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
|
||||
|
||||
|
||||
|
||||
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
```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)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
|
||||
### 11. Maputil package includes some functions to manipulate map.
|
||||
|
||||
```go
|
||||
@@ -610,14 +606,19 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||
- **<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)]
|
||||
[[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.
|
||||
[[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.
|
||||
[[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.
|
||||
[[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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
||||
[[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)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
||||
[[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)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||
- **<big>Transform</big>** : transform a map to another type map.
|
||||
[[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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
@@ -759,8 +767,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
||||
[[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.
|
||||
|
||||
```go
|
||||
@@ -834,6 +840,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||
- **<big>ContainBy</big>** : returns true if predicate function return true.
|
||||
[[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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||
@@ -890,6 +897,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||
- **<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)]
|
||||
[[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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
@@ -904,6 +912,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
@@ -1055,6 +1064,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||
- **<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)]
|
||||
[[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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||
@@ -1084,8 +1094,10 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/KLiX4WiysMM)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||
|
||||
### 19. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
@@ -1223,6 +1235,7 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>New</big>** : creates a new XError pointer instance with message.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
|
||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||
@@ -1247,7 +1260,7 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
- **<big>XError_Is</big>** : checks if target error is XError and Error.id of two errors are matched.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Is)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Values</big>** : returns map of key and value that is set by XError.With function.
|
||||
- **<big>XError_Values</big>** : returns map of key and value that is set by XError.With function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Values)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_StackTrace</big>** : returns stack trace which is compatible with pkg/errors.
|
||||
@@ -1263,7 +1276,6 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
|
||||
|
||||
## How to Contribute
|
||||
|
||||
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
|
||||
|
||||
324
README_zh-CN.md
324
README_zh-CN.md
@@ -181,7 +181,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[play](https://go.dev/play/p/g2j08F_zZky)
|
||||
- **<big>Xnor</big>** : 如果 a 和 b 都是真的或 a 和 b 均是假的,则返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xnor)]
|
||||
[[play](https://go.dev/play/p/OuDB9g51643)]]
|
||||
[[play](https://go.dev/play/p/OuDB9g51643)]]
|
||||
- **<big>Nand</big>** : 如果 a 和 b 都为真,返回 false,否则返回 true
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nand)]
|
||||
[[play](https://go.dev/play/p/vSRMLxLIbq8)]
|
||||
@@ -250,7 +250,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
|
||||
[[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。
|
||||
|
||||
@@ -260,103 +260,101 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>AesEcbEncrypt</big>** : 使用AES ECB算法模式加密数据。
|
||||
- **<big>AesEcbEncrypt</big>** : 使用 AES ECB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbEncrypt)]
|
||||
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
|
||||
- **<big>AesEcbDecrypt</big>** : 使用AES ECB算法模解密数据。
|
||||
- **<big>AesEcbDecrypt</big>** : 使用 AES ECB 算法模解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbDecrypt)]
|
||||
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
|
||||
- **<big>AesCbcEncrypt</big>** : 使用AES CBC算法模式加密数据。
|
||||
- **<big>AesCbcEncrypt</big>** : 使用 AES CBC 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcEncrypt)]
|
||||
[[play](https://go.dev/play/p/IOq_g8_lKZD)]
|
||||
- **<big>AesCbcDecrypt</big>** : 使用AES CBC算法模式解密数据。
|
||||
- **<big>AesCbcDecrypt</big>** : 使用 AES CBC 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcDecrypt)]
|
||||
[[play](https://go.dev/play/p/IOq_g8_lKZD)]
|
||||
- **<big>AesCtrCrypt</big>** : 使用AES CTR算法模式加密/解密数据。
|
||||
- **<big>AesCtrCrypt</big>** : 使用 AES CTR 算法模式加密/解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCtrCrypt)]
|
||||
[[play](https://go.dev/play/p/SpaZO0-5Nsp)]
|
||||
- **<big>AesCfbEncrypt</big>** : 使用AES CFB算法模式加密数据。
|
||||
- **<big>AesCfbEncrypt</big>** : 使用 AES CFB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbEncrypt)]
|
||||
[[play](https://go.dev/play/p/tfkF10B13kH)]
|
||||
- **<big>AesCfbDecrypt</big>** : 使用AES CFB算法模式解密数据。
|
||||
- **<big>AesCfbDecrypt</big>** : 使用 AES CFB 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbDecrypt)]
|
||||
[[play](https://go.dev/play/p/tfkF10B13kH)]
|
||||
- **<big>AesOfbEncrypt</big>** : 使用AES OFB算法模式加密数据。
|
||||
- **<big>AesOfbEncrypt</big>** : 使用 AES OFB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbEncrypt)]
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>AesOfbDecrypt</big>** : 使用AES OFB算法模式解密数据。
|
||||
- **<big>AesOfbDecrypt</big>** : 使用 AES OFB 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbDecrypt)]
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>Base64StdEncode</big>** : 将字符串base64编码。
|
||||
- **<big>Base64StdEncode</big>** : 将字符串 base64 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdEncode)]
|
||||
[[play](https://go.dev/play/p/VOaUyQUreoK)]
|
||||
- **<big>Base64StdDecode</big>** : 解码base64字符串。
|
||||
- **<big>Base64StdDecode</big>** : 解码 base64 字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdDecode)]
|
||||
[[play](https://go.dev/play/p/RWQylnJVgIe)]
|
||||
- **<big>DesEcbEncrypt</big>** : 使用DES ECB算法模式加密数据。
|
||||
- **<big>DesEcbEncrypt</big>** : 使用 DES ECB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbEncrypt)]
|
||||
[[play](https://go.dev/play/p/8qivmPeZy4P)]
|
||||
- **<big>DesEcbDecrypt</big>** : 使用DES ECB算法模解密数据。
|
||||
- **<big>DesEcbDecrypt</big>** : 使用 DES ECB 算法模解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbDecrypt)]
|
||||
[[play](https://go.dev/play/p/8qivmPeZy4P)]
|
||||
- **<big>DesCbcEncrypt</big>** : 使用DES CBC算法模式加密数据。
|
||||
- **<big>DesCbcEncrypt</big>** : 使用 DES CBC 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcEncrypt)]
|
||||
[[play](https://go.dev/play/p/4cC4QvWfe3_1)]
|
||||
- **<big>DesCbcDecrypt</big>** : 使用DES CBC算法模式解密数据。
|
||||
- **<big>DesCbcDecrypt</big>** : 使用 DES CBC 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcDecrypt)]
|
||||
[[play](https://go.dev/play/p/4cC4QvWfe3_1)]
|
||||
- **<big>DesCtrCrypt</big>** : 使用DES CTR算法模式加密/解密数据。
|
||||
- **<big>DesCtrCrypt</big>** : 使用 DES CTR 算法模式加密/解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCtrCrypt)]
|
||||
[[play](https://go.dev/play/p/9-T6OjKpcdw)]
|
||||
- **<big>DesCfbEncrypt</big>** : 使用DES CFB算法模式加密数据。
|
||||
- **<big>DesCfbEncrypt</big>** : 使用 DES CFB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbEncrypt)]
|
||||
[[play](https://go.dev/play/p/y-eNxcFBlxL)]
|
||||
- **<big>DesCfbDecrypt</big>** : 使用DES CFB算法模式解密数据。
|
||||
- **<big>DesCfbDecrypt</big>** : 使用 DES CFB 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbDecrypt)]
|
||||
[[play](https://go.dev/play/p/y-eNxcFBlxL)]
|
||||
- **<big>DesOfbEncrypt</big>** : 使用DES OFB算法模式加密数据。
|
||||
- **<big>DesOfbEncrypt</big>** : 使用 DES OFB 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbEncrypt)]
|
||||
[[play](https://go.dev/play/p/74KmNadjN1J)]
|
||||
- **<big>DesOfbDecrypt</big>** : 使用DES OFB算法模式解密数据。
|
||||
- **<big>DesOfbDecrypt</big>** : 使用 DES OFB 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbDecrypt)]
|
||||
[[play](https://go.dev/play/p/74KmNadjN1J)]
|
||||
- **<big>HmacMd5</big>** : 返回字符串md5 hmac值。
|
||||
- **<big>HmacMd5</big>** : 返回字符串 md5 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
- **<big>HmacSha1</big>** : 返回字符串sha1 hmac值。
|
||||
- **<big>HmacSha1</big>** : 返回字符串 sha1 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)]
|
||||
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
|
||||
- **<big>HmacSha256</big>** : 返回字符串sha256 hmac值。
|
||||
- **<big>HmacSha256</big>** : 返回字符串 sha256 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)]
|
||||
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
|
||||
- **<big>HmacSha512</big>** : 返回字符串sha256 hmac值。
|
||||
- **<big>HmacSha512</big>** : 返回字符串 sha256 hmac 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)]
|
||||
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
|
||||
- **<big>Md5String</big>** : 返回字符串md5值。
|
||||
- **<big>Md5String</big>** : 返回字符串 md5 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)]
|
||||
[[play](https://go.dev/play/p/1bLcVetbTOI)]
|
||||
- **<big>Md5File</big>** : 返回文件md5值。
|
||||
- **<big>Md5File</big>** : 返回文件 md5 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)]
|
||||
- **<big>Sha1</big>** : 返回字符串sha1哈希值。
|
||||
- **<big>Sha1</big>** : 返回字符串 sha1 哈希值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)]
|
||||
[[play](https://go.dev/play/p/_m_uoD1deMT)]
|
||||
- **<big>Sha256</big>** :返回字符串sha256哈希值。
|
||||
- **<big>Sha256</big>** :返回字符串 sha256 哈希值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)]
|
||||
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
|
||||
- **<big>Sha512</big>** : 返回字符串sha512哈希值。
|
||||
- **<big>Sha512</big>** : 返回字符串 sha512 哈希值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)]
|
||||
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
|
||||
- **<big>GenerateRsaKey</big>** : 在当前目录下创建rsa私钥文件和公钥文件。
|
||||
- **<big>GenerateRsaKey</big>** : 在当前目录下创建 rsa 私钥文件和公钥文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)]
|
||||
[[play](https://go.dev/play/p/zutRHrDqs0X)]
|
||||
- **<big>RsaEncrypt</big>** : 用公钥文件ras加密数据。
|
||||
- **<big>RsaEncrypt</big>** : 用公钥文件 ras 加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
- **<big>RsaDecrypt</big>** : 用私钥文件rsa解密数据。
|
||||
- **<big>RsaDecrypt</big>** : 用私钥文件 rsa 解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
|
||||
|
||||
|
||||
### 6. datetime 日期时间处理包,格式化日期,比较日期。
|
||||
|
||||
@@ -432,32 +430,30 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>FormatStrToTime</big>** : 将字符串格式化成时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)]
|
||||
[[play](https://go.dev/play/p/1h9FwdU8ql4)]
|
||||
- **<big>NewUnix</big>** : 创建一个unix时间戳。
|
||||
- **<big>NewUnix</big>** : 创建一个 unix 时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)]
|
||||
[[play](https://go.dev/play/p/psoSuh_kLRt)]
|
||||
- **<big>NewUnixNow</big>** : 创建一个当前时间的unix时间戳。
|
||||
- **<big>NewUnixNow</big>** : 创建一个当前时间的 unix 时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)]
|
||||
[[play](https://go.dev/play/p/U4PPx-9D0oz)]
|
||||
- **<big>NewFormat</big>** : 创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳。
|
||||
- **<big>NewFormat</big>** : 创建一个 yyyy-mm-dd hh:mm:ss 格式时间字符串的 unix 时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)]
|
||||
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
|
||||
- **<big>NewISO8601</big>** : 创建一个iso8601格式时间字符串的unix时间戳。
|
||||
- **<big>NewISO8601</big>** : 创建一个 iso8601 格式时间字符串的 unix 时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
- **<big>ToUnix</big>** : 返回unix时间戳。
|
||||
- **<big>ToUnix</big>** : 返回 unix 时间戳。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)]
|
||||
[[play](https://go.dev/play/p/_LUiwAdocjy)]
|
||||
- **<big>ToFormat</big>** : 返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)]
|
||||
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
|
||||
- **<big>ToFormatForTpl</big>** : 返回tpl格式指定的日期字符串。
|
||||
- **<big>ToFormatForTpl</big>** : 返回 tpl 格式指定的日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)]
|
||||
[[play](https://go.dev/play/p/nyXxXcQJ8L5)]
|
||||
- **<big>ToIso8601</big>** : 返回iso8601日期字符串。
|
||||
- **<big>ToIso8601</big>** : 返回 iso8601 日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
|
||||
|
||||
|
||||
### 7. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
@@ -486,14 +482,11 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set_zh-CN.md)]
|
||||
- **<big>Tree</big>** : 二叉搜索树。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree_zh-CN.md)]
|
||||
- **<big>Heap</big>** : 二叉max堆。
|
||||
- **<big>Heap</big>** : 二叉 max 堆。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap_zh-CN.md)]
|
||||
- **<big>Hashmap</big>** : 哈希映射。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
||||
|
||||
|
||||
|
||||
|
||||
### 8. fileutil 包含文件基本操作。
|
||||
|
||||
```go
|
||||
@@ -568,35 +561,34 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>After</big>** : 创建一个函数,当该函数被调用n或更多次之后将执行传入的函数。
|
||||
- **<big>After</big>** : 创建一个函数,当该函数被调用 n 或更多次之后将执行传入的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Before</big>** : 创建一个函数,当该函数被调用不超过n次时,将执行执行传入的函数。
|
||||
- **<big>Before</big>** : 创建一个函数,当该函数被调用不超过 n 次时,将执行执行传入的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)]
|
||||
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
|
||||
- **<big>CurryFn</big>** : 创建柯里化函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#CurryFn)]
|
||||
[[play](https://go.dev/play/p/5HopfDwANKX)]
|
||||
- **<big>Compose</big>** : 从右至左组合函数列表fnList,返回组合后的函数。
|
||||
- **<big>Compose</big>** : 从右至左组合函数列表 fnList,返回组合后的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)]
|
||||
[[play](https://go.dev/play/p/KKfugD4PKYF)]
|
||||
- **<big>Delay</big>** : 延迟delay时间后调用函数。
|
||||
- **<big>Delay</big>** : 延迟 delay 时间后调用函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)]
|
||||
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
|
||||
- **<big>Debounced</big>** : 创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。
|
||||
- **<big>Debounced</big>** : 创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)]
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的channel。
|
||||
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的 channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
- **<big>Pipeline</big>** : 从右至左执行函数列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)]
|
||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
||||
- **<big>Watcher</big>** : Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
|
||||
- **<big>Watcher</big>** : Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
|
||||
### 11. maputil 包括一些操作 map 的函数.
|
||||
|
||||
```go
|
||||
@@ -611,24 +603,30 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>Filter</big>** : 迭代 map 中的每对 key 和 value,返回 map,其中的 key 和 value 符合 predicate 函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)]
|
||||
[[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)]
|
||||
- **<big>FilterByValues</big>** : 迭代map, 返回一个新map,其value都是给定的value值。
|
||||
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map,其 value 都是给定的 value 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
|
||||
- **<big>OmitBy</big>** : Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。
|
||||
[[play](https://go.dev/play/p/P3-9MdcXegR)]
|
||||
- **<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)]
|
||||
- **<big>OmitByKeys</big>** : FilterByKeys的反向操作, 迭代map, 返回一个新map,其key不包括给定的key值。
|
||||
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
|
||||
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map,其 key 不包括给定的 key 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
|
||||
- **<big>OmitByValues</big>** : FilterByValues的反向操作, 迭代map, 返回一个新map,其value不包括给定的value值。
|
||||
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map,其 value 不包括给定的 value 值。
|
||||
[[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 的交集操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||
- **<big>Keys</big>** : 返回 map 中所有 key 组成的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)]
|
||||
[[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)]
|
||||
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||
@@ -638,19 +636,25 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>Values</big>** : 返回 map 中所有 values 组成的切片
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)]
|
||||
[[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)]
|
||||
- **<big>MapKeys</big>** : 操作map的每个key,然后转为新的map。
|
||||
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||
- **<big>MapKeys</big>** : 操作 map 的每个 key,然后转为新的 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
|
||||
- **<big>MapValues</big>** : 操作map的每个value,然后转为新的map。
|
||||
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||
- **<big>MapValues</big>** : 操作 map 的每个 value,然后转为新的 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
|
||||
- **<big>Entries</big>** : 将map转换为键/值对切片。
|
||||
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
|
||||
- **<big>FromEntries</big>** : 基于键/值对的切片创建map。
|
||||
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
|
||||
- **<big>Transform</big>** : 将map转换为其他类型的map。
|
||||
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
|
||||
- **<big>IsDisjoint</big>** : 验证两个map是否具有不同的key。
|
||||
[[play](https://go.dev/play/p/P6ovfToM3zj)]
|
||||
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
@@ -707,64 +711,61 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>ConvertMapToQueryString</big>** : 将map转换成http查询字符串。
|
||||
- **<big>ConvertMapToQueryString</big>** : 将 map 转换成 http 查询字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)]
|
||||
[[play](https://go.dev/play/p/jnNt_qoSnRi)]
|
||||
- **<big>EncodeUrl</big>** : 编码url query string的值(?a=1&b=[2] -> ?a=1&b=%5B2%5D)。
|
||||
- **<big>EncodeUrl</big>** : 编码 url query string 的值(?a=1&b=[2] -> ?a=1&b=%5B2%5D)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#EncodeUrl)]
|
||||
[[play](https://go.dev/play/p/bsZ6BRC4uKI)]
|
||||
- **<big>GetInternalIp</big>** : 获取内部ipv4。
|
||||
- **<big>GetInternalIp</big>** : 获取内部 ipv4。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)]
|
||||
[[play](https://go.dev/play/p/5mbu-gFp7ei)]
|
||||
- **<big>GetIps</big>** : 获取系统ipv4地址列表。
|
||||
- **<big>GetIps</big>** : 获取系统 ipv4 地址列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetIps)]
|
||||
[[play](https://go.dev/play/p/NUFfcEmukx1)]
|
||||
- **<big>GetMacAddrs</big>** : 获取系统mac地址列。
|
||||
- **<big>GetMacAddrs</big>** : 获取系统 mac 地址列。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetMacAddrs)]
|
||||
[[play](https://go.dev/play/p/Rq9UUBS_Xp1)]
|
||||
- **<big>GetPublicIpInfo</big>** : 获取[公网ip信息](http://ip-api.com/json/).
|
||||
- **<big>GetPublicIpInfo</big>** : 获取[公网 ip 信息](http://ip-api.com/json/).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)]
|
||||
[[play](https://go.dev/play/p/YDxIfozsRHR)]
|
||||
- **<big>GetRequestPublicIp</big>** : 获取http请求ip。
|
||||
- **<big>GetRequestPublicIp</big>** : 获取 http 请求 ip。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp)]
|
||||
[[play](https://go.dev/play/p/kxU-YDc_eBo)]
|
||||
- **<big>IsPublicIP</big>** : 判断ip是否是公共ip。
|
||||
- **<big>IsPublicIP</big>** : 判断 ip 是否是公共 ip。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)]
|
||||
[[play](https://go.dev/play/p/nmktSQpJZnn)]
|
||||
- **<big>IsInternalIP</big>** : 判断ip是否是局域网ip。
|
||||
- **<big>IsInternalIP</big>** : 判断 ip 是否是局域网 ip。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)]
|
||||
[[play](https://go.dev/play/p/sYGhXbgO4Cb)]
|
||||
- **<big>HttpRequest</big>** : 用于抽象HTTP请求实体的结构。
|
||||
- **<big>HttpRequest</big>** : 用于抽象 HTTP 请求实体的结构。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpRequest)]
|
||||
[[play](https://go.dev/play/p/jUSgynekH7G)]
|
||||
- **<big>HttpClient</big>** : 用于发送HTTP请求。
|
||||
- **<big>HttpClient</big>** : 用于发送 HTTP 请求。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpClient)]
|
||||
[[play](https://go.dev/play/p/jUSgynekH7G)]
|
||||
- **<big>SendRequest</big>** : 发送http请求。
|
||||
- **<big>SendRequest</big>** : 发送 http 请求。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)]
|
||||
[[play](https://go.dev/play/p/jUSgynekH7G)]
|
||||
- **<big>DecodeResponse</big>** : 解析http响应体到目标结构体。
|
||||
- **<big>DecodeResponse</big>** : 解析 http 响应体到目标结构体。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)]
|
||||
[[play](https://go.dev/play/p/jUSgynekH7G)]
|
||||
- **<big>StructToUrlValues</big>** : 将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag。
|
||||
- **<big>StructToUrlValues</big>** : 将结构体转为 url values, 仅转化结构体导出字段并且包含`json` tag。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)]
|
||||
[[play](https://go.dev/play/p/pFqMkM40w9z)]
|
||||
- **<big>HttpGet<sup>deprecated</sup></big>** : 发送http get请求(已弃用:SendRequest代替)。
|
||||
- **<big>HttpGet<sup>deprecated</sup></big>** : 发送 http get 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)]
|
||||
- **<big>HttpDelete<sup>deprecated</sup></big>** : 发送http delete请求(已弃用:SendRequest代替)。
|
||||
- **<big>HttpDelete<sup>deprecated</sup></big>** : 发送 http delete 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)]
|
||||
- **<big>HttpPost<sup>deprecated</sup></big>** : 发送http post请求(已弃用:SendRequest代替)。
|
||||
- **<big>HttpPost<sup>deprecated</sup></big>** : 发送 http post 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)]
|
||||
- **<big>HttpPut<sup>deprecated</sup></big>** : 发送http put请求(已弃用:SendRequest代替)。
|
||||
- **<big>HttpPut<sup>deprecated</sup></big>** : 发送 http put 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)]
|
||||
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送http patch请求(已弃用:SendRequest代替)。
|
||||
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送 http patch 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)]
|
||||
- **<big>ParseHttpResponse</big>** : 解析http响应体到目标结构体。
|
||||
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
||||
|
||||
|
||||
|
||||
|
||||
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
```go
|
||||
@@ -776,7 +777,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandBytes</big>** : 生成随机字节切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)]
|
||||
[[play](https://go.dev/play/p/EkiLESeXf8d)]
|
||||
- **<big>RandInt</big>** : 生成随机int, 范围[min, max)。
|
||||
- **<big>RandInt</big>** : 生成随机 int, 范围[min, max)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)]
|
||||
[[play](https://go.dev/play/p/pXyyAAI5YxD)]
|
||||
- **<big>RandString</big>** : 生成给定长度的随机字符串,只包含字母(a-zA-Z)。
|
||||
@@ -794,11 +795,9 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandNumeralOrLetter</big>** : 生成给定长度的随机字符串(数字+字母)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)]
|
||||
[[play](https://go.dev/play/p/19CEQvpx2jD)]
|
||||
- **<big>UUIdV4</big>** : 生成UUID v4字符串。
|
||||
- **<big>UUIdV4</big>** : 生成 UUID v4 字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
|
||||
|
||||
|
||||
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
|
||||
@@ -808,24 +807,22 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>Context</big>** : 设置重试context参数。
|
||||
- **<big>Context</big>** : 设置重试 context 参数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)]
|
||||
[[play](https://go.dev/play/p/xnAOOXv9GkS)]
|
||||
- **<big>Retry</big>** : 重试执行函数retryFunc,直到函数运行成功,或被context取消。
|
||||
- **<big>Retry</big>** : 重试执行函数 retryFunc,直到函数运行成功,或被 context 取消。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryFunc</big>** : 重试执行的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryDuration</big>** : 设置重试间隔时间,默认3秒。
|
||||
- **<big>RetryDuration</big>** : 设置重试间隔时间,默认 3 秒。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)]
|
||||
[[play](https://go.dev/play/p/nk2XRmagfVF)]
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认5。
|
||||
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
|
||||
|
||||
### 16. slice 包含操作切片的方法集合。
|
||||
|
||||
```go
|
||||
@@ -833,36 +830,38 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>Contain</big>** : 判断slice是否包含value。
|
||||
- **<big>Contain</big>** : 判断 slice 是否包含 value。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)]
|
||||
[[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)]
|
||||
- **<big>ContainSubSlice</big>** : 判断slice是否包含subslice。
|
||||
[[play](https://go.dev/play/p/49tkHfX4GNc)]
|
||||
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||
- **<big>Chunk</big>** : 按照size参数均分slice。
|
||||
- **<big>Chunk</big>** : 按照 size 参数均分 slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)]
|
||||
[[play](https://go.dev/play/p/b4Pou5j2L_C)]
|
||||
- **<big>Compact</big>** : 去除slice中的假值(false values are false, nil, 0, "")。
|
||||
- **<big>Compact</big>** : 去除 slice 中的假值(false values are false, nil, 0, "")。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)]
|
||||
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
|
||||
- **<big>Concat</big>** : 合并多个slices到一个slice中。
|
||||
- **<big>Concat</big>** : 合并多个 slices 到一个 slice 中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)]
|
||||
[[play](https://go.dev/play/p/gPt-q7zr5mk)]
|
||||
- **<big>Count</big>** : 返回切片中指定元素的个数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)]
|
||||
[[play](https://go.dev/play/p/Mj4oiEnQvRJ)]
|
||||
- **<big>CountBy</big>** : 遍历切片,对每个元素执行函数predicate. 返回符合函数返回值为true的元素的个数。
|
||||
- **<big>CountBy</big>** : 遍历切片,对每个元素执行函数 predicate. 返回符合函数返回值为 true 的元素的个数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#CountBy)]
|
||||
[[play](https://go.dev/play/p/tHOccTMDZCC)]
|
||||
- **<big>Difference</big>** : 创建一个切片,其元素不包含在另一个给定切片中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)]
|
||||
[[play](https://go.dev/play/p/VXvadzLzhDa)]
|
||||
- **<big>DifferenceBy</big>** : 将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值。
|
||||
- **<big>DifferenceBy</big>** : 将两个 slice 中的每个元素调用 iteratee 函数,并比较它们的返回值,如果不相等返回在 slice 中对应的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)]
|
||||
[[play](https://go.dev/play/p/DiivgwM5OnC)]
|
||||
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
|
||||
@@ -871,36 +870,37 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Drop</big>** : 从切片头部删除n个元素。
|
||||
- **<big>Drop</big>** : 从切片头部删除 n 个元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)]
|
||||
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
||||
- **<big>DropRight</big>** : 从切片尾部删除n个元素。
|
||||
- **<big>DropRight</big>** : 从切片尾部删除 n 个元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRight)]
|
||||
[[play](https://go.dev/play/p/8bcXvywZezG)]
|
||||
- **<big>DropWhile</big>** : 从切片的头部删除n个元素,这个n个元素满足predicate函数返回true。
|
||||
- **<big>DropWhile</big>** : 从切片的头部删除 n 个元素,这个 n 个元素满足 predicate 函数返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropWhile)]
|
||||
[[play](https://go.dev/play/p/4rt252UV_qs)]
|
||||
- **<big>DropRightWhile</big>** : 从切片的尾部删除n个元素,这个n个元素满足predicate函数返回true。
|
||||
- **<big>DropRightWhile</big>** : 从切片的尾部删除 n 个元素,这个 n 个元素满足 predicate 函数返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRightWhile)]
|
||||
[[play](https://go.dev/play/p/6wyK3zMY56e)]
|
||||
- **<big>Equal</big>** : 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Equal)]
|
||||
[[play](https://go.dev/play/p/WcRQJ37ifPa)]
|
||||
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数comparator,返回true。
|
||||
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数 comparator,返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回true。
|
||||
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
- **<big>Filter</big>** : 返回切片中通过predicate函数真值测试的所有元素。
|
||||
- **<big>Filter</big>** : 返回切片中通过 predicate 函数真值测试的所有元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)]
|
||||
[[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)]
|
||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过predicate函数真值测试的元素。
|
||||
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</big>** : 从头到尾遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。
|
||||
- **<big>FindLast</big>** : 从头到尾遍历 slice 的元素,返回最后一个通过 predicate 函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/FFDPV_j7URd)]
|
||||
- **<big>Flatten</big>** : 将多维切片展平一层。
|
||||
@@ -911,19 +911,20 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
|
||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用iteratee函数。
|
||||
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||
- **<big>GroupWith</big>** : 创建一个map,key是iteratee遍历slice中的每个元素返回的结果。值是切片元素。
|
||||
- **<big>GroupWith</big>** : 创建一个 map,key 是 iteratee 遍历 slice 中的每个元素返回的结果。值是切片元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)]
|
||||
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : 将接口切片转换为int切片。
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : 将接口切片转换为 int 切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : 将值转换为interface切片。
|
||||
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : 将值转换为 interface 切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>Intersection</big>** : 返回多个切片的交集。
|
||||
@@ -938,7 +939,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>LastIndexOf</big>** : 返回在切片中找到最后一个值的索引,如果找不到该值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/DokM4cf1IKH)]
|
||||
- **<big>Map</big>** : 对slice中的每个元素执行map函数以创建一个新切片。
|
||||
- **<big>Map</big>** : 对 slice 中的每个元素执行 map 函数以创建一个新切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)]
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>Merge</big>** : 合并多个切片(不会消除重复元素)。
|
||||
@@ -947,16 +948,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Reverse</big>** : 反转切片中的元素顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
||||
- **<big>Reduce</big>** : 将切片中的元素依次运行iteratee函数,返回运行结果。
|
||||
- **<big>Reduce</big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>Replace</big>** : 返回切片的副本,其中前n个不重叠的old替换为new。
|
||||
- **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
- **<big>ReplaceAll</big>** : 返回切片的副本,将其中old全部替换为new。
|
||||
- **<big>ReplaceAll</big>** : 返回切片的副本,将其中 old 全部替换为 new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReplaceAll)]
|
||||
[[play](https://go.dev/play/p/CzqXMsuYUrx)]
|
||||
- **<big>Repeat</big>** : 创建一个切片,包含n个传入的item。
|
||||
- **<big>Repeat</big>** : 创建一个切片,包含 n 个传入的 item。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Repeat)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
|
||||
@@ -971,19 +972,19 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>IsSorted</big>** : 检查切片元素是否是有序的(升序或降序)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSorted)]
|
||||
[[play](https://go.dev/play/p/nCE8wPLwSA-)]
|
||||
- **<big>IsSortedByKey</big>** : 通过iteratee函数,检查切片元素是否是有序的。
|
||||
- **<big>IsSortedByKey</big>** : 通过 iteratee 函数,检查切片元素是否是有序的。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSortedByKey)]
|
||||
[[play](https://go.dev/play/p/tUoGB7DOHI4)]
|
||||
- **<big>Sort</big>** : 对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Sort)]
|
||||
[[play](https://go.dev/play/p/V9AVjzf_4Fk)]
|
||||
- **<big>SortBy</big>** : 按照less函数确定的升序规则对切片进行排序。排序不保证稳定性。
|
||||
- **<big>SortBy</big>** : 按照 less 函数确定的升序规则对切片进行排序。排序不保证稳定性。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortBy)]
|
||||
[[play](https://go.dev/play/p/DAhLQSZEumm)]
|
||||
- **<big>SortByField<sup>deprecated</sup></big>** : 按字段对结构切片进行排序。slice元素应为struct,字段类型应为int、uint、string或bool。
|
||||
- **<big>SortByField<sup>deprecated</sup></big>** : 按字段对结构切片进行排序。slice 元素应为 struct,字段类型应为 int、uint、string 或 bool。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)]
|
||||
[[play](https://go.dev/play/p/fU1prOBP9p1)]
|
||||
- **<big>Some</big>** : 如果列表中的任何值通过谓词函数,则返回true。
|
||||
- **<big>Some</big>** : 如果列表中的任何值通过谓词函数,则返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)]
|
||||
[[play](https://go.dev/play/p/4pO9Xf9NDGS)]
|
||||
- **<big>StringSlice<sup>deprecated</sup></big>** : 将接口切片转换为字符串切片。
|
||||
@@ -1001,7 +1002,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Unique</big>** : 删除切片中的重复元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)]
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : 对切片的每个元素调用iteratee函数,然后删除重复元素。
|
||||
- **<big>UniqueBy</big>** : 对切片的每个元素调用 iteratee 函数,然后删除重复元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
- **<big>Union</big>** : 合并多个切片。
|
||||
@@ -1016,10 +1017,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Without</big>** : 创建一个不包括所有给定值的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)]
|
||||
[[play](https://go.dev/play/p/bwhEXEypThg)]
|
||||
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为map。
|
||||
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
|
||||
|
||||
### 17. strutil 包含字符串处理的相关函数。
|
||||
|
||||
@@ -1062,8 +1062,9 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>UpperFirst</big>** : 将字符串的第一个字符转换为大写形式。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)]
|
||||
[[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)]
|
||||
[[play](https://go.dev/play/p/NzImQq-VF8q)]
|
||||
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||
@@ -1093,8 +1094,11 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
|
||||
[[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>** : 返回有意义单词的数量,只支持字母字符单词。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
|
||||
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||
|
||||
|
||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
||||
|
||||
@@ -1161,7 +1165,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsAllLower</big>** : 验证字符串是否全是小写英文字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)]
|
||||
[[play](https://go.dev/play/p/GjqCnOfV6cM)]
|
||||
- **<big>IsBase64</big>** : 验证字符串是否是base64编码。
|
||||
- **<big>IsBase64</big>** : 验证字符串是否是 base64 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)]
|
||||
[[play](https://go.dev/play/p/sWHEySAt6hl)]
|
||||
- **<big>IsChineseMobile</big>** : 验证字符串是否是中国手机号码。
|
||||
@@ -1176,7 +1180,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsCreditCard</big>** : 验证字符串是否是信用卡号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效dns。
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效 dns。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
|
||||
@@ -1191,7 +1195,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)]
|
||||
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
||||
- **<big>IsJSON</big>** : 验证字符串是否是有效json。
|
||||
- **<big>IsJSON</big>** : 验证字符串是否是有效 json。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)]
|
||||
[[play](https://go.dev/play/p/sRS6c4K8jGk)]
|
||||
- **<big>IsRegexMatch</big>** : 验证字符串是否可以匹配正则表达式。
|
||||
@@ -1200,19 +1204,19 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsIntStr</big>** : 验证字符串是否是可以转换为整数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)]
|
||||
[[play](https://go.dev/play/p/jQRtFv-a0Rk)]
|
||||
- **<big>IsIp</big>** : 验证字符串是否是ip地址。
|
||||
- **<big>IsIp</big>** : 验证字符串是否是 ip 地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是ipv4地址。
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是 ipv4 地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是 ipv6 地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
- **<big>IsUrl</big>** : 验证字符串是否是url。
|
||||
- **<big>IsUrl</big>** : 验证字符串是否是 url。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)]
|
||||
[[play](https://go.dev/play/p/pbJGa7F98Ka)]
|
||||
- **<big>IsWeakPassword</big>** : 验证字符串是否是弱密码(只包含字母+数字)。
|
||||
@@ -1221,10 +1225,9 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsZeroValue</big>** : 判断传入的参数值是否为零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为gbk(汉字内部代码扩展规范)。
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk(汉字内部代码扩展规范)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||
|
||||
|
||||
### 20. xerror 包实现一些错误处理函数
|
||||
|
||||
@@ -1234,46 +1237,45 @@ import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>New</big>** : 创建XError对象实例。
|
||||
- **<big>New</big>** : 创建 XError 对象实例。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#New)]
|
||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||
- **<big>Wrap</big>** : 根据error对象创建XError对象实例,可添加message。
|
||||
- **<big>Wrap</big>** : 根据 error 对象创建 XError 对象实例,可添加 message。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Wrap)]
|
||||
[[play](https://go.dev/play/p/5385qT2dCi4)]
|
||||
- **<big>Unwrap</big>** : 从error对象中解构出XError。
|
||||
- **<big>Unwrap</big>** : 从 error 对象中解构出 XError。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)]
|
||||
[[play](https://go.dev/play/p/LKMLep723tu)]
|
||||
- **<big>XError_Wrap</big>** : 创建新的XError对象并将消息和id复制到新的对象中。
|
||||
- **<big>XError_Wrap</big>** : 创建新的 XError 对象并将消息和 id 复制到新的对象中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Wrap)]
|
||||
[[play](https://go.dev/play/p/5385qT2dCi4)]
|
||||
- **<big>XError_Unwrap</big>** : 解构XEerror为error对象。适配github.com/pkg/errors。
|
||||
- **<big>XError_Unwrap</big>** : 解构 XEerror 为 error 对象。适配 github.com/pkg/errors。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Unwrap)]
|
||||
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
|
||||
- **<big>XError_With</big>** : 添加与XError对象的键和值。
|
||||
- **<big>XError_With</big>** : 添加与 XError 对象的键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_With)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_Id</big>** : 设置XError对象的id。
|
||||
- **<big>XError_Id</big>** : 设置 XError 对象的 id。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Id)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Is</big>** : 检查目标error是否为XError,两个错误中的error.id是否匹配。
|
||||
- **<big>XError_Is</big>** : 检查目标 error 是否为 XError,两个错误中的 error.id 是否匹配。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Is)]
|
||||
[[play](https://go.dev/play/p/X6HBlsy58U9)]
|
||||
- **<big>XError_Values</big>** : 返回由With设置的键和值的映射。将合并所有XError键和值。
|
||||
- **<big>XError_Values</big>** : 返回由 With 设置的键和值的映射。将合并所有 XError 键和值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Values)]
|
||||
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
|
||||
- **<big>XError_StackTrace</big>** : 返回与pkg/error兼容的堆栈信息。
|
||||
- **<big>XError_StackTrace</big>** : 返回与 pkg/error 兼容的堆栈信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_StackTrace)]
|
||||
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
|
||||
- **<big>XError_Info</big>** : 返回可打印的XError对象信息。
|
||||
- **<big>XError_Info</big>** : 返回可打印的 XError 对象信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Info)]
|
||||
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
|
||||
- **<big>XError_Error</big>** : 实现标准库的error接口。
|
||||
- **<big>XError_Error</big>** : 实现标准库的 error 接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Error)]
|
||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||
- **<big>TryUnwrap</big>** : 检查error, 如果err为nil则展开,则它返回一个有效值,如果err不是nil则Unwrap使用err发生panic。
|
||||
- **<big>TryUnwrap</big>** : 检查 error, 如果 err 为 nil 则展开,则它返回一个有效值,如果 err 不是 nil 则 Unwrap 使用 err 发生 panic。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
|
||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||
|
||||
|
||||
## 如何贡献代码
|
||||
|
||||
|
||||
279
async/promise.go
Normal file
279
async/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 async contain some featurese to support async programming. eg, promise, asycn/await, eventbus.
|
||||
package async
|
||||
|
||||
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
async/promise_example_test.go
Normal file
195
async/promise_example_test.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package async
|
||||
|
||||
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
async/promise_test.go
Normal file
302
async/promise_test.go
Normal file
@@ -0,0 +1,302 @@
|
||||
package async
|
||||
|
||||
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())
|
||||
})
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// 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
|
||||
|
||||
import (
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"math"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"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.
|
||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||
func StructToMap(value any) (map[string]any, error) {
|
||||
v := reflect.ValueOf(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
|
||||
return structs.ToMap(value)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/FOVY3XJL-6B
|
||||
func CopyProperties[T, U any](dst T, src U) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = errors.New(fmt.Sprintf("%v", e))
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -255,12 +255,12 @@ func ExampleDecodeByte() {
|
||||
|
||||
func ExampleDeepClone() {
|
||||
type Struct struct {
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
unexported string
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
// unexported string
|
||||
}
|
||||
|
||||
cases := []interface{}{
|
||||
@@ -293,7 +293,7 @@ func ExampleDeepClone() {
|
||||
// 1 false
|
||||
// 0.1 false
|
||||
// map[a:1 b:2] false
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
// &{test 1 0.1 true <nil>} false
|
||||
}
|
||||
|
||||
func ExampleCopyProperties() {
|
||||
@@ -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}
|
||||
|
||||
employee1 := Employee{}
|
||||
CopyProperties(&employee1, &user)
|
||||
err := CopyProperties(&employee1, &user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||
|
||||
CopyProperties(&employee2, &user)
|
||||
err = CopyProperties(&employee2, &user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(employee1)
|
||||
fmt.Println(employee2)
|
||||
|
||||
@@ -180,18 +180,36 @@ func TestToMap(t *testing.T) {
|
||||
func TestStructToMap(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStructToMap")
|
||||
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
age int
|
||||
}
|
||||
p := People{
|
||||
"test",
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
t.Run("StructToMap", func(_ *testing.T) {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
age int
|
||||
}
|
||||
p := People{
|
||||
"test",
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
var expected = map[string]any{"name": "test"}
|
||||
assert.Equal(expected, pm)
|
||||
})
|
||||
|
||||
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
|
||||
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) {
|
||||
@@ -259,12 +277,12 @@ func TestDeepClone(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestDeepClone")
|
||||
|
||||
type Struct struct {
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
unexported string
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
// unexported string
|
||||
}
|
||||
|
||||
cases := []interface{}{
|
||||
|
||||
@@ -17,7 +17,7 @@ type mapNode struct {
|
||||
next *mapNode
|
||||
}
|
||||
|
||||
//HashMap implements a hash map
|
||||
// HashMap implements a hash map
|
||||
type HashMap struct {
|
||||
capacity uint64
|
||||
size uint64
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Concurrency
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import (
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [Range](#Range)
|
||||
- [RangeWithStep](#RangeWithStep)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -476,3 +478,81 @@ func main() {
|
||||
// 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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -34,6 +34,8 @@ import (
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [Range](#Range)
|
||||
- [RangeWithStep](#RangeWithStep)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -476,3 +478,81 @@ func main() {
|
||||
// 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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -590,21 +590,29 @@ import (
|
||||
|
||||
func main() {
|
||||
type TodoQuery struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Status string
|
||||
}
|
||||
todoQuery := TodoQuery{
|
||||
Id: 1,
|
||||
Name: "Test",
|
||||
item := TodoQuery{
|
||||
Id: 1,
|
||||
UserId: 123,
|
||||
Name: "test",
|
||||
Status: "completed",
|
||||
}
|
||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
||||
queryValues := netutil.StructToUrlValues(item)
|
||||
|
||||
fmt.Println(todoValues.Get("id"))
|
||||
fmt.Println(todoValues.Get("userId"))
|
||||
fmt.Println(todoValues.Get("name"))
|
||||
fmt.Println(todoValues.Get("status"))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// Test
|
||||
// 123
|
||||
// test
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -592,21 +592,29 @@ import (
|
||||
|
||||
func main() {
|
||||
type TodoQuery struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Status string
|
||||
}
|
||||
todoQuery := TodoQuery{
|
||||
Id: 1,
|
||||
Name: "Test",
|
||||
item := TodoQuery{
|
||||
Id: 1,
|
||||
UserId: 123,
|
||||
Name: "test",
|
||||
Status: "completed",
|
||||
}
|
||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
||||
queryValues := netutil.StructToUrlValues(item)
|
||||
|
||||
fmt.Println(todoValues.Get("id"))
|
||||
fmt.Println(todoValues.Get("userId"))
|
||||
fmt.Println(todoValues.Get("name"))
|
||||
fmt.Println(todoValues.Get("status"))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// Test
|
||||
// 123
|
||||
// test
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
303
docs/slice.md
303
docs/slice.md
@@ -48,6 +48,7 @@ import (
|
||||
- [Flatten](#Flatten)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](#ForEach)
|
||||
- [ForEachWithBreak](#ForEachWithBreak)
|
||||
- [GroupBy](#GroupBy)
|
||||
- [GroupWith](#GroupWith)
|
||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||
@@ -172,28 +173,28 @@ import (
|
||||
|
||||
func main() {
|
||||
type foo struct {
|
||||
A string
|
||||
B int
|
||||
}
|
||||
A string
|
||||
B int
|
||||
}
|
||||
|
||||
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
|
||||
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
|
||||
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
|
||||
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
|
||||
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
|
||||
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
|
||||
|
||||
array2 := []string{"a", "b", "c"}
|
||||
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
|
||||
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
|
||||
array2 := []string{"a", "b", "c"}
|
||||
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
|
||||
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -560,20 +561,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.Drop([]string{"a", "b", "c"}, 0)
|
||||
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
|
||||
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b c]
|
||||
// []
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b c]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -597,20 +598,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.DropRight([]string{"a", "b", "c"}, 0)
|
||||
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
|
||||
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [a b]
|
||||
// [a b c]
|
||||
// []
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [a b]
|
||||
// [a b c]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -634,23 +635,23 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [2 3 4 5]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
// Output:
|
||||
// [2 3 4 5]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -675,24 +676,24 @@ import (
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
result1 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
result1 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [1 2]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
// Output:
|
||||
// [1 2]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
|
||||
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
|
||||
@@ -1321,19 +1360,19 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
getEvenNumStr := func(i, num int) (string, bool) {
|
||||
if num%2 == 0 {
|
||||
return strconv.FormatInt(int64(num), 10), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
getEvenNumStr := func(i, num int) (string, bool) {
|
||||
if num%2 == 0 {
|
||||
return strconv.FormatInt(int64(num), 10), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
result := slice.FilterMap(nums, getEvenNumStr)
|
||||
result := slice.FilterMap(nums, getEvenNumStr)
|
||||
|
||||
fmt.Printf("%#v", result)
|
||||
fmt.Printf("%#v", result)
|
||||
|
||||
// Output:
|
||||
// []string{"2", "4"}
|
||||
// Output:
|
||||
// []string{"2", "4"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1358,15 +1397,15 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4}
|
||||
|
||||
result := slice.FlatMap(nums, func(i int, num int) []string {
|
||||
s := "hi-" + strconv.FormatInt(int64(num), 10)
|
||||
return []string{s}
|
||||
})
|
||||
result := slice.FlatMap(nums, func(i int, num int) []string {
|
||||
s := "hi-" + strconv.FormatInt(int64(num), 10)
|
||||
return []string{s}
|
||||
})
|
||||
|
||||
fmt.Printf("%#v", result)
|
||||
fmt.Printf("%#v", result)
|
||||
|
||||
// Output:
|
||||
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
|
||||
// Output:
|
||||
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1612,17 +1651,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsAscending([]int{1, 2, 3, 4, 5})
|
||||
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
|
||||
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
|
||||
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1646,17 +1685,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsDescending([]int{5, 4, 3, 2, 1})
|
||||
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1680,17 +1719,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsSorted([]int{5, 4, 3, 2, 1})
|
||||
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1714,23 +1753,23 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
return len(s)
|
||||
})
|
||||
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
- [Flatten](#Flatten)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](#ForEach)
|
||||
- [ForEachWithBreak](#ForEachWithBreak)
|
||||
- [GroupBy](#GroupBy)
|
||||
- [GroupWith](#GroupWith)
|
||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||
@@ -172,28 +173,28 @@ import (
|
||||
|
||||
func main() {
|
||||
type foo struct {
|
||||
A string
|
||||
B int
|
||||
}
|
||||
A string
|
||||
B int
|
||||
}
|
||||
|
||||
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
|
||||
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
|
||||
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
|
||||
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
|
||||
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
|
||||
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
|
||||
|
||||
array2 := []string{"a", "b", "c"}
|
||||
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
|
||||
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
|
||||
array2 := []string{"a", "b", "c"}
|
||||
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
|
||||
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -541,7 +542,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Drop">Drop</span>
|
||||
|
||||
<p>从切片的头部删除n个元素。</p>
|
||||
@@ -562,20 +562,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.Drop([]string{"a", "b", "c"}, 0)
|
||||
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
|
||||
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b c]
|
||||
// []
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b c]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -599,20 +599,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.DropRight([]string{"a", "b", "c"}, 0)
|
||||
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
|
||||
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
|
||||
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
|
||||
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [a b]
|
||||
// [a b c]
|
||||
// []
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [a b]
|
||||
// [a b c]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -636,23 +636,23 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [2 3 4 5]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
// Output:
|
||||
// [2 3 4 5]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -677,24 +677,24 @@ import (
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
result1 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
result1 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n != 2
|
||||
})
|
||||
result2 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return true
|
||||
})
|
||||
result3 := slice.DropRightWhile(numbers, func(n int) bool {
|
||||
return n == 0
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [1 2]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
// Output:
|
||||
// [1 2]
|
||||
// []
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
|
||||
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
||||
@@ -1323,19 +1361,19 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
getEvenNumStr := func(i, num int) (string, bool) {
|
||||
if num%2 == 0 {
|
||||
return strconv.FormatInt(int64(num), 10), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
getEvenNumStr := func(i, num int) (string, bool) {
|
||||
if num%2 == 0 {
|
||||
return strconv.FormatInt(int64(num), 10), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
result := slice.FilterMap(nums, getEvenNumStr)
|
||||
result := slice.FilterMap(nums, getEvenNumStr)
|
||||
|
||||
fmt.Printf("%#v", result)
|
||||
fmt.Printf("%#v", result)
|
||||
|
||||
// Output:
|
||||
// []string{"2", "4"}
|
||||
// Output:
|
||||
// []string{"2", "4"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1360,15 +1398,15 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4}
|
||||
|
||||
result := slice.FlatMap(nums, func(i int, num int) []string {
|
||||
s := "hi-" + strconv.FormatInt(int64(num), 10)
|
||||
return []string{s}
|
||||
})
|
||||
result := slice.FlatMap(nums, func(i int, num int) []string {
|
||||
s := "hi-" + strconv.FormatInt(int64(num), 10)
|
||||
return []string{s}
|
||||
})
|
||||
|
||||
fmt.Printf("%#v", result)
|
||||
fmt.Printf("%#v", result)
|
||||
|
||||
// Output:
|
||||
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
|
||||
// Output:
|
||||
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1587,8 +1625,8 @@ func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
result := slice.Shuffle(nums)
|
||||
|
||||
fmt.Println(res)
|
||||
|
||||
fmt.Println(res)
|
||||
|
||||
// Output:
|
||||
// [3 1 5 4 2] (random order)
|
||||
}
|
||||
@@ -1614,17 +1652,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsAscending([]int{1, 2, 3, 4, 5})
|
||||
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
|
||||
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
|
||||
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1648,17 +1686,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsDescending([]int{5, 4, 3, 2, 1})
|
||||
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1682,17 +1720,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsSorted([]int{5, 4, 3, 2, 1})
|
||||
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
|
||||
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
|
||||
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1716,23 +1754,23 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := slice.IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
return len(s)
|
||||
})
|
||||
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
|
||||
return len(s)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
@@ -79,16 +79,18 @@ func (a *Assert) LessOrEqual(expected, actual any) {
|
||||
}
|
||||
|
||||
// IsNil check if value is nil
|
||||
func (a *Assert) IsNil(value any) {
|
||||
if value != nil {
|
||||
makeTestFailed(a.T, a.CaseName, nil, value)
|
||||
func (a *Assert) IsNil(v any) {
|
||||
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||
return
|
||||
}
|
||||
|
||||
makeTestFailed(a.T, a.CaseName, nil, v)
|
||||
}
|
||||
|
||||
// IsNotNil check if value is not nil
|
||||
func (a *Assert) IsNotNil(value any) {
|
||||
if value == nil {
|
||||
makeTestFailed(a.T, a.CaseName, "not nil", value)
|
||||
func (a *Assert) IsNotNil(v any) {
|
||||
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/7ov6BJHbVqh
|
||||
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) 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.
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/jXGrWDBfSRp
|
||||
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) 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.
|
||||
// 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 {
|
||||
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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Ltb11LNcElY
|
||||
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
||||
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
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/fTdu4sCNjQO
|
||||
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
result := make(map[K]T, len(m))
|
||||
|
||||
|
||||
@@ -183,3 +183,36 @@ func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
}
|
||||
return sum / n
|
||||
}
|
||||
|
||||
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||
// Play: todo
|
||||
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: todo
|
||||
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
|
||||
}
|
||||
|
||||
@@ -185,3 +185,39 @@ func ExampleMinBy() {
|
||||
// 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]
|
||||
}
|
||||
|
||||
@@ -137,3 +137,33 @@ func TestMinBy(t *testing.T) {
|
||||
})
|
||||
assert.Equal("", res3)
|
||||
}
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "Range")
|
||||
|
||||
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, "Range")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -21,12 +21,11 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"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) {
|
||||
if headers == nil {
|
||||
headers = make(http.Header)
|
||||
@@ -278,29 +277,15 @@ func validateRequest(req *HttpRequest) error {
|
||||
// StructToUrlValues convert struct to url valuse,
|
||||
// only convert the field which is exported and has `json` tag.
|
||||
// Play: https://go.dev/play/p/pFqMkM40w9z
|
||||
func StructToUrlValues(targetStruct any) url.Values {
|
||||
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))
|
||||
}
|
||||
|
||||
func StructToUrlValues(targetStruct any) (url.Values, error) {
|
||||
result := url.Values{}
|
||||
|
||||
fieldNum := rt.NumField()
|
||||
pattern := `^[A-Z]`
|
||||
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()))
|
||||
}
|
||||
s, err := convertor.StructToMap(targetStruct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range s {
|
||||
result.Add(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -217,30 +217,31 @@ func TestStructToUrlValues(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStructToUrlValues")
|
||||
|
||||
type TodoQuery struct {
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
todoQuery := TodoQuery{
|
||||
item1 := TodoQuery{
|
||||
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("userId"))
|
||||
assert.Equal("123", todoValues.Get("userId"))
|
||||
assert.Equal("", todoValues.Get("name"))
|
||||
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos",
|
||||
Method: "GET",
|
||||
QueryParams: todoValues,
|
||||
item2 := TodoQuery{
|
||||
Id: 2,
|
||||
UserId: 456,
|
||||
}
|
||||
queryValues2, _ := StructToUrlValues(item2)
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
resp, err := httpClient.SendRequest(request)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Log("response: ", string(body))
|
||||
assert.Equal("2", queryValues2.Get("id"))
|
||||
assert.Equal("456", queryValues2.Get("userId"))
|
||||
assert.Equal("", queryValues2.Get("name"))
|
||||
}
|
||||
|
||||
@@ -123,21 +123,45 @@ func ExampleHttpClient_DecodeResponse() {
|
||||
|
||||
func ExampleStructToUrlValues() {
|
||||
type TodoQuery struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Status string
|
||||
}
|
||||
todoQuery := TodoQuery{
|
||||
Id: 1,
|
||||
Name: "Test",
|
||||
item1 := TodoQuery{
|
||||
Id: 1,
|
||||
UserId: 123,
|
||||
Name: "test",
|
||||
Status: "completed",
|
||||
}
|
||||
queryValues1, err := StructToUrlValues(item1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
todoValues := StructToUrlValues(todoQuery)
|
||||
|
||||
fmt.Println(todoValues.Get("id"))
|
||||
fmt.Println(todoValues.Get("name"))
|
||||
item2 := TodoQuery{
|
||||
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:
|
||||
// 1
|
||||
// Test
|
||||
// 123
|
||||
// test
|
||||
//
|
||||
// 2
|
||||
// 456
|
||||
//
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
)
|
||||
|
||||
// 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 {
|
||||
for _, item := range slice {
|
||||
if item == target {
|
||||
@@ -34,6 +34,7 @@ func Contain[T comparable](slice []T, target T) bool {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
for _, item := range slice {
|
||||
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.
|
||||
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
||||
loop:
|
||||
for i, v := range slice {
|
||||
if !iteratee(i, v) {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/biaTefqPquw
|
||||
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:
|
||||
// 1, mapping result.
|
||||
// 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 {
|
||||
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.
|
||||
// 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 {
|
||||
result := make([]U, 0, len(slice))
|
||||
|
||||
|
||||
@@ -379,6 +379,25 @@ func ExampleForEach() {
|
||||
// [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() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
|
||||
@@ -307,6 +307,23 @@ func TestForEach(t *testing.T) {
|
||||
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) {
|
||||
nums := []int{1, 2, 3, 4}
|
||||
multiplyTwo := func(i, num int) int {
|
||||
|
||||
@@ -64,6 +64,7 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
||||
|
||||
var zeroValue T
|
||||
for next, item, ok := generator(), zeroValue, true; ok; {
|
||||
|
||||
item, ok = next()
|
||||
if ok {
|
||||
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
|
||||
source := make([]T, l, l)
|
||||
source := make([]T, l)
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
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.
|
||||
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 {
|
||||
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)
|
||||
})
|
||||
}
|
||||
116
structs/struct.go
Normal file
116
structs/struct.go
Normal file
@@ -0,0 +1,116 @@
|
||||
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.
|
||||
// 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 {
|
||||
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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/KLiX4WiysMM
|
||||
func SplitWords(s string) []string {
|
||||
var word 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.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/bj7_odx3vRf
|
||||
func WordCount(s string) int {
|
||||
var r rune
|
||||
var size, count int
|
||||
|
||||
Reference in New Issue
Block a user