mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
20 Commits
v2.1.16
...
47dccd63af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47dccd63af | ||
|
|
5e66bc6227 | ||
|
|
7261b281ad | ||
|
|
f79693804b | ||
|
|
534c7a0abc | ||
|
|
4eaff47d38 | ||
|
|
3e019522c7 | ||
|
|
0734f220b3 | ||
|
|
2d2c277090 | ||
|
|
ef1e548dfc | ||
|
|
924589d2da | ||
|
|
77f32f4cc6 | ||
|
|
1755dd249b | ||
|
|
7a25688ec1 | ||
|
|
51a6912eb3 | ||
|
|
28d0428b50 | ||
|
|
6a9eb645bb | ||
|
|
3857b342f6 | ||
|
|
71aa91a58d | ||
|
|
081908bce3 |
28
README.md
28
README.md
@@ -251,7 +251,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||||
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
|
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
|
||||||
|
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||||
|
|
||||||
### 5. Cryptor package is for data encryption and decryption.
|
### 5. Cryptor package is for data encryption and decryption.
|
||||||
|
|
||||||
@@ -456,9 +456,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
|
||||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -593,7 +590,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
### 11. Maputil package includes some functions to manipulate map.
|
### 11. Maputil package includes some functions to manipulate map.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -610,14 +606,19 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||||
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
|
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||||
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
|
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
|
||||||
|
[[play](https://go.dev/play/p/P3-9MdcXegR)]
|
||||||
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
|
||||||
|
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
|
||||||
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||||
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
|
||||||
|
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
|
||||||
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
||||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||||
@@ -626,6 +627,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||||
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
|
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
|
||||||
|
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||||
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
||||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||||
@@ -637,16 +639,22 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||||
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
|
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||||
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
|
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
|
||||||
|
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||||
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
|
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
|
||||||
|
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||||
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
|
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
|
||||||
|
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||||
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
|
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
|
||||||
|
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||||
- **<big>Transform</big>** : transform a map to another type map.
|
- **<big>Transform</big>** : transform a map to another type map.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
|
||||||
|
[[play](https://go.dev/play/p/P6ovfToM3zj)]
|
||||||
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||||
@@ -759,8 +767,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 14. Random package implements some basic functions to generate random int and string.
|
### 14. Random package implements some basic functions to generate random int and string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -834,6 +840,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||||
- **<big>ContainBy</big>** : returns true if predicate function return true.
|
- **<big>ContainBy</big>** : returns true if predicate function return true.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
|
||||||
|
[[play](https://go.dev/play/p/49tkHfX4GNc)]
|
||||||
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
||||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||||
@@ -890,6 +897,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||||
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
|
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
|
||||||
|
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||||
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||||
@@ -904,6 +912,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||||
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
|
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
|
||||||
|
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||||
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
@@ -1055,6 +1064,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||||
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
|
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
|
||||||
|
[[play](https://go.dev/play/p/NzImQq-VF8q)]
|
||||||
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
||||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||||
@@ -1084,8 +1094,10 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||||
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
|
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
|
||||||
|
[[play](https://go.dev/play/p/KLiX4WiysMM)]
|
||||||
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
|
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
|
||||||
|
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||||
|
|
||||||
### 19. System package contain some functions about os, runtime, shell command.
|
### 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:
|
#### Function list:
|
||||||
|
|
||||||
- **<big>New</big>** : creates a new XError pointer instance with message.
|
- **<big>New</big>** : creates a new XError pointer instance with message.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
|
||||||
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
[[play](https://go.dev/play/p/w4oWZts7q7f)]
|
||||||
@@ -1263,7 +1276,6 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
|
||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
|
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
|
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
[[play](https://go.dev/play/p/j4DP5dquxnk)]
|
||||||
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
|
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
|
||||||
|
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||||
|
|
||||||
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||||
|
|
||||||
@@ -356,8 +356,6 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
||||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 6. datetime 日期时间处理包,格式化日期,比较日期。
|
### 6. datetime 日期时间处理包,格式化日期,比较日期。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -457,8 +455,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
||||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 7. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
### 7. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -491,9 +487,6 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
|||||||
- **<big>Hashmap</big>** : 哈希映射。
|
- **<big>Hashmap</big>** : 哈希映射。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 8. fileutil 包含文件基本操作。
|
### 8. fileutil 包含文件基本操作。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -596,7 +589,6 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
### 11. maputil 包括一些操作 map 的函数.
|
### 11. maputil 包括一些操作 map 的函数.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -613,14 +605,19 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||||
- **<big>FilterByKeys</big>** : 迭代 map, 返回一个新 map,其 key 都是给定的 key 值。
|
- **<big>FilterByKeys</big>** : 迭代 map, 返回一个新 map,其 key 都是给定的 key 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
|
||||||
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map,其 value 都是给定的 value 值。
|
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map,其 value 都是给定的 value 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
|
||||||
|
[[play](https://go.dev/play/p/P3-9MdcXegR)]
|
||||||
- **<big>OmitBy</big>** : Filter 的反向操作, 迭代 map 中的每对 key 和 value, 删除符合 predicate 函数的 key, value, 返回新 map。
|
- **<big>OmitBy</big>** : Filter 的反向操作, 迭代 map 中的每对 key 和 value, 删除符合 predicate 函数的 key, value, 返回新 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
|
||||||
|
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
|
||||||
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map,其 key 不包括给定的 key 值。
|
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map,其 key 不包括给定的 key 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
|
||||||
|
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||||
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map,其 value 不包括给定的 value 值。
|
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map,其 value 不包括给定的 value 值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
|
||||||
|
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
|
||||||
- **<big>Intersect</big>** : 多个 map 的交集操作。
|
- **<big>Intersect</big>** : 多个 map 的交集操作。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
||||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||||
@@ -629,6 +626,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||||
- **<big>KeysBy</big>** : 创建一个切片,其元素是每个 map 的 key 调用 mapper 函数的结果。
|
- **<big>KeysBy</big>** : 创建一个切片,其元素是每个 map 的 key 调用 mapper 函数的结果。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
|
||||||
|
[[play](https://go.dev/play/p/hI371iB8Up8)]
|
||||||
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
||||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||||
@@ -640,16 +638,22 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||||
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 map 的 value 调用 mapper 函数的结果。
|
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 map 的 value 调用 mapper 函数的结果。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
|
||||||
|
[[play](https://go.dev/play/p/sg9-oRidh8f)]
|
||||||
- **<big>MapKeys</big>** : 操作 map 的每个 key,然后转为新的 map。
|
- **<big>MapKeys</big>** : 操作 map 的每个 key,然后转为新的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
|
||||||
|
[[play](https://go.dev/play/p/8scDxWeBDKd)]
|
||||||
- **<big>MapValues</big>** : 操作 map 的每个 value,然后转为新的 map。
|
- **<big>MapValues</big>** : 操作 map 的每个 value,然后转为新的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
|
||||||
|
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
|
||||||
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
|
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
|
||||||
|
[[play](https://go.dev/play/p/Ltb11LNcElY)]
|
||||||
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
|
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
|
||||||
|
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
|
||||||
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
|
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
|
||||||
|
[[play](https://go.dev/play/p/P6ovfToM3zj)]
|
||||||
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||||
@@ -762,9 +766,6 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -798,8 +799,6 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
||||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -824,8 +823,6 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
||||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 16. slice 包含操作切片的方法集合。
|
### 16. slice 包含操作切片的方法集合。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -833,6 +830,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 函数列表:
|
#### 函数列表:
|
||||||
|
|
||||||
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
||||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||||
@@ -841,6 +839,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||||
- **<big>ContainBy</big>** : 根据 predicate 函数判断切片是否包含某个值。
|
- **<big>ContainBy</big>** : 根据 predicate 函数判断切片是否包含某个值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
|
||||||
|
[[play](https://go.dev/play/p/49tkHfX4GNc)]
|
||||||
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
|
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
||||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||||
@@ -897,6 +896,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||||
- **<big>FilterMap</big>** : 返回一个将 filter 和 map 操作应用于给定切片的切片。
|
- **<big>FilterMap</big>** : 返回一个将 filter 和 map 操作应用于给定切片的切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
|
||||||
|
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
||||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||||
@@ -911,6 +911,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||||
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
|
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
|
||||||
|
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
|
||||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
@@ -1020,7 +1021,6 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||||
|
|
||||||
|
|
||||||
### 17. strutil 包含字符串处理的相关函数。
|
### 17. strutil 包含字符串处理的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1064,6 +1064,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||||
- **<big>Pad</big>** : 如果字符串长度短于 size,则在左右两侧填充字符串。
|
- **<big>Pad</big>** : 如果字符串长度短于 size,则在左右两侧填充字符串。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
|
||||||
|
[[play](https://go.dev/play/p/NzImQq-VF8q)]
|
||||||
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
||||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||||
@@ -1093,8 +1094,11 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||||
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
|
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
|
||||||
|
[[play](https://go.dev/play/p/KLiX4WiysMM)]
|
||||||
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
|
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
|
||||||
|
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||||
|
|
||||||
|
|
||||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
### 18. system 包含 os, runtime, shell command 的相关函数。
|
||||||
|
|
||||||
@@ -1225,7 +1229,6 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
||||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||||
|
|
||||||
|
|
||||||
### 20. xerror 包实现一些错误处理函数
|
### 20. xerror 包实现一些错误处理函数
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -1274,7 +1277,6 @@ import "github.com/duke-git/lancet/v2/xerror"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
|
||||||
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
[[play](https://go.dev/play/p/acyZVkNZEeW)]
|
||||||
|
|
||||||
|
|
||||||
## 如何贡献代码
|
## 如何贡献代码
|
||||||
|
|
||||||
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -235,31 +235,7 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
|
|||||||
// map key is specified same as struct field tag `json` value.
|
// map key is specified same as struct field tag `json` value.
|
||||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||||
func StructToMap(value any) (map[string]any, error) {
|
func StructToMap(value any) (map[string]any, error) {
|
||||||
v := reflect.ValueOf(value)
|
return structs.ToMap(value)
|
||||||
t := reflect.TypeOf(value)
|
|
||||||
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]any)
|
|
||||||
|
|
||||||
fieldNum := t.NumField()
|
|
||||||
pattern := `^[A-Z]`
|
|
||||||
regex := regexp.MustCompile(pattern)
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
name := t.Field(i).Name
|
|
||||||
tag := t.Field(i).Tag.Get("json")
|
|
||||||
if regex.MatchString(name) && tag != "" {
|
|
||||||
//result[name] = v.Field(i).Interface()
|
|
||||||
result[tag] = v.Field(i).Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapToSlice convert map to slice based on iteratee function.
|
// MapToSlice convert map to slice based on iteratee function.
|
||||||
@@ -343,11 +319,11 @@ func DeepClone[T any](src T) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/FOVY3XJL-6B
|
||||||
func CopyProperties[T, U any](dst T, src U) (err error) {
|
func CopyProperties[T, U any](dst T, src U) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
err = errors.New(fmt.Sprintf("%v", e))
|
err = fmt.Errorf("%v", e)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ func ExampleDeepClone() {
|
|||||||
Float float64
|
Float float64
|
||||||
Bool bool
|
Bool bool
|
||||||
Nil interface{}
|
Nil interface{}
|
||||||
unexported string
|
// unexported string
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []interface{}{
|
cases := []interface{}{
|
||||||
@@ -323,12 +323,18 @@ func ExampleCopyProperties() {
|
|||||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||||
|
|
||||||
employee1 := Employee{}
|
employee1 := Employee{}
|
||||||
CopyProperties(&employee1, &user)
|
err := CopyProperties(&employee1, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||||
|
|
||||||
CopyProperties(&employee2, &user)
|
err = CopyProperties(&employee2, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println(employee1)
|
fmt.Println(employee1)
|
||||||
fmt.Println(employee2)
|
fmt.Println(employee2)
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ func TestToMap(t *testing.T) {
|
|||||||
func TestStructToMap(t *testing.T) {
|
func TestStructToMap(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestStructToMap")
|
assert := internal.NewAssert(t, "TestStructToMap")
|
||||||
|
|
||||||
|
t.Run("StructToMap", func(_ *testing.T) {
|
||||||
type People struct {
|
type People struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
age int
|
age int
|
||||||
@@ -189,9 +190,26 @@ func TestStructToMap(t *testing.T) {
|
|||||||
100,
|
100,
|
||||||
}
|
}
|
||||||
pm, _ := StructToMap(p)
|
pm, _ := StructToMap(p)
|
||||||
|
var expected = map[string]any{"name": "test"}
|
||||||
expected := map[string]any{"name": "test"}
|
|
||||||
assert.Equal(expected, pm)
|
assert.Equal(expected, pm)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name,omitempty"` // json tag with attribute
|
||||||
|
Phone string `json:"phone"` // json tag without attribute
|
||||||
|
Sex string `json:"-"` // ignore
|
||||||
|
age int // no tag
|
||||||
|
}
|
||||||
|
p := People{
|
||||||
|
Phone: "1111",
|
||||||
|
Sex: "male",
|
||||||
|
age: 100,
|
||||||
|
}
|
||||||
|
pm, _ := StructToMap(p)
|
||||||
|
var expected = map[string]any{"phone": "1111"}
|
||||||
|
assert.Equal(expected, pm)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapToSlice(t *testing.T) {
|
func TestMapToSlice(t *testing.T) {
|
||||||
@@ -264,7 +282,7 @@ func TestDeepClone(t *testing.T) {
|
|||||||
Float float64
|
Float float64
|
||||||
Bool bool
|
Bool bool
|
||||||
Nil interface{}
|
Nil interface{}
|
||||||
unexported string
|
// unexported string
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []interface{}{
|
cases := []interface{}{
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [Range](#Range)
|
||||||
|
- [RangeWithStep](#RangeWithStep)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -476,3 +478,81 @@ func main() {
|
|||||||
// 0.125
|
// 0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
|
<p>Creates a slice of numbers from start with specified count, element step is 1.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Range(1, 4)
|
||||||
|
result2 := mathutil.Range(1, -4)
|
||||||
|
result3 := mathutil.Range(-4, 4)
|
||||||
|
result4 := mathutil.Range(1.0, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [-4 -3 -2 -1]
|
||||||
|
// [1 2 3 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RangeWithStep">RangeWithStep</span>
|
||||||
|
|
||||||
|
<p>Creates a slice of numbers from start to end with specified step.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RangeWithStep(1, 4, 1)
|
||||||
|
result2 := mathutil.RangeWithStep(1, -1, 0)
|
||||||
|
result3 := mathutil.RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3]
|
||||||
|
// []
|
||||||
|
// [-4 -2 0]
|
||||||
|
// [1 2.1 3.2]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [Range](#Range)
|
||||||
|
- [RangeWithStep](#RangeWithStep)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -476,3 +478,81 @@ func main() {
|
|||||||
// 0.125
|
// 0.125
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
|
<p>根据指定的起始值和数量,创建一个数字切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Range(1, 4)
|
||||||
|
result2 := mathutil.Range(1, -4)
|
||||||
|
result3 := mathutil.Range(-4, 4)
|
||||||
|
result4 := mathutil.Range(1.0, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [1 2 3 4]
|
||||||
|
// [-4 -3 -2 -1]
|
||||||
|
// [1 2 3 4]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RangeWithStep">RangeWithStep</span>
|
||||||
|
|
||||||
|
<p>根据指定的起始值,结束值,步长,创建一个数字切片。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.RangeWithStep(1, 4, 1)
|
||||||
|
result2 := mathutil.RangeWithStep(1, -1, 0)
|
||||||
|
result3 := mathutil.RangeWithStep(-4, 1, 2)
|
||||||
|
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [1 2 3]
|
||||||
|
// []
|
||||||
|
// [-4 -2 0]
|
||||||
|
// [1 2.1 3.2]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -591,20 +591,28 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
}
|
}
|
||||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
queryValues := netutil.StructToUrlValues(item)
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
fmt.Println(todoValues.Get("id"))
|
||||||
|
fmt.Println(todoValues.Get("userId"))
|
||||||
fmt.Println(todoValues.Get("name"))
|
fmt.Println(todoValues.Get("name"))
|
||||||
|
fmt.Println(todoValues.Get("status"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -593,20 +593,28 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
}
|
}
|
||||||
todoValues := netutil.StructToUrlValues(todoQuery)
|
queryValues := netutil.StructToUrlValues(item)
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
fmt.Println(todoValues.Get("id"))
|
||||||
|
fmt.Println(todoValues.Get("userId"))
|
||||||
fmt.Println(todoValues.Get("name"))
|
fmt.Println(todoValues.Get("name"))
|
||||||
|
fmt.Println(todoValues.Get("status"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import (
|
|||||||
- [Flatten](#Flatten)
|
- [Flatten](#Flatten)
|
||||||
- [FlattenDeep](#FlattenDeep)
|
- [FlattenDeep](#FlattenDeep)
|
||||||
- [ForEach](#ForEach)
|
- [ForEach](#ForEach)
|
||||||
|
- [ForEachWithBreak](#ForEachWithBreak)
|
||||||
- [GroupBy](#GroupBy)
|
- [GroupBy](#GroupBy)
|
||||||
- [GroupWith](#GroupWith)
|
- [GroupWith](#GroupWith)
|
||||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||||
@@ -1001,6 +1002,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
|
<p>Iterates over elements of slice and invokes function for each element, when iteratee return true, will break the for each loop.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="GroupBy">GroupBy</span>
|
### <span id="GroupBy">GroupBy</span>
|
||||||
|
|
||||||
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
|
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import (
|
|||||||
- [Flatten](#Flatten)
|
- [Flatten](#Flatten)
|
||||||
- [FlattenDeep](#FlattenDeep)
|
- [FlattenDeep](#FlattenDeep)
|
||||||
- [ForEach](#ForEach)
|
- [ForEach](#ForEach)
|
||||||
|
- [ForEachWithBreak](#ForEachWithBreak)
|
||||||
- [GroupBy](#GroupBy)
|
- [GroupBy](#GroupBy)
|
||||||
- [GroupWith](#GroupWith)
|
- [GroupWith](#GroupWith)
|
||||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||||
@@ -1003,6 +1004,46 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
|
<p>遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="GroupBy">GroupBy</span>
|
### <span id="GroupBy">GroupBy</span>
|
||||||
|
|
||||||
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
||||||
|
|||||||
353
docs/structs/field.md
Normal file
353
docs/structs/field.md
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
# Field
|
||||||
|
|
||||||
|
Field is abstract struct field for provide several high level functions
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index:
|
||||||
|
- [Tag](#Tag)
|
||||||
|
- [Name](#Name)
|
||||||
|
- [Value](#Value)
|
||||||
|
- [Kind](#Kind)
|
||||||
|
- [IsEmbedded](#IsEmbedded)
|
||||||
|
- [IsExported](#IsExported)
|
||||||
|
- [IsZero](#IsZero)
|
||||||
|
- [IsSlice](#IsSlice)
|
||||||
|
|
||||||
|
> Note:Since `Field` inherits from `Struct`, it also has all the methods of 'Struct', as follows:
|
||||||
|
|
||||||
|
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#ToMap)
|
||||||
|
- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Fields)
|
||||||
|
- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Field)
|
||||||
|
- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation:
|
||||||
|
|
||||||
|
### <span id="Tag">Tag</span>
|
||||||
|
|
||||||
|
<p>Get a `Tag` of the `Field`, `Tag` is a abstract struct field tag</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Tag() *Tag
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
|
||||||
|
fmt.Println(tag.Name)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Value">Value</span>
|
||||||
|
|
||||||
|
<p>Get the `Field` underlying value</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Value() any
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(n.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 111
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsEmbedded">IsEmbedded</span>
|
||||||
|
|
||||||
|
<p>Check if the field is an embedded field</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsEmbedded() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := structs.New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsEmbedded())
|
||||||
|
fmt.Println(a.IsEmbedded())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsExported">IsExported</span>
|
||||||
|
|
||||||
|
<p>Check if the field is exported</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsExported() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsExported())
|
||||||
|
fmt.Println(a.IsExported())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZero">IsZero</span>
|
||||||
|
|
||||||
|
<p>Check if the field is zero value</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsZero() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsZero())
|
||||||
|
fmt.Println(a.IsZero())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Name">Name</span>
|
||||||
|
|
||||||
|
<p>Get the field name</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Name() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Name())
|
||||||
|
fmt.Println(a.Name())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Name
|
||||||
|
// Age
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Kind">Kind</span>
|
||||||
|
|
||||||
|
<p>Get the field's kind</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Kind() reflect.Kind
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Kind())
|
||||||
|
fmt.Println(a.Kind())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsSlice">IsSlice</span>
|
||||||
|
|
||||||
|
<p>Check if the field is a slice</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsSlice() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := structs.New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
fmt.Println(a.IsSlice())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
353
docs/structs/field_zh-CN.md
Normal file
353
docs/structs/field_zh-CN.md
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
# Field
|
||||||
|
|
||||||
|
Field 包封装了一个抽象的`Field`结构体,提供了操作`struct`属性的相关函数
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录:
|
||||||
|
- [Tag](#Tag)
|
||||||
|
- [Name](#Name)
|
||||||
|
- [Value](#Value)
|
||||||
|
- [Kind](#Kind)
|
||||||
|
- [IsEmbedded](#IsEmbedded)
|
||||||
|
- [IsExported](#IsExported)
|
||||||
|
- [IsZero](#IsZero)
|
||||||
|
- [IsSlice](#IsSlice)
|
||||||
|
|
||||||
|
> 注意:由于`Field`继承于`Struct`,所以同样拥有`Struct`所有方法,如下:
|
||||||
|
|
||||||
|
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)
|
||||||
|
- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)
|
||||||
|
- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Field)
|
||||||
|
- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## API 文档:
|
||||||
|
|
||||||
|
### <span id="Tag">Tag</span>
|
||||||
|
|
||||||
|
<p>获取`Field`的`Tag`,默认的tag key是json</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Tag() *Tag
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
|
||||||
|
fmt.Println(tag.Name)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Value">Value</span>
|
||||||
|
|
||||||
|
<p>获取`Field`属性的值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Value() any
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(n.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 111
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsEmbedded">IsEmbedded</span>
|
||||||
|
|
||||||
|
<p>判断属性是否为嵌入</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsEmbedded() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := structs.New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsEmbedded())
|
||||||
|
fmt.Println(a.IsEmbedded())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsExported">IsExported</span>
|
||||||
|
|
||||||
|
<p>判断属性是否导出</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsExported() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsExported())
|
||||||
|
fmt.Println(a.IsExported())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsZero">IsZero</span>
|
||||||
|
|
||||||
|
<p>判断属性是否为零值</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsZero() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.IsZero())
|
||||||
|
fmt.Println(a.IsZero())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Name">Name</span>
|
||||||
|
|
||||||
|
<p>获取属性名</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Name() string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Name())
|
||||||
|
fmt.Println(a.Name())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Name
|
||||||
|
// Age
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Kind">Kind</span>
|
||||||
|
|
||||||
|
<p>获取属性Kind</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) Kind() reflect.Kind
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := structs.New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
fmt.Println(n.Kind())
|
||||||
|
fmt.Println(a.Kind())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// string
|
||||||
|
// int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsSlice">IsSlice</span>
|
||||||
|
|
||||||
|
<p>判断属性是否是切片</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (f *Field) IsSlice() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := structs.New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
fmt.Println(a.IsSlice())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
213
docs/structs/struct.md
Normal file
213
docs/structs/struct.md
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
# Structs
|
||||||
|
|
||||||
|
Struct is abstract struct for provide several high level functions
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Source:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Index:
|
||||||
|
- [New](#New)
|
||||||
|
- [ToMap](#ToMap)
|
||||||
|
- [Fields](#Fields)
|
||||||
|
- [Field](#Field)
|
||||||
|
- [IsStruct](#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## Documentation:
|
||||||
|
|
||||||
|
### <span id="New">New</span>
|
||||||
|
|
||||||
|
<p>The constructor function of the `Struct` </p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func New(value any, tagName ...string) *Struct
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
// to do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToMap">ToMap</span>
|
||||||
|
|
||||||
|
<p>convert a valid struct to a map</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) ToMap() (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
> In addition, provided a convenient static function ToMap
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToMap(v any) (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
// use constructor function
|
||||||
|
s1 := structs.New(p1)
|
||||||
|
m1, _ := s1.ToMap()
|
||||||
|
|
||||||
|
fmt.Println(m1)
|
||||||
|
|
||||||
|
// use static function
|
||||||
|
m2, _ := structs.ToMap(p1)
|
||||||
|
|
||||||
|
fmt.Println(m2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// map[name:11]
|
||||||
|
// map[name:11]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Fields">Fields</span>
|
||||||
|
|
||||||
|
<p>Get all fields of a given struct, that the fields are abstract struct field</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Fields() []*Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
|
||||||
|
fmt.Println(len(fields))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Field">Field</span>
|
||||||
|
|
||||||
|
<p>Get an abstract field of a struct by given field name </p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Field(name string) *Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
f := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(f.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 11
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsStruct">IsStruct</span>
|
||||||
|
|
||||||
|
<p>Check if the struct is valid</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) IsStruct() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
|
||||||
|
fmt.Println(s.IsStruct())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
212
docs/structs/struct_zh-CN.md
Normal file
212
docs/structs/struct_zh-CN.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# Structs
|
||||||
|
|
||||||
|
structs 包封装了一个抽象的`Struct`结构体,提供了操作`struct`的相关函数
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 源码:
|
||||||
|
|
||||||
|
- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 用法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## 目录:
|
||||||
|
- [New](#New)
|
||||||
|
- [ToMap](#ToMap)
|
||||||
|
- [Fields](#Fields)
|
||||||
|
- [Field](#Field)
|
||||||
|
- [IsStruct](#IsStruct)
|
||||||
|
|
||||||
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
## API 文档:
|
||||||
|
|
||||||
|
### <span id="New">New</span>
|
||||||
|
|
||||||
|
<p>`Struct`结构体的构造函数</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func New(value any, tagName ...string) *Struct
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
// to do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ToMap">ToMap</span>
|
||||||
|
|
||||||
|
<p>将一个合法的struct对象转换为map[string]any</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) ToMap() (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>除此之外,提供一个便捷的静态方法ToMap</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToMap(v any) (map[string]any, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s1 := structs.New(p1)
|
||||||
|
m1, _ := s1.ToMap()
|
||||||
|
|
||||||
|
fmt.Println(m1)
|
||||||
|
|
||||||
|
// 如果不需要Struct更多的方法,可以直接使用ToMap
|
||||||
|
m2, _ := structs.ToMap(p1)
|
||||||
|
|
||||||
|
fmt.Println(m2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// map[name:11]
|
||||||
|
// map[name:11]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Fields">Fields</span>
|
||||||
|
|
||||||
|
<p>获取一个struct对象的属性列表</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Fields() []*Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
fields := s.Fields()
|
||||||
|
|
||||||
|
fmt.Println(len(fields))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="Field">Field</span>
|
||||||
|
|
||||||
|
<p>根据属性名获取一个struct对象的属性</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) Field(name string) *Field
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
f := s.Field("Name")
|
||||||
|
|
||||||
|
fmt.Println(f.Value())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 11
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="IsStruct">IsStruct</span>
|
||||||
|
|
||||||
|
<p>判断是否为一个合法的struct对象</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Struct) IsStruct() bool
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type People struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
p1 := &People{Name: "11"}
|
||||||
|
s := structs.New(p1)
|
||||||
|
|
||||||
|
fmt.Println(s.IsStruct())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -39,7 +39,7 @@ func Values[K comparable, V any](m map[K]V) []V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
|
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/hI371iB8Up8
|
||||||
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
||||||
keys := make([]T, 0, len(m))
|
keys := make([]T, 0, len(m))
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
|
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/sg9-oRidh8f
|
||||||
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
|
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
|
||||||
keys := make([]T, 0, len(m))
|
keys := make([]T, 0, len(m))
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
|
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/7ov6BJHbVqh
|
||||||
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterByValues iterates over map, return a new map whose values are all given values.
|
// FilterByValues iterates over map, return a new map whose values are all given values.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/P3-9MdcXegR
|
||||||
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/YJM4Hj5hNwm
|
||||||
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/jXGrWDBfSRp
|
||||||
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/XB7Y10uw20_U
|
||||||
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
|
||||||
result := make(map[K]V)
|
result := make(map[K]V)
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ type Entry[K comparable, V any] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Entries transforms a map into array of key/value pairs.
|
// Entries transforms a map into array of key/value pairs.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/Ltb11LNcElY
|
||||||
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
||||||
entries := make([]Entry[K, V], 0, len(m))
|
entries := make([]Entry[K, V], 0, len(m))
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FromEntries creates a map based on a slice of key/value pairs
|
// FromEntries creates a map based on a slice of key/value pairs
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/fTdu4sCNjQO
|
||||||
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
||||||
result := make(map[K]V, len(entries))
|
result := make(map[K]V, len(entries))
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transform a map to another type map.
|
// Transform a map to another type map.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/P6ovfToM3zj
|
||||||
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
|
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
|
||||||
result := make(map[K2]V2, len(m))
|
result := make(map[K2]V2, len(m))
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iterat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MapKeys transforms a map to other type map by manipulating it's keys.
|
// MapKeys transforms a map to other type map by manipulating it's keys.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/8scDxWeBDKd
|
||||||
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
|
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
|
||||||
result := make(map[T]V, len(m))
|
result := make(map[T]V, len(m))
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MapValues transforms a map to other type map by manipulating it's values.
|
// MapValues transforms a map to other type map by manipulating it's values.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/g92aY3fc7Iw
|
||||||
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
|
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
|
||||||
result := make(map[K]T, len(m))
|
result := make(map[K]T, len(m))
|
||||||
|
|
||||||
|
|||||||
@@ -183,3 +183,36 @@ func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
|||||||
}
|
}
|
||||||
return sum / n
|
return sum / n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||||
|
// Play: 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
|
// 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)
|
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"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/convertor"
|
||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ func (client *HttpClient) setTLS(rawUrl string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setHeader set http rquest header
|
// setHeader set http request header
|
||||||
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
|
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
|
||||||
if headers == nil {
|
if headers == nil {
|
||||||
headers = make(http.Header)
|
headers = make(http.Header)
|
||||||
@@ -278,29 +277,15 @@ func validateRequest(req *HttpRequest) error {
|
|||||||
// StructToUrlValues convert struct to url valuse,
|
// StructToUrlValues convert struct to url valuse,
|
||||||
// only convert the field which is exported and has `json` tag.
|
// only convert the field which is exported and has `json` tag.
|
||||||
// Play: https://go.dev/play/p/pFqMkM40w9z
|
// Play: https://go.dev/play/p/pFqMkM40w9z
|
||||||
func StructToUrlValues(targetStruct any) url.Values {
|
func StructToUrlValues(targetStruct any) (url.Values, error) {
|
||||||
rv := reflect.ValueOf(targetStruct)
|
|
||||||
rt := reflect.TypeOf(targetStruct)
|
|
||||||
|
|
||||||
if rt.Kind() == reflect.Ptr {
|
|
||||||
rt = rt.Elem()
|
|
||||||
}
|
|
||||||
if rt.Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
|
|
||||||
}
|
|
||||||
|
|
||||||
result := url.Values{}
|
result := url.Values{}
|
||||||
|
s, err := convertor.StructToMap(targetStruct)
|
||||||
fieldNum := rt.NumField()
|
if err != nil {
|
||||||
pattern := `^[A-Z]`
|
return nil, err
|
||||||
regex := regexp.MustCompile(pattern)
|
|
||||||
for i := 0; i < fieldNum; i++ {
|
|
||||||
name := rt.Field(i).Name
|
|
||||||
tag := rt.Field(i).Tag.Get("json")
|
|
||||||
if regex.MatchString(name) && tag != "" {
|
|
||||||
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
|
|
||||||
}
|
}
|
||||||
|
for k, v := range s {
|
||||||
|
result.Add(k, fmt.Sprintf("%v", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,28 +219,29 @@ func TestStructToUrlValues(t *testing.T) {
|
|||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
UserId int `json:"userId"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item1 := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
UserId: 1,
|
UserId: 123,
|
||||||
|
Name: "",
|
||||||
|
}
|
||||||
|
todoValues, err := StructToUrlValues(item1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("params is invalid: %v", err)
|
||||||
}
|
}
|
||||||
todoValues := StructToUrlValues(todoQuery)
|
|
||||||
|
|
||||||
assert.Equal("1", todoValues.Get("id"))
|
assert.Equal("1", todoValues.Get("id"))
|
||||||
assert.Equal("1", todoValues.Get("userId"))
|
assert.Equal("123", todoValues.Get("userId"))
|
||||||
|
assert.Equal("", todoValues.Get("name"))
|
||||||
|
|
||||||
request := &HttpRequest{
|
item2 := TodoQuery{
|
||||||
RawURL: "https://jsonplaceholder.typicode.com/todos",
|
Id: 2,
|
||||||
Method: "GET",
|
UserId: 456,
|
||||||
QueryParams: todoValues,
|
|
||||||
}
|
}
|
||||||
|
queryValues2, _ := StructToUrlValues(item2)
|
||||||
|
|
||||||
httpClient := NewHttpClient()
|
assert.Equal("2", queryValues2.Get("id"))
|
||||||
resp, err := httpClient.SendRequest(request)
|
assert.Equal("456", queryValues2.Get("userId"))
|
||||||
if err != nil || resp.StatusCode != 200 {
|
assert.Equal("", queryValues2.Get("name"))
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
t.Log("response: ", string(body))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,20 +124,44 @@ func ExampleHttpClient_DecodeResponse() {
|
|||||||
func ExampleStructToUrlValues() {
|
func ExampleStructToUrlValues() {
|
||||||
type TodoQuery struct {
|
type TodoQuery struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
UserId int `json:"userId"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string
|
||||||
}
|
}
|
||||||
todoQuery := TodoQuery{
|
item1 := TodoQuery{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: "Test",
|
UserId: 123,
|
||||||
|
Name: "test",
|
||||||
|
Status: "completed",
|
||||||
|
}
|
||||||
|
queryValues1, err := StructToUrlValues(item1)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
todoValues := StructToUrlValues(todoQuery)
|
|
||||||
|
|
||||||
fmt.Println(todoValues.Get("id"))
|
item2 := TodoQuery{
|
||||||
fmt.Println(todoValues.Get("name"))
|
Id: 2,
|
||||||
|
UserId: 456,
|
||||||
|
}
|
||||||
|
queryValues2, _ := StructToUrlValues(item2)
|
||||||
|
|
||||||
|
fmt.Println(queryValues1.Get("id"))
|
||||||
|
fmt.Println(queryValues1.Get("userId"))
|
||||||
|
fmt.Println(queryValues1.Get("name"))
|
||||||
|
fmt.Println(queryValues1.Get("status"))
|
||||||
|
|
||||||
|
fmt.Println(queryValues2.Get("id"))
|
||||||
|
fmt.Println(queryValues2.Get("userId"))
|
||||||
|
fmt.Println(queryValues2.Get("name"))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// Test
|
// 123
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// 2
|
||||||
|
// 456
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleConvertMapToQueryString() {
|
func ExampleConvertMapToQueryString() {
|
||||||
|
|||||||
14
pointer/pointer.go
Normal file
14
pointer/pointer.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// ExtractPointer returns the underlying value by the given interface type
|
||||||
|
func ExtractPointer(value any) any {
|
||||||
|
t := reflect.TypeOf(value)
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
|
if t.Kind() != reflect.Pointer {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ExtractPointer(v.Elem().Interface())
|
||||||
|
}
|
||||||
18
pointer/pointer_test.go
Normal file
18
pointer/pointer_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractPointer(t *testing.T) {
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestExtractPointer")
|
||||||
|
|
||||||
|
a := 1
|
||||||
|
b := &a
|
||||||
|
c := &b
|
||||||
|
d := &c
|
||||||
|
|
||||||
|
assert.Equal(1, ExtractPointer(d))
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Contain check if the target value is in the slice or not.
|
// Contain check if the target value is in the slice or not.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/_454yEHcNjf
|
||||||
func Contain[T comparable](slice []T, target T) bool {
|
func Contain[T comparable](slice []T, target T) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
if item == target {
|
if item == target {
|
||||||
@@ -34,6 +34,7 @@ func Contain[T comparable](slice []T, target T) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ContainBy returns true if predicate function return true.
|
// ContainBy returns true if predicate function return true.
|
||||||
|
// Play: https://go.dev/play/p/49tkHfX4GNc
|
||||||
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
|
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
if predicate(item) {
|
if predicate(item) {
|
||||||
@@ -420,6 +421,17 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||||
|
// when iteratee return true, 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.
|
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||||
// Play: https://go.dev/play/p/biaTefqPquw
|
// Play: https://go.dev/play/p/biaTefqPquw
|
||||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||||
@@ -436,7 +448,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
|||||||
// iteratee callback function should returntwo values:
|
// iteratee callback function should returntwo values:
|
||||||
// 1, mapping result.
|
// 1, mapping result.
|
||||||
// 2, whether the result element should be included or not
|
// 2, whether the result element should be included or not
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/J94SZ_9MiIe
|
||||||
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
|
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
|
||||||
result := []U{}
|
result := []U{}
|
||||||
|
|
||||||
@@ -450,7 +462,7 @@ func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
|
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/_QARWlWs1N_F
|
||||||
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
|
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
|
||||||
result := make([]U, 0, len(slice))
|
result := make([]U, 0, len(slice))
|
||||||
|
|
||||||
|
|||||||
@@ -379,6 +379,25 @@ func ExampleForEach() {
|
|||||||
// [2 3 4]
|
// [2 3 4]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleForEachWithBreak() {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 6
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleMap() {
|
func ExampleMap() {
|
||||||
nums := []int{1, 2, 3}
|
nums := []int{1, 2, 3}
|
||||||
|
|
||||||
|
|||||||
@@ -307,6 +307,23 @@ func TestForEach(t *testing.T) {
|
|||||||
assert.Equal(expected, numbersAddTwo)
|
assert.Equal(expected, numbersAddTwo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestForEachWithBreak(t *testing.T) {
|
||||||
|
numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
ForEachWithBreak(numbers, func(_, n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestForEach")
|
||||||
|
assert.Equal(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
func TestMap(t *testing.T) {
|
||||||
nums := []int{1, 2, 3, 4}
|
nums := []int{1, 2, 3, 4}
|
||||||
multiplyTwo := func(i, num int) int {
|
multiplyTwo := func(i, num int) int {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
|||||||
|
|
||||||
var zeroValue T
|
var zeroValue T
|
||||||
for next, item, ok := generator(), zeroValue, true; ok; {
|
for next, item, ok := generator(), zeroValue, true; ok; {
|
||||||
|
|
||||||
item, ok = next()
|
item, ok = next()
|
||||||
if ok {
|
if ok {
|
||||||
source = append(source, item)
|
source = append(source, item)
|
||||||
@@ -98,7 +99,7 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := int((end-start)/step) + 1
|
l := int((end-start)/step) + 1
|
||||||
source := make([]T, l, l)
|
source := make([]T, l)
|
||||||
|
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
source[i] = start + (T(i) * step)
|
source[i] = start + (T(i) * step)
|
||||||
@@ -160,7 +161,7 @@ func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
|
|||||||
|
|
||||||
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
||||||
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
||||||
source := make([]T, s.Count(), s.Count())
|
source := make([]T, s.Count())
|
||||||
|
|
||||||
for i, v := range s.source {
|
for i, v := range s.source {
|
||||||
source[i] = mapper(v)
|
source[i] = mapper(v)
|
||||||
|
|||||||
112
structs/field.go
Normal file
112
structs/field.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Field is abstract struct field for provide several high level functions
|
||||||
|
type Field struct {
|
||||||
|
Struct
|
||||||
|
field reflect.StructField
|
||||||
|
tag *Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func newField(v reflect.Value, f reflect.StructField, tagName string) *Field {
|
||||||
|
tag := f.Tag.Get(tagName)
|
||||||
|
field := &Field{
|
||||||
|
field: f,
|
||||||
|
tag: newTag(tag),
|
||||||
|
}
|
||||||
|
field.rvalue = v
|
||||||
|
field.rtype = v.Type()
|
||||||
|
field.TagName = tagName
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag returns the value that the key in the tag string.
|
||||||
|
func (f *Field) Tag() *Tag {
|
||||||
|
return f.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the underlying value of the field.
|
||||||
|
func (f *Field) Value() any {
|
||||||
|
return f.rvalue.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmbedded returns true if the given field is an embedded field.
|
||||||
|
func (f *Field) IsEmbedded() bool {
|
||||||
|
return len(f.field.Index) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExported returns true if the given field is exported.
|
||||||
|
func (f *Field) IsExported() bool {
|
||||||
|
return f.field.IsExported()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the given field is zero value.
|
||||||
|
func (f *Field) IsZero() bool {
|
||||||
|
z := reflect.Zero(f.rvalue.Type()).Interface()
|
||||||
|
v := f.Value()
|
||||||
|
return reflect.DeepEqual(z, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the given field
|
||||||
|
func (f *Field) Name() string {
|
||||||
|
return f.field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind returns the field's kind
|
||||||
|
func (f *Field) Kind() reflect.Kind {
|
||||||
|
return f.rvalue.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSlice check if a struct field type is slice or not
|
||||||
|
func (f *Field) IsSlice() bool {
|
||||||
|
k := f.rvalue.Kind()
|
||||||
|
return k == reflect.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapValue covert field value to map
|
||||||
|
func (f *Field) mapValue(value any) any {
|
||||||
|
val := pointer.ExtractPointer(value)
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
var ret any
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
s := New(val)
|
||||||
|
s.TagName = f.TagName
|
||||||
|
m, _ := s.ToMap()
|
||||||
|
ret = m
|
||||||
|
case reflect.Map:
|
||||||
|
mapEl := v.Type().Elem()
|
||||||
|
switch mapEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
// iterate the map
|
||||||
|
m := make(map[string]any, v.Len())
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
m[key.String()] = f.mapValue(v.MapIndex(key).Interface())
|
||||||
|
}
|
||||||
|
ret = m
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
sEl := v.Type().Elem()
|
||||||
|
switch sEl.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice, reflect.Chan:
|
||||||
|
slices := make([]any, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
slices[i] = f.mapValue(v.Index(i).Interface())
|
||||||
|
}
|
||||||
|
ret = slices
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ret = v.Interface()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
272
structs/field_test.go
Normal file
272
structs/field_test.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestField_Tag(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Tag")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
tag := n.Tag()
|
||||||
|
assert.Equal("name", tag.Name)
|
||||||
|
assert.Equal(true, tag.HasOption("omitempty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Value(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Value")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{"111"}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
|
||||||
|
assert.Equal("111", n.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsEmbedded(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
type Child struct {
|
||||||
|
Parent
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
c1 := &Child{}
|
||||||
|
c1.Name = "111"
|
||||||
|
c1.Age = 11
|
||||||
|
|
||||||
|
s := New(c1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsEmbedded())
|
||||||
|
assert.Equal(false, a.IsEmbedded())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsExported(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsEmbedded")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Name: "11", age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("age")
|
||||||
|
assert.Equal(true, n.IsExported())
|
||||||
|
assert.Equal(false, a.IsExported())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsZero(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsZero")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
assert.Equal(true, n.IsZero())
|
||||||
|
assert.Equal(false, a.IsZero())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Name(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Name")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal("Name", n.Name())
|
||||||
|
assert.Equal("Age", a.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_Kind(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_Kind")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p1 := &Parent{Age: 11}
|
||||||
|
s := New(p1)
|
||||||
|
n, _ := s.Field("Name")
|
||||||
|
a, _ := s.Field("Age")
|
||||||
|
|
||||||
|
assert.Equal(reflect.String, n.Kind())
|
||||||
|
assert.Equal(reflect.Int, a.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_IsSlice(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_IsSlice")
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
arr []int
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||||
|
s := New(p1)
|
||||||
|
a, _ := s.Field("arr")
|
||||||
|
|
||||||
|
assert.Equal(true, a.IsSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField_MapValue(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestField_MapValue")
|
||||||
|
|
||||||
|
t.Run("nested struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c1,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child any `json:"child"`
|
||||||
|
}
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &c1
|
||||||
|
c3 := &c2
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: c3,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"name": "11-1"}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []int `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []int{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal([]int{1, 2, 3}, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested array struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child []*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: []*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested ptr array struct", func(t *testing.T) {
|
||||||
|
type Child struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child *[]*Child `json:"child"`
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &Child{"11-1"}
|
||||||
|
c2 := &Child{"11-2"}
|
||||||
|
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: &[]*Child{c1, c2},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
|
||||||
|
assert.Equal(arr, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nested map in struct", func(t *testing.T) {
|
||||||
|
type Parent struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Child map[string]any `json:"child"`
|
||||||
|
}
|
||||||
|
p1 := &Parent{
|
||||||
|
Name: "11",
|
||||||
|
Child: map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := New(p1)
|
||||||
|
f, ok := s.Field("Child")
|
||||||
|
val := f.mapValue(f.Value())
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}}, val)
|
||||||
|
})
|
||||||
|
}
|
||||||
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.
|
// PadStart pads string on the left and right side if it's shorter than size.
|
||||||
// Padding characters are truncated if they exceed size.
|
// Padding characters are truncated if they exceed size.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/NzImQq-VF8q
|
||||||
func Pad(source string, size int, padStr string) string {
|
func Pad(source string, size int, padStr string) string {
|
||||||
return padAtPosition(source, size, padStr, 0)
|
return padAtPosition(source, size, padStr, 0)
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ func Substring(s string, offset int, length uint) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SplitWords splits a string into words, word only contains alphabetic characters.
|
// SplitWords splits a string into words, word only contains alphabetic characters.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/KLiX4WiysMM
|
||||||
func SplitWords(s string) []string {
|
func SplitWords(s string) []string {
|
||||||
var word string
|
var word string
|
||||||
var words []string
|
var words []string
|
||||||
@@ -331,7 +331,7 @@ func SplitWords(s string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WordCount return the number of meaningful word, word only contains alphabetic characters.
|
// WordCount return the number of meaningful word, word only contains alphabetic characters.
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/bj7_odx3vRf
|
||||||
func WordCount(s string) int {
|
func WordCount(s string) int {
|
||||||
var r rune
|
var r rune
|
||||||
var size, count int
|
var size, count int
|
||||||
|
|||||||
Reference in New Issue
Block a user