1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-05 05:12:26 +08:00

Compare commits

..

57 Commits

Author SHA1 Message Date
dudaodong
e29b56c3c3 release v2.1.18 2023-04-03 10:12:50 +08:00
dudaodong
c357fc68c8 doc: update readme file for new feature 2023-04-03 10:12:13 +08:00
dudaodong
bc25e7a037 feat: add IsPrintable 2023-03-31 12:00:32 +08:00
dudaodong
217350042b feat: add RemoveNonPrintable 2023-03-30 14:52:32 +08:00
dudaodong
e56a8a1ef5 feat: add IsASCII 2023-03-30 14:41:32 +08:00
dudaodong
6453f755a6 doc: add doc for IsPrime 2023-03-30 14:09:05 +08:00
dudaodong
027abd6ad5 feat: add IsPrime 2023-03-30 11:54:20 +08:00
dudaodong
91503b1656 comment TestEachWithBreak 2023-03-29 10:31:38 +08:00
dudaodong
e2522cd29b fix: fix TestEachWithBreak case 2023-03-29 10:24:41 +08:00
dudaodong
da69b77892 Merge branch 'main' of github.com:duke-git/lancet 2023-03-29 10:15:56 +08:00
dudaodong
05772d8d7d comment TestEachWithBreak 2023-03-28 20:08:05 +08:00
Mickls
3b497532f3 fix: The LastIndexOf method can never return the index of the first element (#83)
Co-authored-by: JiangCheng <jiangcheng@kezaihui.com>
2023-03-28 20:02:57 +08:00
dudaodong
1cd3be508c refactor rename async package name to 2023-03-24 11:43:56 +08:00
dudaodong
a41d461910 doc: update mathutil package doc 2023-03-24 11:23:45 +08:00
dudaodong
cde5946bf0 feat: add PointDistance 2023-03-23 17:49:07 +08:00
dudaodong
c28803b25e feat: add AngleToRadian and RadianToAngle 2023-03-23 17:41:31 +08:00
dudaodong
f09e521783 doc: add go playground demo 2023-03-22 21:06:01 +08:00
dudaodong
0aa41f337d fix: test failed 2023-03-20 16:39:56 +08:00
dudaodong
48814a720a fix: test failed in promise test 2023-03-20 16:26:21 +08:00
dudaodong
04b79b3dfe release v2.1.17 2023-03-20 16:17:52 +08:00
dudaodong
302007ebdf doc: update readme file for new feature 2023-03-20 16:12:58 +08:00
dudaodong
965e5fbcda feat: add Pop for set 2023-03-20 11:10:35 +08:00
dudaodong
70d0adde42 feat: add EachWithBreak for set 2023-03-20 10:49:14 +08:00
dudaodong
0b80074bb7 refactor: remove unused code 2023-03-20 10:35:37 +08:00
dudaodong
90945a0399 Merge branch 'main' into v2 2023-03-18 19:35:48 +08:00
zm
47dccd63af add the struct package english docs (#82) 2023-03-18 19:33:07 +08:00
dudaodong
4ae7e59829 feat: add example for promise 2023-03-17 16:03:35 +08:00
dudaodong
8f0c60cade test: add unit test for promise Race and Any function 2023-03-17 13:59:18 +08:00
dudaodong
3f6aef1432 fix: fix bug of IsNotNil function 2023-03-16 19:15:36 +08:00
dudaodong
a714e04470 test: add unit test for promise.All function 2023-03-16 19:11:30 +08:00
dudaodong
7456621153 fix: fix bug of IsNil function 2023-03-16 17:01:28 +08:00
dudaodong
73ac9825e9 test: add unit test for Promise 2023-03-16 16:55:32 +08:00
dudaodong
930bb9c839 feat: complete promise Any function 2023-03-16 15:59:06 +08:00
dudaodong
3d8f1be212 feat: add error_join.go to support join error under go1.19, for internal use. 2023-03-16 15:56:54 +08:00
dudaodong
13a4ed59fa doc: update comment for concurrency package 2023-03-16 15:35:26 +08:00
dudaodong
c799d10ce9 feat: add promise All, Race, Any methods 2023-03-16 15:34:28 +08:00
dudaodong
5ab322ade2 feat: add async package, promise implemention 2023-03-16 14:49:07 +08:00
dudaodong
d0ffc61842 doc: fix doc error 2023-03-16 10:36:06 +08:00
zm
5e66bc6227 [structs] change package structutil to structs (#81)
* refactor package structutil to structs

* add structs package zh-CN docs
2023-03-15 19:14:19 +08:00
dudaodong
7261b281ad refactor: add function comment for tag.go 2023-03-15 17:43:47 +08:00
dudaodong
f79693804b refactor: make package variable defaultTagName unexported 2023-03-15 15:08:56 +08:00
dudaodong
534c7a0abc refactor: make errInvalidStruct exported, change error.go to struct_internal.go 2023-03-15 14:58:34 +08:00
dudaodong
4eaff47d38 Merge branch 'main' into v2 2023-03-15 14:43:48 +08:00
dudaodong
3e019522c7 doc: add doc for ForEachWithBreak 2023-03-15 14:42:22 +08:00
dudaodong
0734f220b3 feat: add ForEachWithBreak support break for each loop 2023-03-15 14:38:33 +08:00
zm
2d2c277090 [StructUtil] add support that the Struct can nest any type to transform (#80)
* add support json tag attribute for StructToMap function

* add the structutil to provide more rich functions and fixed #77

* add support that the nested struct to map for structutil

* recover code

* add structutil unit test

* [StructUtil] add unit test
2023-03-15 14:26:34 +08:00
dudaodong
ef1e548dfc merge main 2023-03-13 19:44:44 +08:00
zm
924589d2da Add StructUtil for provide more rich functions (#79)
* add support json tag attribute for StructToMap function

* add the structutil to provide more rich functions and fixed #77
2023-03-13 19:28:37 +08:00
dudaodong
77f32f4cc6 Merge branch 'main' into v2 2023-03-11 20:14:32 +08:00
zm
1755dd249b add support json tag attribute for StructToMap function (#78) 2023-03-11 20:08:41 +08:00
dudaodong
7a25688ec1 doc: add doc for Range and RangeWithStep 2023-03-09 17:13:51 +08:00
dudaodong
51a6912eb3 feat: add RangeWithStep function 2023-03-06 18:05:58 +08:00
dudaodong
28d0428b50 feat: add Range function 2023-03-06 17:49:56 +08:00
dudaodong
6a9eb645bb fix: fix StructToUrlValues failed when tag contain omitempty 2023-03-06 17:07:57 +08:00
dudaodong
3857b342f6 fix: fix ExampleContext failed 2023-03-01 11:45:02 +08:00
dudaodong
71aa91a58d doc: add go playground demo 2023-03-01 11:39:27 +08:00
dudaodong
081908bce3 fix: fix goline error 2023-03-01 11:10:12 +08:00
57 changed files with 4927 additions and 744 deletions

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.16-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.18-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -251,7 +251,7 @@ import "github.com/duke-git/lancet/v2/convertor"
[[play](https://go.dev/play/p/j4DP5dquxnk)]
- **<big>CopyProperties</big>** : copies each field from the source struct into the destination struct.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
### 5. Cryptor package is for data encryption and decryption.
@@ -456,9 +456,6 @@ import "github.com/duke-git/lancet/v2/datetime"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
```go
@@ -593,7 +590,6 @@ import "github.com/duke-git/lancet/v2/function"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 11. Maputil package includes some functions to manipulate map.
```go
@@ -610,14 +606,19 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
- **<big>FilterByKeys</big>** : iterates over map, return a new map whose keys are all given keys
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByKeys)]
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
- **<big>FilterByValues</big>** : iterates over map, return a new map whose values are all given values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FilterByValues)]
[[play](https://go.dev/play/p/P3-9MdcXegR)]
- **<big>OmitBy</big>** : the opposite of Filter, removes all the map elements for which the predicate function returns true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitBy)]
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByKeys)]
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#OmitByValues)]
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
@@ -626,6 +627,7 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
- **<big>KeysBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#KeysBy)]
[[play](https://go.dev/play/p/hI371iB8Up8)]
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
[[play](https://go.dev/play/p/H95LENF1uB-)]
@@ -637,16 +639,22 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
- **<big>ValuesBy</big>** : creates a slice whose element is the result of function mapper invoked by every map's value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ValuesBy)]
[[play](https://go.dev/play/p/sg9-oRidh8f)]
- **<big>MapKeys</big>** : transforms a map to other type map by manipulating it's keys.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapKeys)]
[[play](https://go.dev/play/p/8scDxWeBDKd)]
- **<big>MapValues</big>** : transforms a map to other type map by manipulating it's values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapValues)]
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
- **<big>Entries</big>** : transforms a map into array of key/value pairs.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Entries)]
[[play](https://go.dev/play/p/Ltb11LNcElY)]
- **<big>FromEntries</big>** : creates a map based on a slice of key/value pairs.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#FromEntries)]
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
- **<big>Transform</big>** : transform a map to another type map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Transform)]
[[play](https://go.dev/play/p/P6ovfToM3zj)]
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
@@ -695,6 +703,20 @@ import "github.com/duke-git/lancet/v2/mathutil"
- **<big>TruncRound</big>** : round off n decimal places for int64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
[[play](https://go.dev/play/p/aumarSHIGzP)]
- **<big>Range</big>** : Creates a slice of numbers from start with specified count, element step is 1.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
- **<big>RangeWithStep</big>** : Creates a slice of numbers from start to end with specified step.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
[[play](https://go.dev/play/p/akLWz0EqOSM)]
- **<big>AngleToRadian</big>** : converts angle value to radian value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#AngleToRadian)]
- **<big>RadianToAngle</big>** : converts radian value to angle value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RadianToAngle)]
- **<big>PointDistance</big>** : get two points distance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#PointDistance)]
- **<big>IsPrime</big>** : checks if number is prime number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#IsPrime)]
### 13. Netutil package contains functions to get net information and send http request.
@@ -759,8 +781,6 @@ import "github.com/duke-git/lancet/v2/netutil"
- **<big>ParseHttpResponse</big>** : decode http response into target object.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
### 14. Random package implements some basic functions to generate random int and string.
```go
@@ -834,6 +854,7 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/_454yEHcNjf)]
- **<big>ContainBy</big>** : returns true if predicate function return true.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainBy)]
[[play](https://go.dev/play/p/49tkHfX4GNc)]
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
@@ -890,6 +911,7 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/SdPna-7qK4T)]
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
@@ -904,9 +926,13 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
- **<big>FlatMap</big>** : manipulates a slice and transforms and flattens it to a slice of another type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlatMap)]
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
- **<big>ForEachWithBreak</big>** : iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEachWithBreak)]
[[play](https://go.dev/play/p/qScs39f3D9W)]
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
@@ -1013,7 +1039,40 @@ import "github.com/duke-git/lancet/v2/slice"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
### 17. Strutil package contains some functions to manipulate string.
### 17. Structs package provides several high level functions to manipulate struct, tag, and field.
```go
import "github.com/duke-git/lancet/v2/structs"
```
#### Function list:
- **<big>New</big>** : creates a `Struct` instance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#New)]
- **<big>ToMap</big>** : converts a valid struct to a map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#ToMap)]
- **<big>Fields</big>** : get all fields of a given struct, that the fields are abstract struct field.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Fields)]
- **<big>IsStruct</big>** : check if the struct is valid.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#IsStruct)]
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Tag)]
- **<big>Name</big>** : get the field name.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Name)]
- **<big>Value</big>** : get the `Field` underlying value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Value)]
- **<big>Kind</big>** : get the field's kind
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Kind)]
- **<big>IsEmbedded</big>** : check if the field is an embedded field.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsEmbedded)]
- **<big>IsExported</big>** : check if the field is exporte
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsExported)]
- **<big>IsZero</big>** : check if the field is zero value
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsZero)]
- **<big>IsSlice</big>** : check if the field is a slice
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
### 18. Strutil package contains some functions to manipulate string.
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -1055,6 +1114,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
- **<big>Pad</big>** : pads string on the left and right side if it's shorter than size.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Pad)]
[[play](https://go.dev/play/p/NzImQq-VF8q)]
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
[[play](https://go.dev/play/p/9xP8rN0vz--)]
@@ -1084,8 +1144,12 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
- **<big>SplitWords</big>** : splits a string into words, word only contains alphabetic characters.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitWords)]
[[play](https://go.dev/play/p/KLiX4WiysMM)]
- **<big>WordCount</big>** : return the number of meaningful word of a string, word only contains alphabetic characters.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#WordCount)]
[[play](https://go.dev/play/p/bj7_odx3vRf)]
- **<big>RemoveNonPrintable</big>** : remove non-printable characters from a string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveNonPrintable)]
### 19. System package contain some functions about os, runtime, shell command.
@@ -1123,7 +1187,7 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
### 19. Validator package contains some functions for data validation.
### 20. Validator package contains some functions for data validation.
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -1215,14 +1279,19 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsGBK</big>** : check if data encoding is gbk.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
[[play](https://go.dev/play/p/E2nt3unlmzP)]
- **<big>IsASCII</big>** : checks if string is all ASCII char.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsASCII)]
- **<big>IsPrintable</big>** : checks if string is all printable chars.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
### 20. xerror package implements helpers for errors.
### 21. xerror package implements helpers for errors.
```go
import "github.com/duke-git/lancet/v2/xerror"
```
#### Function list:
- **<big>New</big>** : creates a new XError pointer instance with message.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#New)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
@@ -1247,7 +1316,7 @@ import "github.com/duke-git/lancet/v2/xerror"
- **<big>XError_Is</big>** : checks if target error is XError and Error.id of two errors are matched.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Is)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Values</big>** : returns map of key and value that is set by XError.With function.
- **<big>XError_Values</big>** : returns map of key and value that is set by XError.With function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#XError_Values)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_StackTrace</big>** : returns stack trace which is compatible with pkg/errors.
@@ -1263,7 +1332,6 @@ import "github.com/duke-git/lancet/v2/xerror"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#TryUnwrap)]
[[play](https://go.dev/play/p/acyZVkNZEeW)]
## How to Contribute
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.16-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.18-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -181,7 +181,7 @@ import "github.com/duke-git/lancet/v2/condition"
[[play](https://go.dev/play/p/g2j08F_zZky)
- **<big>Xnor</big>** : 如果 a 和 b 都是真的或 a 和 b 均是假的,则返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xnor)]
[[play](https://go.dev/play/p/OuDB9g51643)]]
[[play](https://go.dev/play/p/OuDB9g51643)]]
- **<big>Nand</big>** : 如果 a 和 b 都为真,返回 false否则返回 true
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nand)]
[[play](https://go.dev/play/p/vSRMLxLIbq8)]
@@ -250,7 +250,7 @@ import "github.com/duke-git/lancet/v2/convertor"
[[play](https://go.dev/play/p/j4DP5dquxnk)]
- **<big>CopyProperties</big>** : 拷贝不同结构体之间的同名字段。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
### 5. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
@@ -260,103 +260,101 @@ import "github.com/duke-git/lancet/v2/cryptor"
#### 函数列表:
- **<big>AesEcbEncrypt</big>** : 使用AES ECB算法模式加密数据。
- **<big>AesEcbEncrypt</big>** : 使用 AES ECB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbEncrypt)]
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
- **<big>AesEcbDecrypt</big>** : 使用AES ECB算法模解密数据。
- **<big>AesEcbDecrypt</big>** : 使用 AES ECB 算法模解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbDecrypt)]
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
- **<big>AesCbcEncrypt</big>** : 使用AES CBC算法模式加密数据。
- **<big>AesCbcEncrypt</big>** : 使用 AES CBC 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcEncrypt)]
[[play](https://go.dev/play/p/IOq_g8_lKZD)]
- **<big>AesCbcDecrypt</big>** : 使用AES CBC算法模式解密数据。
- **<big>AesCbcDecrypt</big>** : 使用 AES CBC 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcDecrypt)]
[[play](https://go.dev/play/p/IOq_g8_lKZD)]
- **<big>AesCtrCrypt</big>** : 使用AES CTR算法模式加密/解密数据。
- **<big>AesCtrCrypt</big>** : 使用 AES CTR 算法模式加密/解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCtrCrypt)]
[[play](https://go.dev/play/p/SpaZO0-5Nsp)]
- **<big>AesCfbEncrypt</big>** : 使用AES CFB算法模式加密数据。
- **<big>AesCfbEncrypt</big>** : 使用 AES CFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbEncrypt)]
[[play](https://go.dev/play/p/tfkF10B13kH)]
- **<big>AesCfbDecrypt</big>** : 使用AES CFB算法模式解密数据。
- **<big>AesCfbDecrypt</big>** : 使用 AES CFB 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbDecrypt)]
[[play](https://go.dev/play/p/tfkF10B13kH)]
- **<big>AesOfbEncrypt</big>** : 使用AES OFB算法模式加密数据。
- **<big>AesOfbEncrypt</big>** : 使用 AES OFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbEncrypt)]
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
- **<big>AesOfbDecrypt</big>** : 使用AES OFB算法模式解密数据。
- **<big>AesOfbDecrypt</big>** : 使用 AES OFB 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbDecrypt)]
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
- **<big>Base64StdEncode</big>** : 将字符串base64编码。
- **<big>Base64StdEncode</big>** : 将字符串 base64 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdEncode)]
[[play](https://go.dev/play/p/VOaUyQUreoK)]
- **<big>Base64StdDecode</big>** : 解码base64字符串。
- **<big>Base64StdDecode</big>** : 解码 base64 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdDecode)]
[[play](https://go.dev/play/p/RWQylnJVgIe)]
- **<big>DesEcbEncrypt</big>** : 使用DES ECB算法模式加密数据。
- **<big>DesEcbEncrypt</big>** : 使用 DES ECB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbEncrypt)]
[[play](https://go.dev/play/p/8qivmPeZy4P)]
- **<big>DesEcbDecrypt</big>** : 使用DES ECB算法模解密数据。
- **<big>DesEcbDecrypt</big>** : 使用 DES ECB 算法模解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbDecrypt)]
[[play](https://go.dev/play/p/8qivmPeZy4P)]
- **<big>DesCbcEncrypt</big>** : 使用DES CBC算法模式加密数据。
- **<big>DesCbcEncrypt</big>** : 使用 DES CBC 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcEncrypt)]
[[play](https://go.dev/play/p/4cC4QvWfe3_1)]
- **<big>DesCbcDecrypt</big>** : 使用DES CBC算法模式解密数据。
- **<big>DesCbcDecrypt</big>** : 使用 DES CBC 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcDecrypt)]
[[play](https://go.dev/play/p/4cC4QvWfe3_1)]
- **<big>DesCtrCrypt</big>** : 使用DES CTR算法模式加密/解密数据。
- **<big>DesCtrCrypt</big>** : 使用 DES CTR 算法模式加密/解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCtrCrypt)]
[[play](https://go.dev/play/p/9-T6OjKpcdw)]
- **<big>DesCfbEncrypt</big>** : 使用DES CFB算法模式加密数据。
- **<big>DesCfbEncrypt</big>** : 使用 DES CFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbEncrypt)]
[[play](https://go.dev/play/p/y-eNxcFBlxL)]
- **<big>DesCfbDecrypt</big>** : 使用DES CFB算法模式解密数据。
- **<big>DesCfbDecrypt</big>** : 使用 DES CFB 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbDecrypt)]
[[play](https://go.dev/play/p/y-eNxcFBlxL)]
- **<big>DesOfbEncrypt</big>** : 使用DES OFB算法模式加密数据。
- **<big>DesOfbEncrypt</big>** : 使用 DES OFB 算法模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbEncrypt)]
[[play](https://go.dev/play/p/74KmNadjN1J)]
- **<big>DesOfbDecrypt</big>** : 使用DES OFB算法模式解密数据。
- **<big>DesOfbDecrypt</big>** : 使用 DES OFB 算法模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbDecrypt)]
[[play](https://go.dev/play/p/74KmNadjN1J)]
- **<big>HmacMd5</big>** : 返回字符串md5 hmac值。
- **<big>HmacMd5</big>** : 返回字符串 md5 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>HmacSha1</big>** : 返回字符串sha1 hmac值。
- **<big>HmacSha1</big>** : 返回字符串 sha1 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)]
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
- **<big>HmacSha256</big>** : 返回字符串sha256 hmac值。
- **<big>HmacSha256</big>** : 返回字符串 sha256 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)]
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
- **<big>HmacSha512</big>** : 返回字符串sha256 hmac值。
- **<big>HmacSha512</big>** : 返回字符串 sha256 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)]
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
- **<big>Md5String</big>** : 返回字符串md5值。
- **<big>Md5String</big>** : 返回字符串 md5 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)]
[[play](https://go.dev/play/p/1bLcVetbTOI)]
- **<big>Md5File</big>** : 返回文件md5值。
- **<big>Md5File</big>** : 返回文件 md5 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)]
- **<big>Sha1</big>** : 返回字符串sha1哈希值。
- **<big>Sha1</big>** : 返回字符串 sha1 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)]
[[play](https://go.dev/play/p/_m_uoD1deMT)]
- **<big>Sha256</big>** :返回字符串sha256哈希值。
- **<big>Sha256</big>** :返回字符串 sha256 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)]
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
- **<big>Sha512</big>** : 返回字符串sha512哈希值。
- **<big>Sha512</big>** : 返回字符串 sha512 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)]
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
- **<big>GenerateRsaKey</big>** : 在当前目录下创建rsa私钥文件和公钥文件。
- **<big>GenerateRsaKey</big>** : 在当前目录下创建 rsa 私钥文件和公钥文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)]
[[play](https://go.dev/play/p/zutRHrDqs0X)]
- **<big>RsaEncrypt</big>** : 用公钥文件ras加密数据。
- **<big>RsaEncrypt</big>** : 用公钥文件 ras 加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>RsaDecrypt</big>** : 用私钥文件rsa解密数据。
- **<big>RsaDecrypt</big>** : 用私钥文件 rsa 解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
### 6. datetime 日期时间处理包,格式化日期,比较日期。
@@ -432,32 +430,30 @@ import "github.com/duke-git/lancet/v2/datetime"
- **<big>FormatStrToTime</big>** : 将字符串格式化成时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)]
[[play](https://go.dev/play/p/1h9FwdU8ql4)]
- **<big>NewUnix</big>** : 创建一个unix时间戳。
- **<big>NewUnix</big>** : 创建一个 unix 时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)]
[[play](https://go.dev/play/p/psoSuh_kLRt)]
- **<big>NewUnixNow</big>** : 创建一个当前时间的unix时间戳。
- **<big>NewUnixNow</big>** : 创建一个当前时间的 unix 时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)]
[[play](https://go.dev/play/p/U4PPx-9D0oz)]
- **<big>NewFormat</big>** : 创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳。
- **<big>NewFormat</big>** : 创建一个 yyyy-mm-dd hh:mm:ss 格式时间字符串的 unix 时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>NewISO8601</big>** : 创建一个iso8601格式时间字符串的unix时间戳。
- **<big>NewISO8601</big>** : 创建一个 iso8601 格式时间字符串的 unix 时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
- **<big>ToUnix</big>** : 返回unix时间戳。
- **<big>ToUnix</big>** : 返回 unix 时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)]
[[play](https://go.dev/play/p/_LUiwAdocjy)]
- **<big>ToFormat</big>** : 返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)]
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
- **<big>ToFormatForTpl</big>** : 返回tpl格式指定的日期字符串。
- **<big>ToFormatForTpl</big>** : 返回 tpl 格式指定的日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)]
[[play](https://go.dev/play/p/nyXxXcQJ8L5)]
- **<big>ToIso8601</big>** : 返回iso8601日期字符串。
- **<big>ToIso8601</big>** : 返回 iso8601 日期字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
### 7. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
@@ -486,14 +482,11 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set_zh-CN.md)]
- **<big>Tree</big>** : 二叉搜索树。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree_zh-CN.md)]
- **<big>Heap</big>** : 二叉max堆。
- **<big>Heap</big>** : 二叉 max 堆。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap_zh-CN.md)]
- **<big>Hashmap</big>** : 哈希映射。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
### 8. fileutil 包含文件基本操作。
```go
@@ -568,35 +561,34 @@ import "github.com/duke-git/lancet/v2/function"
#### 函数列表:
- **<big>After</big>** : 创建一个函数,当该函数被调用n或更多次之后将执行传入的函数。
- **<big>After</big>** : 创建一个函数,当该函数被调用 n 或更多次之后将执行传入的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)]
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
- **<big>Before</big>** : 创建一个函数,当该函数被调用不超过n次时,将执行执行传入的函数。
- **<big>Before</big>** : 创建一个函数,当该函数被调用不超过 n 次时,将执行执行传入的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)]
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
- **<big>CurryFn</big>** : 创建柯里化函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#CurryFn)]
[[play](https://go.dev/play/p/5HopfDwANKX)]
- **<big>Compose</big>** : 从右至左组合函数列表fnList返回组合后的函数。
- **<big>Compose</big>** : 从右至左组合函数列表 fnList返回组合后的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)]
[[play](https://go.dev/play/p/KKfugD4PKYF)]
- **<big>Delay</big>** : 延迟delay时间后调用函数。
- **<big>Delay</big>** : 延迟 delay 时间后调用函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)]
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
- **<big>Debounced</big>** : 创建一个debounced函数该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。
- **<big>Debounced</big>** : 创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)]
[[play](https://go.dev/play/p/absuEGB_GN7)]
- **<big>Schedule</big>** : 每次持续时间调用函数直到关闭返回的channel。
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的 channel。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Schedule)]
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
- **<big>Pipeline</big>** : 从右至左执行函数列表。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)]
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
- **<big>Watcher</big>** : Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
- **<big>Watcher</big>** : Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 11. maputil 包括一些操作 map 的函数.
```go
@@ -611,24 +603,30 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Filter</big>** : 迭代 map 中的每对 key 和 value返回 map其中的 key 和 value 符合 predicate 函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)]
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
- **<big>FilterByKeys</big>** : 迭代map, 返回一个新map其key都是给定的key值。
- **<big>FilterByKeys</big>** : 迭代 map, 返回一个新 map key 都是给定的 key 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByKeys)]
- **<big>FilterByValues</big>** : 迭代map, 返回一个新map其value都是给定的value值。
[[play](https://go.dev/play/p/7ov6BJHbVqh)]
- **<big>FilterByValues</big>** : 迭代 map, 返回一个新 map其 value 都是给定的 value 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FilterByValues)]
- **<big>OmitBy</big>** : Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。
[[play](https://go.dev/play/p/P3-9MdcXegR)]
- **<big>OmitBy</big>** : Filter 的反向操作, 迭代 map 中的每对 key 和 value, 删除符合 predicate 函数的 key, value, 返回新 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitBy)]
- **<big>OmitByKeys</big>** : FilterByKeys的反向操作, 迭代map, 返回一个新map其key不包括给定的key值。
[[play](https://go.dev/play/p/YJM4Hj5hNwm)]
- **<big>OmitByKeys</big>** : FilterByKeys 的反向操作, 迭代 map, 返回一个新 map其 key 不包括给定的 key 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByKeys)]
- **<big>OmitByValues</big>** : FilterByValues的反向操作, 迭代map, 返回一个新map其value不包括给定的value值。
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
- **<big>OmitByValues</big>** : FilterByValues 的反向操作, 迭代 map, 返回一个新 map其 value 不包括给定的 value 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#OmitByValues)]
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
- **<big>Intersect</big>** : 多个 map 的交集操作。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
- **<big>Keys</big>** : 返回 map 中所有 key 组成的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)]
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
- **<big>KeysBy</big>** : 创建一个切片其元素是每个mapkey调用mapper函数的结果。
- **<big>KeysBy</big>** : 创建一个切片,其元素是每个 mapkey 调用 mapper 函数的结果。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#KeysBy)]
[[play](https://go.dev/play/p/hI371iB8Up8)]
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
[[play](https://go.dev/play/p/H95LENF1uB-)]
@@ -638,19 +636,25 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>Values</big>** : 返回 map 中所有 values 组成的切片
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)]
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
- **<big>ValuesBy</big>** : 创建一个切片其元素是每个mapvalue调用mapper函数的结果。
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 mapvalue 调用 mapper 函数的结果。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
- **<big>MapKeys</big>** : 操作map的每个key然后转为新的map。
[[play](https://go.dev/play/p/sg9-oRidh8f)]
- **<big>MapKeys</big>** : 操作 map 的每个 key然后转为新的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
- **<big>MapValues</big>** : 操作map的每个value然后转为新的map。
[[play](https://go.dev/play/p/8scDxWeBDKd)]
- **<big>MapValues</big>** : 操作 map 的每个 value然后转为新的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
- **<big>Entries</big>** : 将map转换为键/值对切片。
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
- **<big>FromEntries</big>** : 基于键/值对的切片创建map。
[[play](https://go.dev/play/p/Ltb11LNcElY)]
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
- **<big>Transform</big>** : 将map转换为其他类型的map。
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
- **<big>IsDisjoint</big>** : 验证两个map是否具有不同的key。
[[play](https://go.dev/play/p/P6ovfToM3zj)]
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
@@ -698,6 +702,20 @@ import "github.com/duke-git/lancet/v2/mathutil"
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
[[play](https://go.dev/play/p/aumarSHIGzP)]
- **<big>Range</big>** : 根据指定的起始值和数量,创建一个数字切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Range)]
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
- **<big>RangeWithStep</big>** : 根据指定的起始值,结束值,步长,创建一个数字切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RangeWithStep)]
[[play](https://go.dev/play/p/akLWz0EqOSM)]
- **<big>AngleToRadian</big>** : 将角度值转为弧度值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#AngleToRadian)]
- **<big>RadianToAngle</big>** : 将弧度值转为角度值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RadianToAngle)]
- **<big>PointDistance</big>** : 计算两个坐标点的距离。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#PointDistance)]
- **<big>IsPrime</big>** : 判断质数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#IsPrime)]
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
@@ -707,64 +725,61 @@ import "github.com/duke-git/lancet/v2/netutil"
#### 函数列表:
- **<big>ConvertMapToQueryString</big>** : 将map转换成http查询字符串。
- **<big>ConvertMapToQueryString</big>** : 将 map 转换成 http 查询字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)]
[[play](https://go.dev/play/p/jnNt_qoSnRi)]
- **<big>EncodeUrl</big>** : 编码url query string的值(?a=1&b=[2] -> ?a=1&b=%5B2%5D)。
- **<big>EncodeUrl</big>** : 编码 url query string 的值(?a=1&b=[2] -> ?a=1&b=%5B2%5D)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#EncodeUrl)]
[[play](https://go.dev/play/p/bsZ6BRC4uKI)]
- **<big>GetInternalIp</big>** : 获取内部ipv4。
- **<big>GetInternalIp</big>** : 获取内部 ipv4。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)]
[[play](https://go.dev/play/p/5mbu-gFp7ei)]
- **<big>GetIps</big>** : 获取系统ipv4地址列表。
- **<big>GetIps</big>** : 获取系统 ipv4 地址列表。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetIps)]
[[play](https://go.dev/play/p/NUFfcEmukx1)]
- **<big>GetMacAddrs</big>** : 获取系统mac地址列。
- **<big>GetMacAddrs</big>** : 获取系统 mac 地址列。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetMacAddrs)]
[[play](https://go.dev/play/p/Rq9UUBS_Xp1)]
- **<big>GetPublicIpInfo</big>** : 获取[公网ip信息](http://ip-api.com/json/).
- **<big>GetPublicIpInfo</big>** : 获取[公网 ip 信息](http://ip-api.com/json/).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)]
[[play](https://go.dev/play/p/YDxIfozsRHR)]
- **<big>GetRequestPublicIp</big>** : 获取http请求ip。
- **<big>GetRequestPublicIp</big>** : 获取 http 请求 ip。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp)]
[[play](https://go.dev/play/p/kxU-YDc_eBo)]
- **<big>IsPublicIP</big>** : 判断ip是否是公共ip。
- **<big>IsPublicIP</big>** : 判断 ip 是否是公共 ip。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)]
[[play](https://go.dev/play/p/nmktSQpJZnn)]
- **<big>IsInternalIP</big>** : 判断ip是否是局域网ip。
- **<big>IsInternalIP</big>** : 判断 ip 是否是局域网 ip。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)]
[[play](https://go.dev/play/p/sYGhXbgO4Cb)]
- **<big>HttpRequest</big>** : 用于抽象HTTP请求实体的结构。
- **<big>HttpRequest</big>** : 用于抽象 HTTP 请求实体的结构。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>HttpClient</big>** : 用于发送HTTP请求。
- **<big>HttpClient</big>** : 用于发送 HTTP 请求。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpClient)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>SendRequest</big>** : 发送http请求。
- **<big>SendRequest</big>** : 发送 http 请求。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>DecodeResponse</big>** : 解析http响应体到目标结构体。
- **<big>DecodeResponse</big>** : 解析 http 响应体到目标结构体。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)]
[[play](https://go.dev/play/p/jUSgynekH7G)]
- **<big>StructToUrlValues</big>** : 将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag。
- **<big>StructToUrlValues</big>** : 将结构体转为 url values, 仅转化结构体导出字段并且包含`json` tag。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)]
[[play](https://go.dev/play/p/pFqMkM40w9z)]
- **<big>HttpGet<sup>deprecated</sup></big>** : 发送http get请求已弃用SendRequest代替
- **<big>HttpGet<sup>deprecated</sup></big>** : 发送 http get 请求已弃用SendRequest 代替)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)]
- **<big>HttpDelete<sup>deprecated</sup></big>** : 发送http delete请求已弃用SendRequest代替
- **<big>HttpDelete<sup>deprecated</sup></big>** : 发送 http delete 请求已弃用SendRequest 代替)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)]
- **<big>HttpPost<sup>deprecated</sup></big>** : 发送http post请求已弃用SendRequest代替
- **<big>HttpPost<sup>deprecated</sup></big>** : 发送 http post 请求已弃用SendRequest 代替)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)]
- **<big>HttpPut<sup>deprecated</sup></big>** : 发送http put请求已弃用SendRequest代替
- **<big>HttpPut<sup>deprecated</sup></big>** : 发送 http put 请求已弃用SendRequest 代替)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)]
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送http patch请求已弃用SendRequest代替
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送 http patch 请求已弃用SendRequest 代替)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)]
- **<big>ParseHttpResponse</big>** : 解析http响应体到目标结构体。
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
```go
@@ -776,7 +791,7 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>RandBytes</big>** : 生成随机字节切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)]
[[play](https://go.dev/play/p/EkiLESeXf8d)]
- **<big>RandInt</big>** : 生成随机int, 范围[min, max)。
- **<big>RandInt</big>** : 生成随机 int, 范围[min, max)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)]
[[play](https://go.dev/play/p/pXyyAAI5YxD)]
- **<big>RandString</big>** : 生成给定长度的随机字符串,只包含字母(a-zA-Z)。
@@ -794,11 +809,9 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>RandNumeralOrLetter</big>** : 生成给定长度的随机字符串(数字+字母)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)]
[[play](https://go.dev/play/p/19CEQvpx2jD)]
- **<big>UUIdV4</big>** : 生成UUID v4字符串。
- **<big>UUIdV4</big>** : 生成 UUID v4 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
@@ -808,24 +821,22 @@ import "github.com/duke-git/lancet/v2/retry"
#### 函数列表:
- **<big>Context</big>** : 设置重试context参数。
- **<big>Context</big>** : 设置重试 context 参数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)]
[[play](https://go.dev/play/p/xnAOOXv9GkS)]
- **<big>Retry</big>** : 重试执行函数retryFunc直到函数运行成功或被context取消。
- **<big>Retry</big>** : 重试执行函数 retryFunc直到函数运行成功或被 context 取消。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)]
[[play](https://go.dev/play/p/nk2XRmagfVF)]
- **<big>RetryFunc</big>** : 重试执行的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)]
[[play](https://go.dev/play/p/nk2XRmagfVF)]
- **<big>RetryDuration</big>** : 设置重试间隔时间,默认3秒。
- **<big>RetryDuration</big>** : 设置重试间隔时间,默认 3 秒。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)]
[[play](https://go.dev/play/p/nk2XRmagfVF)]
- **<big>RetryTimes</big>** : 设置重试次数默认5。
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
### 16. slice 包含操作切片的方法集合。
```go
@@ -833,36 +844,38 @@ import "github.com/duke-git/lancet/v2/slice"
```
#### 函数列表:
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
- **<big>Contain</big>** : 判断slice是否包含value。
- **<big>Contain</big>** : 判断 slice 是否包含 value。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)]
[[play](https://go.dev/play/p/_454yEHcNjf)]
- **<big>ContainBy</big>** : 根据predicate函数判断切片是否包含某个值。
- **<big>ContainBy</big>** : 根据 predicate 函数判断切片是否包含某个值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainBy)]
- **<big>ContainSubSlice</big>** : 判断slice是否包含subslice。
[[play](https://go.dev/play/p/49tkHfX4GNc)]
- **<big>ContainSubSlice</big>** : 判断 slice 是否包含 subslice。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
- **<big>Chunk</big>** : 按照size参数均分slice。
- **<big>Chunk</big>** : 按照 size 参数均分 slice。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)]
[[play](https://go.dev/play/p/b4Pou5j2L_C)]
- **<big>Compact</big>** : 去除slice中的假值false values are false, nil, 0, "")。
- **<big>Compact</big>** : 去除 slice 中的假值false values are false, nil, 0, "")。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)]
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
- **<big>Concat</big>** : 合并多个slices到一个slice中。
- **<big>Concat</big>** : 合并多个 slices 到一个 slice 中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)]
[[play](https://go.dev/play/p/gPt-q7zr5mk)]
- **<big>Count</big>** : 返回切片中指定元素的个数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)]
[[play](https://go.dev/play/p/Mj4oiEnQvRJ)]
- **<big>CountBy</big>** : 遍历切片对每个元素执行函数predicate. 返回符合函数返回值为true的元素的个数。
- **<big>CountBy</big>** : 遍历切片,对每个元素执行函数 predicate. 返回符合函数返回值为 true 的元素的个数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#CountBy)]
[[play](https://go.dev/play/p/tHOccTMDZCC)]
- **<big>Difference</big>** : 创建一个切片,其元素不包含在另一个给定切片中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)]
[[play](https://go.dev/play/p/VXvadzLzhDa)]
- **<big>DifferenceBy</big>** : 将两个slice中的每个元素调用iteratee函数并比较它们的返回值如果不相等返回在slice中对应的值。
- **<big>DifferenceBy</big>** : 将两个 slice 中的每个元素调用 iteratee 函数,并比较它们的返回值,如果不相等返回在 slice 中对应的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)]
[[play](https://go.dev/play/p/DiivgwM5OnC)]
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
@@ -871,36 +884,37 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)]
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
- **<big>Drop</big>** : 从切片头部删除n个元素。
- **<big>Drop</big>** : 从切片头部删除 n 个元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)]
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
- **<big>DropRight</big>** : 从切片尾部删除n个元素。
- **<big>DropRight</big>** : 从切片尾部删除 n 个元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRight)]
[[play](https://go.dev/play/p/8bcXvywZezG)]
- **<big>DropWhile</big>** : 从切片的头部删除n个元素,这个n个元素满足predicate函数返回true。
- **<big>DropWhile</big>** : 从切片的头部删除 n 个元素,这个 n 个元素满足 predicate 函数返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropWhile)]
[[play](https://go.dev/play/p/4rt252UV_qs)]
- **<big>DropRightWhile</big>** : 从切片的尾部删除n个元素,这个n个元素满足predicate函数返回true。
- **<big>DropRightWhile</big>** : 从切片的尾部删除 n 个元素,这个 n 个元素满足 predicate 函数返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DropRightWhile)]
[[play](https://go.dev/play/p/6wyK3zMY56e)]
- **<big>Equal</big>** : 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Equal)]
[[play](https://go.dev/play/p/WcRQJ37ifPa)]
- **<big>EqualWith</big>** : 检查两个切片是否相等相等条件对两个切片的元素调用比较函数comparator返回true。
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数 comparator返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#EqualWith)]
[[play](https://go.dev/play/p/b9iygtgsHI1)]
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数则返回true。
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)]
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
- **<big>Filter</big>** : 返回切片中通过predicate函数真值测试的所有元素。
- **<big>Filter</big>** : 返回切片中通过 predicate 函数真值测试的所有元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)]
[[play](https://go.dev/play/p/SdPna-7qK4T)]
- **<big>FilterMap</big>** : 返回一个将filtermap操作应用于给定切片的切片。
- **<big>FilterMap</big>** : 返回一个将 filtermap 操作应用于给定切片的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
- **<big>Find</big>** : 遍历切片的元素返回第一个通过predicate函数真值测试的元素。
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
- **<big>FindLast</big>** : 从头到尾遍历slice的元素返回最后一个通过predicate函数真值测试的元素。
- **<big>FindLast</big>** : 从头到尾遍历 slice 的元素,返回最后一个通过 predicate 函数真值测试的元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)]
[[play](https://go.dev/play/p/FFDPV_j7URd)]
- **<big>Flatten</big>** : 将多维切片展平一层。
@@ -911,19 +925,23 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
- **<big>FlatMap</big>** : 将切片转换为其它类型切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlatMap)]
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用iteratee函数。
[[play](https://go.dev/play/p/_QARWlWs1N_F)]
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
- **<big>ForEachWithBreak</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数,当 iteratee 函数返回 false 时,终止遍历。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEachWithBreak)]
[[play](https://go.dev/play/p/qScs39f3D9W)]
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
- **<big>GroupWith</big>** : 创建一个mapkeyiteratee遍历slice中的每个元素返回的结果。值是切片元素。
- **<big>GroupWith</big>** : 创建一个 mapkeyiteratee 遍历 slice 中的每个元素返回的结果。值是切片元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)]
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
- **<big>IntSlice<sup>deprecated</sup></big>** : 将接口切片转换为int切片。
- **<big>IntSlice<sup>deprecated</sup></big>** : 将接口切片转换为 int 切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)]
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : 将值转换为interface切片。
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : 将值转换为 interface 切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)]
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
- **<big>Intersection</big>** : 返回多个切片的交集。
@@ -938,7 +956,7 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>LastIndexOf</big>** : 返回在切片中找到最后一个值的索引,如果找不到该值,则返回-1。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)]
[[play](https://go.dev/play/p/DokM4cf1IKH)]
- **<big>Map</big>** : 对slice中的每个元素执行map函数以创建一个新切片。
- **<big>Map</big>** : 对 slice 中的每个元素执行 map 函数以创建一个新切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)]
[[play](https://go.dev/play/p/biaTefqPquw)]
- **<big>Merge</big>** : 合并多个切片(不会消除重复元素)。
@@ -947,16 +965,16 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Reverse</big>** : 反转切片中的元素顺序。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)]
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
- **<big>Reduce</big>** : 将切片中的元素依次运行iteratee函数返回运行结果。
- **<big>Reduce</big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)]
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
- **<big>Replace</big>** : 返回切片的副本,其中前n个不重叠的old替换为new。
- **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)]
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
- **<big>ReplaceAll</big>** : 返回切片的副本将其中old全部替换为new。
- **<big>ReplaceAll</big>** : 返回切片的副本,将其中 old 全部替换为 new。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReplaceAll)]
[[play](https://go.dev/play/p/CzqXMsuYUrx)]
- **<big>Repeat</big>** : 创建一个切片,包含n个传入的item。
- **<big>Repeat</big>** : 创建一个切片,包含 n 个传入的 item。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Repeat)]
[[play](https://go.dev/play/p/1CbOmtgILUU)]
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
@@ -971,19 +989,19 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>IsSorted</big>** : 检查切片元素是否是有序的(升序或降序)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSorted)]
[[play](https://go.dev/play/p/nCE8wPLwSA-)]
- **<big>IsSortedByKey</big>** : 通过iteratee函数检查切片元素是否是有序的。
- **<big>IsSortedByKey</big>** : 通过 iteratee 函数,检查切片元素是否是有序的。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IsSortedByKey)]
[[play](https://go.dev/play/p/tUoGB7DOHI4)]
- **<big>Sort</big>** : 对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Sort)]
[[play](https://go.dev/play/p/V9AVjzf_4Fk)]
- **<big>SortBy</big>** : 按照less函数确定的升序规则对切片进行排序。排序不保证稳定性。
- **<big>SortBy</big>** : 按照 less 函数确定的升序规则对切片进行排序。排序不保证稳定性。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortBy)]
[[play](https://go.dev/play/p/DAhLQSZEumm)]
- **<big>SortByField<sup>deprecated</sup></big>** : 按字段对结构切片进行排序。slice元素应为struct字段类型应为int、uint、stringbool。
- **<big>SortByField<sup>deprecated</sup></big>** : 按字段对结构切片进行排序。slice 元素应为 struct字段类型应为 int、uint、stringbool。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)]
[[play](https://go.dev/play/p/fU1prOBP9p1)]
- **<big>Some</big>** : 如果列表中的任何值通过谓词函数则返回true。
- **<big>Some</big>** : 如果列表中的任何值通过谓词函数,则返回 true。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)]
[[play](https://go.dev/play/p/4pO9Xf9NDGS)]
- **<big>StringSlice<sup>deprecated</sup></big>** : 将接口切片转换为字符串切片。
@@ -1001,7 +1019,7 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Unique</big>** : 删除切片中的重复元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)]
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
- **<big>UniqueBy</big>** : 对切片的每个元素调用iteratee函数然后删除重复元素。
- **<big>UniqueBy</big>** : 对切片的每个元素调用 iteratee 函数,然后删除重复元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UniqueBy)]
[[play](https://go.dev/play/p/UR323iZLDpv)]
- **<big>Union</big>** : 合并多个切片。
@@ -1016,12 +1034,46 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>Without</big>** : 创建一个不包括所有给定值的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)]
[[play](https://go.dev/play/p/bwhEXEypThg)]
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为map。
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
### 17. strutil 包含字符串处理的相关函数。
### 17. structs 提供操作 struct, tag, field 的相关函数。
```go
import "github.com/duke-git/lancet/v2/structs"
```
#### Function list:
- **<big>New</big>** : `Struct`结构体的构造函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#New)]
- **<big>ToMap</big>** : 将一个合法的 struct 对象转换为 map[string]any。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)]
- **<big>Fields</big>** : 获取一个 struct 对象的属性列表。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
- **<big>Field</big>** : 根据属性名获取一个 struct 对象的属性。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
- **<big>IsStruct</big>** : 判断是否为一个合法的 struct 对象。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)]
- **<big>Tag</big>** : 获取`Field``Tag`,默认的 tag key 是 json。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Tag)]
- **<big>Name</big>** : 获取属性名。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Name)]
- **<big>Value</big>** : 获取`Field`属性的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Value)]
- **<big>Kind</big>** : 获取属性 Kind。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Kind)]
- **<big>IsEmbedded</big>** : 判断属性是否为嵌入。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsEmbedded)]
- **<big>IsExported</big>** : 判断属性是否导出。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsExported)]
- **<big>IsZero</big>** : 判断属性是否为零值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsZero)]
- **<big>IsSlice</big>** : 判断属性是否是切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
### 18. strutil 包含字符串处理的相关函数。
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -1062,8 +1114,9 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>UpperFirst</big>** : 将字符串的第一个字符转换为大写形式。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)]
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
- **<big>Pad</big>** : 如果字符串长度短于size则在左右两侧填充字符串。
- **<big>Pad</big>** : 如果字符串长度短于 size则在左右两侧填充字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Pad)]
[[play](https://go.dev/play/p/NzImQq-VF8q)]
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
[[play](https://go.dev/play/p/9xP8rN0vz--)]
@@ -1093,10 +1146,14 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
- **<big>SplitWords</big>** : 将字符串拆分为单词,只支持字母字符单词。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitWords)]
[[play](https://go.dev/play/p/KLiX4WiysMM)]
- **<big>WordCount</big>** : 返回有意义单词的数量,只支持字母字符单词。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#WordCount)]
[[play](https://go.dev/play/p/bj7_odx3vRf)]
- **<big>RemoveNonPrintable</big>** : 删除字符串中不可打印的字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveNonPrintable)]
### 18. system 包含 os, runtime, shell command 的相关函数。
### 19. system 包含 os, runtime, shell command 的相关函数。
```go
import "github.com/duke-git/lancet/v2/system"
@@ -1132,7 +1189,7 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
### 19. validator 验证器包,包含常用字符串格式验证函数。
### 20. validator 验证器包,包含常用字符串格式验证函数。
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -1161,7 +1218,7 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsAllLower</big>** : 验证字符串是否全是小写英文字母。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)]
[[play](https://go.dev/play/p/GjqCnOfV6cM)]
- **<big>IsBase64</big>** : 验证字符串是否是base64编码。
- **<big>IsBase64</big>** : 验证字符串是否是 base64 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)]
[[play](https://go.dev/play/p/sWHEySAt6hl)]
- **<big>IsChineseMobile</big>** : 验证字符串是否是中国手机号码。
@@ -1176,7 +1233,7 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsCreditCard</big>** : 验证字符串是否是信用卡号码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)]
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
- **<big>IsDns</big>** : 验证字符串是否是有效dns。
- **<big>IsDns</big>** : 验证字符串是否是有效 dns。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)]
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
@@ -1191,7 +1248,7 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)]
[[play](https://go.dev/play/p/LzaKocSV79u)]
- **<big>IsJSON</big>** : 验证字符串是否是有效json。
- **<big>IsJSON</big>** : 验证字符串是否是有效 json。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)]
[[play](https://go.dev/play/p/sRS6c4K8jGk)]
- **<big>IsRegexMatch</big>** : 验证字符串是否可以匹配正则表达式。
@@ -1200,19 +1257,19 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsIntStr</big>** : 验证字符串是否是可以转换为整数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)]
[[play](https://go.dev/play/p/jQRtFv-a0Rk)]
- **<big>IsIp</big>** : 验证字符串是否是ip地址。
- **<big>IsIp</big>** : 验证字符串是否是 ip 地址。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)]
[[play](https://go.dev/play/p/FgcplDvmxoD)]
- **<big>IsIpV4</big>** : 验证字符串是否是ipv4地址。
- **<big>IsIpV4</big>** : 验证字符串是否是 ipv4 地址。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)]
[[play](https://go.dev/play/p/zBGT99EjaIu)]
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
- **<big>IsIpV6</big>** : 验证字符串是否是 ipv6 地址。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)]
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)]
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
- **<big>IsUrl</big>** : 验证字符串是否是url。
- **<big>IsUrl</big>** : 验证字符串是否是 url。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)]
[[play](https://go.dev/play/p/pbJGa7F98Ka)]
- **<big>IsWeakPassword</big>** : 验证字符串是否是弱密码(只包含字母+数字)。
@@ -1221,12 +1278,15 @@ import "github.com/duke-git/lancet/v2/validator"
- **<big>IsZeroValue</big>** : 判断传入的参数值是否为零值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)]
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
- **<big>IsGBK</big>** : 检查数据编码是否为gbk汉字内部代码扩展规范
- **<big>IsGBK</big>** : 检查数据编码是否为 gbk汉字内部代码扩展规范
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
[[play](https://go.dev/play/p/E2nt3unlmzP)]
- **<big>IsASCII</big>** : 验证字符串全部为 ASCII 字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsASCII)]
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
### 20. xerror 包实现一些错误处理函数
### 21. xerror 包实现一些错误处理函数
```go
import "github.com/duke-git/lancet/v2/xerror"
@@ -1234,46 +1294,45 @@ import "github.com/duke-git/lancet/v2/xerror"
#### 函数列表:
- **<big>New</big>** : 创建XError对象实例。
- **<big>New</big>** : 创建 XError 对象实例。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#New)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>Wrap</big>** : 根据error对象创建XError对象实例可添加message。
- **<big>Wrap</big>** : 根据 error 对象创建 XError 对象实例,可添加 message。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>Unwrap</big>** : 从error对象中解构出XError。
- **<big>Unwrap</big>** : 从 error 对象中解构出 XError。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)]
[[play](https://go.dev/play/p/LKMLep723tu)]
- **<big>XError_Wrap</big>** : 创建新的XError对象并将消息和id复制到新的对象中。
- **<big>XError_Wrap</big>** : 创建新的 XError 对象并将消息和 id 复制到新的对象中。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Wrap)]
[[play](https://go.dev/play/p/5385qT2dCi4)]
- **<big>XError_Unwrap</big>** : 解构XEerrorerror对象。适配github.com/pkg/errors。
- **<big>XError_Unwrap</big>** : 解构 XEerrorerror 对象。适配 github.com/pkg/errors。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Unwrap)]
[[play](https://go.dev/play/p/VUXJ8BST4c6)]
- **<big>XError_With</big>** : 添加与XError对象的键和值。
- **<big>XError_With</big>** : 添加与 XError 对象的键和值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_With)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_Id</big>** : 设置XError对象的id。
- **<big>XError_Id</big>** : 设置 XError 对象的 id。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Id)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Is</big>** : 检查目标error是否为XError两个错误中的error.id是否匹配。
- **<big>XError_Is</big>** : 检查目标 error 是否为 XError两个错误中的 error.id 是否匹配。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Is)]
[[play](https://go.dev/play/p/X6HBlsy58U9)]
- **<big>XError_Values</big>** : 返回由With设置的键和值的映射。将合并所有XError键和值。
- **<big>XError_Values</big>** : 返回由 With 设置的键和值的映射。将合并所有 XError 键和值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Values)]
[[play](https://go.dev/play/p/ow8UISXX_Dp)]
- **<big>XError_StackTrace</big>** : 返回与pkg/error兼容的堆栈信息。
- **<big>XError_StackTrace</big>** : 返回与 pkg/error 兼容的堆栈信息。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_StackTrace)]
[[play](https://go.dev/play/p/6FAvSQpa7pc)]
- **<big>XError_Info</big>** : 返回可打印的XError对象信息。
- **<big>XError_Info</big>** : 返回可打印的 XError 对象信息。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Info)]
[[play](https://go.dev/play/p/1ZX0ME1F-Jb)]
- **<big>XError_Error</big>** : 实现标准库的error接口。
- **<big>XError_Error</big>** : 实现标准库的 error 接口。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#XError_Error)]
[[play](https://go.dev/play/p/w4oWZts7q7f)]
- **<big>TryUnwrap</big>** : 检查error, 如果errnil则展开则它返回一个有效值如果err不是nilUnwrap使用err发生panic。
- **<big>TryUnwrap</big>** : 检查 error, 如果 errnil 则展开,则它返回一个有效值,如果 err 不是 nilUnwrap 使用 err 发生 panic。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#TryUnwrap)]
[[play](https://go.dev/play/p/acyZVkNZEeW)]
## 如何贡献代码

View File

@@ -1,7 +1,7 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
package concurrency
import (

View File

@@ -11,9 +11,9 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/duke-git/lancet/v2/structs"
"math"
"reflect"
"regexp"
"strconv"
"strings"
)
@@ -235,31 +235,7 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
// map key is specified same as struct field tag `json` value.
// Play: https://go.dev/play/p/KYGYJqNUBOI
func StructToMap(value any) (map[string]any, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
result := make(map[string]any)
fieldNum := t.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := t.Field(i).Name
tag := t.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
//result[name] = v.Field(i).Interface()
result[tag] = v.Field(i).Interface()
}
}
return result, nil
return structs.ToMap(value)
}
// MapToSlice convert map to slice based on iteratee function.
@@ -343,11 +319,11 @@ func DeepClone[T any](src T) T {
}
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// Play: todo
// Play: https://go.dev/play/p/FOVY3XJL-6B
func CopyProperties[T, U any](dst T, src U) (err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(fmt.Sprintf("%v", e))
err = fmt.Errorf("%v", e)
}
}()

View File

@@ -255,12 +255,12 @@ func ExampleDecodeByte() {
func ExampleDeepClone() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
}
cases := []interface{}{
@@ -293,7 +293,7 @@ func ExampleDeepClone() {
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
// &{test 1 0.1 true <nil>} false
}
func ExampleCopyProperties() {
@@ -323,12 +323,18 @@ func ExampleCopyProperties() {
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
employee1 := Employee{}
CopyProperties(&employee1, &user)
err := CopyProperties(&employee1, &user)
if err != nil {
return
}
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
CopyProperties(&employee2, &user)
err = CopyProperties(&employee2, &user)
if err != nil {
return
}
fmt.Println(employee1)
fmt.Println(employee2)

View File

@@ -180,18 +180,36 @@ func TestToMap(t *testing.T) {
func TestStructToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToMap")
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
t.Run("StructToMap", func(_ *testing.T) {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
})
expected := map[string]any{"name": "test"}
assert.Equal(expected, pm)
t.Run("StructToMapWithJsonAttr", func(_ *testing.T) {
type People struct {
Name string `json:"name,omitempty"` // json tag with attribute
Phone string `json:"phone"` // json tag without attribute
Sex string `json:"-"` // ignore
age int // no tag
}
p := People{
Phone: "1111",
Sex: "male",
age: 100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"phone": "1111"}
assert.Equal(expected, pm)
})
}
func TestMapToSlice(t *testing.T) {
@@ -259,12 +277,12 @@ func TestDeepClone(t *testing.T) {
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
Str string
Int int
Float float64
Bool bool
Nil interface{}
// unexported string
}
cases := []interface{}{

View File

@@ -17,7 +17,7 @@ type mapNode struct {
next *mapNode
}
//HashMap implements a hash map
// HashMap implements a hash map
type HashMap struct {
capacity uint64
size uint64

View File

@@ -171,3 +171,25 @@ func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
return set
}
// EachWithBreak iterates over elements of a set and invokes function for each element,
// when iteratee return false, will break the for each loop.
func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
for _, v := range s.Values() {
if !iteratee(v) {
break
}
}
}
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
func (s Set[T]) Pop() (v T, ok bool) {
if len(s) > 0 {
items := s.Values()
item := items[len(s)-1]
delete(s, item)
return item, true
}
return v, false
}

View File

@@ -192,3 +192,40 @@ func TestSet_Minus(t *testing.T) {
assert.Equal(NewSet(1), set1.Minus(set2))
assert.Equal(NewSet(4, 5), set2.Minus(set3))
}
func TestEachWithBreak(t *testing.T) {
// s := NewSet(1, 2, 3, 4, 5)
// var sum int
// s.EachWithBreak(func(n int) bool {
// if n > 3 {
// return false
// }
// sum += n
// return true
// })
// assert := internal.NewAssert(t, "TestEachWithBreak")
// assert.Equal(6, sum)
}
// func TestPop(t *testing.T) {
// assert := internal.NewAssert(t, "TestPop")
// s := NewSet[int]()
// val, ok := s.Pop()
// assert.Equal(0, val)
// assert.Equal(false, ok)
// s.Add(1)
// s.Add(2)
// s.Add(3)
// // s = NewSet(1, 2, 3, 4, 5)
// val, ok = s.Pop()
// assert.Equal(3, val)
// assert.Equal(true, ok)
// }

View File

@@ -1,5 +1,5 @@
# Concurrency
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
<div STYLE="page-break-after: always;"></div>

View File

@@ -1,5 +1,5 @@
# Concurrency
并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
并发包包含一些支持并发编程的功能。例如goroutine, channel等。
<div STYLE="page-break-after: always;"></div>

View File

@@ -1,16 +1,17 @@
# Set
Set is a data container, like list, but elements of set is not duplicate.
<div STYLE="page-break-after: always;"></div>
## Source
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
<div STYLE="page-break-after: always;"></div>
## Usage
```go
import (
set "github.com/duke-git/lancet/v2/datastructure/set"
@@ -21,32 +22,32 @@ import (
## Index
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [EachWithBreak](#EachWithBreak)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="NewSet">NewSet</span>
<p>Create a set instance</p>
<b>Signature:</b>
@@ -55,6 +56,7 @@ import (
type Set[T comparable] map[T]bool
func NewSet[T comparable](items ...T) Set[T]
```
<b>Example:</b>
```go
@@ -71,8 +73,8 @@ func main() {
}
```
### <span id="NewSetFromSlice">NewSetFromSlice</span>
<p>Create a set from slice</p>
<b>Signature:</b>
@@ -80,6 +82,7 @@ func main() {
```go
func NewSetFromSlice[T comparable](items []T) Set[T]
```
<b>Example:</b>
```go
@@ -96,9 +99,8 @@ func main() {
}
```
### <span id="Values">Values</span>
<p>Return slice of all set data</p>
<b>Signature:</b>
@@ -106,6 +108,7 @@ func main() {
```go
func (s Set[T]) Values() []T
```
<b>Example:</b>
```go
@@ -122,10 +125,8 @@ func main() {
}
```
### <span id="Add">Add</span>
<p>Add items to set</p>
<b>Signature:</b>
@@ -133,6 +134,7 @@ func main() {
```go
func (s Set[T]) Add(items ...T)
```
<b>Example:</b>
```go
@@ -151,8 +153,8 @@ func main() {
}
```
### <span id="AddIfNotExist">AddIfNotExist</span>
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
<b>Signature:</b>
@@ -160,6 +162,7 @@ func main() {
```go
func (s Set[T]) AddIfNotExist(item T) bool
```
<b>Example:</b>
```go
@@ -175,7 +178,7 @@ func main() {
st.Add(1, 2, 3)
r1 := st.AddIfNotExist(1)
r2 := st.AddIfNotExist(4)
r2 := st.AddIfNotExist(4)
fmt.Println(r1) // false
fmt.Println(r2) // true
@@ -183,8 +186,8 @@ func main() {
}
```
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
<b>Signature:</b>
@@ -192,6 +195,7 @@ func main() {
```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
```
<b>Example:</b>
```go
@@ -206,23 +210,23 @@ func main() {
st := set.NewSet[int]()
st.Add(1, 2)
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
fmt.Println(ok) // true
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
fmt.Println(notOk) // false
fmt.Println(st.Values()) // 1, 2, 3
}
```
### <span id="Delete">Delete</span>
<p>Delete item in set</p>
<b>Signature:</b>
@@ -230,6 +234,7 @@ func main() {
```go
func (s Set[T]) Delete(items ...T)
```
<b>Example:</b>
```go
@@ -249,9 +254,8 @@ func main() {
}
```
### <span id="Contain">Contain</span>
<p>Check if item is in set or not</p>
<b>Signature:</b>
@@ -259,6 +263,7 @@ func main() {
```go
func (s Set[T]) Contain(item T) bool
```
<b>Example:</b>
```go
@@ -278,10 +283,8 @@ func main() {
}
```
### <span id="ContainAll">ContainAll</span>
<p>Checks if set contains another set</p>
<b>Signature:</b>
@@ -289,6 +292,7 @@ func main() {
```go
func (s Set[T]) ContainAll(other Set[T]) bool
```
<b>Example:</b>
```go
@@ -301,17 +305,16 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
fmt.Println(set1.ContainAll(set2)) //true
fmt.Println(set1.ContainAll(set3)) //false
}
```
### <span id="Size">Size</span>
<p>Get the number of elements in set</p>
<b>Signature:</b>
@@ -319,6 +322,7 @@ func main() {
```go
func (s Set[T]) Size() int
```
<b>Example:</b>
```go
@@ -336,9 +340,8 @@ func main() {
}
```
### <span id="Clone">Clone</span>
<p>Make a copy of set</p>
<b>Signature:</b>
@@ -346,6 +349,7 @@ func main() {
```go
func (s Set[T]) Clone() Set[T]
```
<b>Example:</b>
```go
@@ -365,10 +369,8 @@ func main() {
}
```
### <span id="Equal">Equal</span>
<p>Check if two sets has same elements or not</p>
<b>Signature:</b>
@@ -376,6 +378,7 @@ func main() {
```go
func (s Set[T]) Equal(other Set[T]) bool
```
<b>Example:</b>
```go
@@ -396,9 +399,8 @@ func main() {
}
```
### <span id="Iterate">Iterate</span>
<p>Call function by every element of set</p>
<b>Signature:</b>
@@ -406,6 +408,7 @@ func main() {
```go
func (s Set[T]) Iterate(fn func(item T))
```
<b>Example:</b>
```go
@@ -427,9 +430,45 @@ func main() {
}
```
### <span id="EachWithBreak">EachWithBreak</span>
<p>Iterates over elements of a set and invokes function for each element, when iteratee return false, will break the for each loop.</p>
<b>Signature:</b>
```go
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet(1, 2, 3, 4, 5)
var sum int
s.EachWithBreak(func(n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum) //6
}
```
### <span id="IsEmpty">IsEmpty</span>
<p>Check if the set is empty or not</p>
<b>Signature:</b>
@@ -437,6 +476,7 @@ func main() {
```go
func (s Set[T]) IsEmpty() bool
```
<b>Example:</b>
```go
@@ -456,9 +496,8 @@ func main() {
}
```
### <span id="Union">Union</span>
<p>Create a new set contain all element of set s and other</p>
<b>Signature:</b>
@@ -466,6 +505,7 @@ func main() {
```go
func (s Set[T]) Union(other Set[T]) Set[T]
```
<b>Example:</b>
```go
@@ -485,9 +525,8 @@ func main() {
}
```
### <span id="Intersection">Intersection</span>
<p>Create a new set whose element both be contained in set s and other</p>
<b>Signature:</b>
@@ -495,6 +534,7 @@ func main() {
```go
func (s Set[T]) Intersection(other Set[T]) Set[T]
```
<b>Example:</b>
```go
@@ -514,11 +554,8 @@ func main() {
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
<b>Signature:</b>
@@ -526,6 +563,7 @@ func main() {
```go
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
```
<b>Example:</b>
```go
@@ -538,18 +576,15 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
fmt.Println(set3.Values()) //1,4,5
}
```
### <span id="Minus">Minus</span>
<p>Create an set of whose element in origin set but not in compared set</p>
<b>Signature:</b>
@@ -557,6 +592,7 @@ func main() {
```go
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
```
<b>Example:</b>
```go
@@ -569,8 +605,8 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
res1 := set1.Minus(set2)
fmt.Println(res1.Values()) //1
@@ -580,5 +616,35 @@ func main() {
}
```
### <span id="Pop">Pop</span>
<p>Delete the top element of set then return it, if set is empty, return nil-value of T and false.</p>
<b>Signature:</b>
```go
func (s Set[T]) Pop() (v T, ok bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet[int]()
s.Add(1)
s.Add(2)
s.Add(3)
val, ok = s.Pop()
fmt.Println(val) // 3
fmt.Println(ok) // true
}
```

View File

@@ -1,16 +1,17 @@
# Set
Set集合数据结构类似列表。Set中元素不重复。
Set 集合数据结构类似列表。Set 中元素不重复。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
set "github.com/duke-git/lancet/v2/datastructure/set"
@@ -21,32 +22,31 @@ import (
## 目录
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
- [NewSet](#NewSet)
- [NewSetFromSlice](#NewSetFromSlice)
- [Values](#Values)
- [Add](#Add)
- [AddIfNotExist](#AddIfNotExist)
- [AddIfNotExistBy](#AddIfNotExistBy)
- [Delete](#Delete)
- [Contain](#Contain)
- [ContainAll](#ContainAll)
- [Clone](#Clone)
- [Size](#Size)
- [Equal](#Equal)
- [Iterate](#Iterate)
- [IsEmpty](#IsEmpty)
- [Union](#Union)
- [Intersection](#Intersection)
- [SymmetricDifference](#SymmetricDifference)
- [Minus](#Minus)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="NewSet">NewSet</span>
<p>返回Set结构体对象</p>
<b>函数签名:</b>
@@ -55,6 +55,7 @@ import (
type Set[T comparable] map[T]bool
func NewSet[T comparable](items ...T) Set[T]
```
<b>示例:</b>
```go
@@ -71,9 +72,8 @@ func main() {
}
```
### <span id="NewSetFromSlice">NewSetFromSlice</span>
<p>基于切片创建集合</p>
<b>函数签名:</b>
@@ -81,6 +81,7 @@ func main() {
```go
func NewSetFromSlice[T comparable](items []T) Set[T]
```
<b>示例:</b>
```go
@@ -97,9 +98,8 @@ func main() {
}
```
### <span id="Values">Values</span>
<p>获取集合中所有元素的切片</p>
<b>函数签名:</b>
@@ -107,6 +107,7 @@ func main() {
```go
func (s Set[T]) Values() []T
```
<b>示例:</b>
```go
@@ -123,10 +124,8 @@ func main() {
}
```
### <span id="Add">Add</span>
<p>向集合中添加元素</p>
<b>函数签名:</b>
@@ -134,6 +133,7 @@ func main() {
```go
func (s Set[T]) Add(items ...T)
```
<b>示例:</b>
```go
@@ -152,8 +152,8 @@ func main() {
}
```
### <span id="AddIfNotExist">AddIfNotExist</span>
<p>如果集合中不存在元素则添加该元素返回true, 如果集合中存在元素, 不做任何操作返回false</p>
<b>函数签名:</b>
@@ -161,6 +161,7 @@ func main() {
```go
func (s Set[T]) AddIfNotExist(item T) bool
```
<b>示例:</b>
```go
@@ -176,7 +177,7 @@ func main() {
st.Add(1, 2, 3)
r1 := st.AddIfNotExist(1)
r2 := st.AddIfNotExist(4)
r2 := st.AddIfNotExist(4)
fmt.Println(r1) // false
fmt.Println(r2) // true
@@ -184,8 +185,8 @@ func main() {
}
```
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
<p>根据checker函数判断元素是否在集合中如果集合中不存在元素且checker返回true则添加该元素返回true, 否则不做任何操作返回false</p>
<b>函数签名:</b>
@@ -193,6 +194,7 @@ func main() {
```go
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
```
<b>示例:</b>
```go
@@ -207,24 +209,23 @@ func main() {
st := set.NewSet[int]()
st.Add(1, 2)
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
ok := st.AddIfNotExistBy(3, func(val int) bool {
return val%2 != 0
})
fmt.Println(ok) // true
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
notOk := st.AddIfNotExistBy(4, func(val int) bool {
return val%2 != 0
})
fmt.Println(notOk) // false
fmt.Println(st.Values()) // 1, 2, 3
}
```
### <span id="Delete">Delete</span>
<p>删除集合中元素</p>
<b>函数签名:</b>
@@ -232,6 +233,7 @@ func main() {
```go
func (s Set[T]) Delete(items ...T)
```
<b>示例:</b>
```go
@@ -251,9 +253,8 @@ func main() {
}
```
### <span id="Contain">Contain</span>
<p>判断集合是否包含某个值</p>
<b>函数签名:</b>
@@ -261,6 +262,7 @@ func main() {
```go
func (s Set[T]) Contain(item T) bool
```
<b>示例:</b>
```go
@@ -280,10 +282,8 @@ func main() {
}
```
### <span id="ContainAll">ContainAll</span>
<p>判断集合是否包含另一个集合</p>
<b>函数签名:</b>
@@ -291,6 +291,7 @@ func main() {
```go
func (s Set[T]) ContainAll(other Set[T]) bool
```
<b>示例:</b>
```go
@@ -303,17 +304,16 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
set2 := set.NewSet(1, 2)
set3 := set.NewSet(1, 2, 3, 4)
fmt.Println(set1.ContainAll(set2)) //true
fmt.Println(set1.ContainAll(set3)) //false
}
```
### <span id="Size">Size</span>
<p>获取集合中元素的个数</p>
<b>函数签名:</b>
@@ -321,6 +321,7 @@ func main() {
```go
func (s Set[T]) Size() int
```
<b>示例:</b>
```go
@@ -338,9 +339,8 @@ func main() {
}
```
### <span id="Clone">Clone</span>
<p>克隆一个集合</p>
<b>函数签名:</b>
@@ -348,6 +348,7 @@ func main() {
```go
func (s Set[T]) Clone() Set[T]
```
<b>示例:</b>
```go
@@ -367,10 +368,8 @@ func main() {
}
```
### <span id="Equal">Equal</span>
<p>比较两个集合是否相等,包含相同元素为相等</p>
<b>函数签名:</b>
@@ -378,6 +377,7 @@ func main() {
```go
func (s Set[T]) Equal(other Set[T]) bool
```
<b>示例:</b>
```go
@@ -398,9 +398,8 @@ func main() {
}
```
### <span id="Iterate">Iterate</span>
<p>迭代结合,在每个元素上调用函数</p>
<b>函数签名:</b>
@@ -408,6 +407,7 @@ func main() {
```go
func (s Set[T]) Iterate(fn func(item T))
```
<b>示例:</b>
```go
@@ -429,9 +429,45 @@ func main() {
}
```
### <span id="EachWithBreak">EachWithBreak</span>
<p>遍历集合的元素并为每个元素调用iteratee函数当iteratee函数返回false时终止遍历。</p>
<b>函数签名:</b>
```go
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet(1, 2, 3, 4, 5)
var sum int
s.EachWithBreak(func(n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum) //6
}
```
### <span id="IsEmpty">IsEmpty</span>
<p>判断集合是否为空</p>
<b>函数签名:</b>
@@ -439,6 +475,7 @@ func main() {
```go
func (s Set[T]) IsEmpty() bool
```
<b>示例:</b>
```go
@@ -458,9 +495,8 @@ func main() {
}
```
### <span id="Union">Union</span>
<p>求两个集合的并集</p>
<b>函数签名:</b>
@@ -468,6 +504,7 @@ func main() {
```go
func (s Set[T]) Union(other Set[T]) Set[T]
```
<b>示例:</b>
```go
@@ -487,9 +524,8 @@ func main() {
}
```
### <span id="Intersection">Intersection</span>
<p>求两个集合的交集</p>
<b>函数签名:</b>
@@ -497,6 +533,7 @@ func main() {
```go
func (s Set[T]) Intersection(other Set[T]) Set[T]
```
<b>示例:</b>
```go
@@ -516,8 +553,8 @@ func main() {
}
```
### <span id="SymmetricDifference">SymmetricDifference</span>
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
<b>函数签名:</b>
@@ -525,6 +562,7 @@ func main() {
```go
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
```
<b>示例:</b>
```go
@@ -537,18 +575,15 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set1.SymmetricDifference(set2)
fmt.Println(set3.Values()) //1,4,5
}
```
### <span id="Minus">Minus</span>
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
<b>函数签名:</b>
@@ -556,6 +591,7 @@ func main() {
```go
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
```
<b>示例:</b>
```go
@@ -568,8 +604,8 @@ import (
func main() {
set1 := set.NewSet(1, 2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
set2 := set.NewSet(2, 3, 4, 5)
set3 := set.NewSet(2, 3)
res1 := set1.Minus(set2)
fmt.Println(res1.Values()) //1
@@ -579,5 +615,35 @@ func main() {
}
```
### <span id="Pop">Pop</span>
<p>删除并返回集合中的顶部元素</p>
<b>函数签名:</b>
```go
func (s Set[T]) Pop() (v T, ok bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
set "github.com/duke-git/lancet/v2/datastructure/set"
)
func main() {
s := set.NewSet[int]()
s.Add(1)
s.Add(2)
s.Add(3)
val, ok = s.Pop()
fmt.Println(val) // 3
fmt.Println(ok) // true
}
```

View File

@@ -34,6 +34,12 @@ import (
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [Range](#Range)
- [RangeWithStep](#RangeWithStep)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
<div STYLE="page-break-after: always;"></div>
@@ -476,3 +482,224 @@ func main() {
// 0.125
}
```
### <span id="Range">Range</span>
<p>Creates a slice of numbers from start with specified count, element step is 1.</p>
<b>Signature:</b>
```go
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Range(1, 4)
result2 := mathutil.Range(1, -4)
result3 := mathutil.Range(-4, 4)
result4 := mathutil.Range(1.0, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [-4 -3 -2 -1]
// [1 2 3 4]
}
```
### <span id="RangeWithStep">RangeWithStep</span>
<p>Creates a slice of numbers from start to end with specified step.</p>
<b>Signature:</b>
```go
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RangeWithStep(1, 4, 1)
result2 := mathutil.RangeWithStep(1, -1, 0)
result3 := mathutil.RangeWithStep(-4, 1, 2)
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3]
// []
// [-4 -2 0]
// [1 2.1 3.2]
}
```
### <span id="AngleToRadian">AngleToRadian</span>
<p>Converts angle value to radian value.</p>
<b>Signature:</b>
```go
func AngleToRadian(angle float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.AngleToRadian(45)
result2 := mathutil.AngleToRadian(90)
result3 := mathutil.AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
```
### <span id="RadianToAngle">RadianToAngle</span>
<p>Converts radian value to angle value.</p>
<b>Signature:</b>
```go
func RadianToAngle(radian float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RadianToAngle(math.Pi)
result2 := mathutil.RadianToAngle(math.Pi / 2)
result3 := mathutil.RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
```
### <span id="PointDistance">PointDistance</span>
<p>Caculates two points distance.</p>
<b>Signature:</b>
```go
func PointDistance(x1, y1, x2, y2 float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
```
### <span id="IsPrime">IsPrime</span>
<p>Checks if number is prime number.</p>
<b>Signature:</b>
```go
func IsPrime(n int) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
```

View File

@@ -34,6 +34,12 @@ import (
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [Range](#Range)
- [RangeWithStep](#RangeWithStep)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
<div STYLE="page-break-after: always;"></div>
@@ -476,3 +482,223 @@ func main() {
// 0.125
}
```
### <span id="Range">Range</span>
<p>根据指定的起始值和数量,创建一个数字切片。</p>
<b>函数签名:</b>
```go
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.Range(1, 4)
result2 := mathutil.Range(1, -4)
result3 := mathutil.Range(-4, 4)
result4 := mathutil.Range(1.0, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [-4 -3 -2 -1]
// [1 2 3 4]
}
```
### <span id="RangeWithStep">RangeWithStep</span>
<p>根据指定的起始值,结束值,步长,创建一个数字切片。</p>
<b>函数签名:</b>
```go
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RangeWithStep(1, 4, 1)
result2 := mathutil.RangeWithStep(1, -1, 0)
result3 := mathutil.RangeWithStep(-4, 1, 2)
result4 := mathutil.RangeWithStep(1.0, 4.0, 1.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3]
// []
// [-4 -2 0]
// [1 2.1 3.2]
}
```
### <span id="AngleToRadian">AngleToRadian</span>
<p>将角度值转为弧度值</p>
<b>函数签名:</b>
```go
func AngleToRadian(angle float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.AngleToRadian(45)
result2 := mathutil.AngleToRadian(90)
result3 := mathutil.AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
```
### <span id="RadianToAngle">RadianToAngle</span>
<p>将弧度值转为角度值</p>
<b>函数签名:</b>
```go
func RadianToAngle(radian float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.RadianToAngle(math.Pi)
result2 := mathutil.RadianToAngle(math.Pi / 2)
result3 := mathutil.RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
```
### <span id="PointDistance">PointDistance</span>
<p>计算两个坐标点的距离</p>
<b>函数签名:</b>
```go
func PointDistance(x1, y1, x2, y2 float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
```
### <span id="IsPrime">IsPrime</span>
<p>判断质数。</p>
<b>函数签名:</b>
```go
func IsPrime(n int) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}

View File

@@ -590,21 +590,29 @@ import (
func main() {
type TodoQuery struct {
Id int `json:"id"`
Name string `json:"name"`
Id int `json:"id"`
UserId int `json:"userId"`
Name string `json:"name,omitempty"`
Status string
}
todoQuery := TodoQuery{
Id: 1,
Name: "Test",
item := TodoQuery{
Id: 1,
UserId: 123,
Name: "test",
Status: "completed",
}
todoValues := netutil.StructToUrlValues(todoQuery)
queryValues := netutil.StructToUrlValues(item)
fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("userId"))
fmt.Println(todoValues.Get("name"))
fmt.Println(todoValues.Get("status"))
// Output:
// 1
// Test
// 123
// test
//
}
```

View File

@@ -592,21 +592,29 @@ import (
func main() {
type TodoQuery struct {
Id int `json:"id"`
Name string `json:"name"`
Id int `json:"id"`
UserId int `json:"userId"`
Name string `json:"name,omitempty"`
Status string
}
todoQuery := TodoQuery{
Id: 1,
Name: "Test",
item := TodoQuery{
Id: 1,
UserId: 123,
Name: "test",
Status: "completed",
}
todoValues := netutil.StructToUrlValues(todoQuery)
queryValues := netutil.StructToUrlValues(item)
fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("userId"))
fmt.Println(todoValues.Get("name"))
fmt.Println(todoValues.Get("status"))
// Output:
// 1
// Test
// 123
// test
//
}
```

View File

@@ -48,6 +48,7 @@ import (
- [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [ForEachWithBreak](#ForEachWithBreak)
- [GroupBy](#GroupBy)
- [GroupWith](#GroupWith)
- [IntSlice<sup>deprecated</sup>](#IntSlice)
@@ -172,28 +173,28 @@ import (
func main() {
type foo struct {
A string
B int
}
A string
B int
}
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array2 := []string{"a", "b", "c"}
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
array2 := []string{"a", "b", "c"}
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// false
// true
// false
// Output:
// true
// false
// true
// false
}
```
@@ -560,20 +561,20 @@ import (
func main() {
result1 := slice.Drop([]string{"a", "b", "c"}, 0)
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [b c]
// [a b c]
// []
// Output:
// [a b c]
// [b c]
// [a b c]
// []
}
```
@@ -597,20 +598,20 @@ import (
func main() {
result1 := slice.DropRight([]string{"a", "b", "c"}, 0)
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [a b]
// [a b c]
// []
// Output:
// [a b c]
// [a b]
// [a b c]
// []
}
```
@@ -634,23 +635,23 @@ import (
func main() {
result1 := slice.DropWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropWhile(numbers, func(n int) bool {
return n == 0
})
return n != 2
})
result2 := slice.DropWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [2 3 4 5]
// []
// [1 2 3 4 5]
// Output:
// [2 3 4 5]
// []
// [1 2 3 4 5]
}
```
@@ -675,24 +676,24 @@ import (
func main() {
numbers := []int{1, 2, 3, 4, 5}
result1 := slice.DropRightWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropRightWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropRightWhile(numbers, func(n int) bool {
return n == 0
})
result1 := slice.DropRightWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropRightWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropRightWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [1 2]
// []
// [1 2 3 4 5]
// Output:
// [1 2]
// []
// [1 2 3 4 5]
}
```
@@ -1001,6 +1002,44 @@ func main() {
}
```
### <span id="ForEachWithBreak">ForEachWithBreak</span>
<p>Iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.</p>
<b>Signature:</b>
```go
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
var sum int
slice.ForEachWithBreak(numbers, func(_, n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum)
// Output:
// 6
}
```
### <span id="GroupBy">GroupBy</span>
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
@@ -1321,19 +1360,19 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
result := slice.FilterMap(nums, getEvenNumStr)
result := slice.FilterMap(nums, getEvenNumStr)
fmt.Printf("%#v", result)
fmt.Printf("%#v", result)
// Output:
// []string{"2", "4"}
// Output:
// []string{"2", "4"}
}
```
@@ -1358,15 +1397,15 @@ import (
func main() {
nums := []int{1, 2, 3, 4}
result := slice.FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
result := slice.FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
fmt.Printf("%#v", result)
fmt.Printf("%#v", result)
// Output:
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
// Output:
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
}
```
@@ -1612,17 +1651,17 @@ import (
func main() {
result1 := slice.IsAscending([]int{1, 2, 3, 4, 5})
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
// Output:
// true
// false
// false
}
```
@@ -1646,17 +1685,17 @@ import (
func main() {
result1 := slice.IsDescending([]int{5, 4, 3, 2, 1})
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
// Output:
// true
// false
// false
}
```
@@ -1680,17 +1719,17 @@ import (
func main() {
result1 := slice.IsSorted([]int{5, 4, 3, 2, 1})
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
// Output:
// true
// true
// false
}
```
@@ -1714,23 +1753,23 @@ import (
func main() {
result1 := slice.IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
return len(s)
})
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
})
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
})
return len(s)
})
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
})
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
// Output:
// true
// true
// false
}
```

View File

@@ -48,6 +48,7 @@ import (
- [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [ForEachWithBreak](#ForEachWithBreak)
- [GroupBy](#GroupBy)
- [GroupWith](#GroupWith)
- [IntSlice<sup>deprecated</sup>](#IntSlice)
@@ -172,28 +173,28 @@ import (
func main() {
type foo struct {
A string
B int
}
A string
B int
}
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array1 := []foo{{A: "1", B: 1}, {A: "2", B: 2}}
result1 := slice.ContainBy(array1, func(f foo) bool { return f.A == "1" && f.B == 1 })
result2 := slice.ContainBy(array1, func(f foo) bool { return f.A == "2" && f.B == 1 })
array2 := []string{"a", "b", "c"}
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
array2 := []string{"a", "b", "c"}
result3 := slice.ContainBy(array2, func(t string) bool { return t == "a" })
result4 := slice.ContainBy(array2, func(t string) bool { return t == "d" })
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// false
// true
// false
// Output:
// true
// false
// true
// false
}
```
@@ -541,7 +542,6 @@ func main() {
}
```
### <span id="Drop">Drop</span>
<p>从切片的头部删除n个元素。</p>
@@ -562,20 +562,20 @@ import (
func main() {
result1 := slice.Drop([]string{"a", "b", "c"}, 0)
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
result2 := slice.Drop([]string{"a", "b", "c"}, 1)
result3 := slice.Drop([]string{"a", "b", "c"}, -1)
result4 := slice.Drop([]string{"a", "b", "c"}, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [b c]
// [a b c]
// []
// Output:
// [a b c]
// [b c]
// [a b c]
// []
}
```
@@ -599,20 +599,20 @@ import (
func main() {
result1 := slice.DropRight([]string{"a", "b", "c"}, 0)
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
result2 := slice.DropRight([]string{"a", "b", "c"}, 1)
result3 := slice.DropRight([]string{"a", "b", "c"}, -1)
result4 := slice.DropRight([]string{"a", "b", "c"}, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [a b c]
// [a b]
// [a b c]
// []
// Output:
// [a b c]
// [a b]
// [a b c]
// []
}
```
@@ -636,23 +636,23 @@ import (
func main() {
result1 := slice.DropWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropWhile(numbers, func(n int) bool {
return n == 0
})
return n != 2
})
result2 := slice.DropWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [2 3 4 5]
// []
// [1 2 3 4 5]
// Output:
// [2 3 4 5]
// []
// [1 2 3 4 5]
}
```
@@ -677,24 +677,24 @@ import (
func main() {
numbers := []int{1, 2, 3, 4, 5}
result1 := slice.DropRightWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropRightWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropRightWhile(numbers, func(n int) bool {
return n == 0
})
result1 := slice.DropRightWhile(numbers, func(n int) bool {
return n != 2
})
result2 := slice.DropRightWhile(numbers, func(n int) bool {
return true
})
result3 := slice.DropRightWhile(numbers, func(n int) bool {
return n == 0
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// [1 2]
// []
// [1 2 3 4 5]
// Output:
// [1 2]
// []
// [1 2 3 4 5]
}
```
@@ -1003,6 +1003,44 @@ func main() {
}
```
### <span id="ForEachWithBreak">ForEachWithBreak</span>
<p>遍历切片的元素并为每个元素调用iteratee函数当iteratee函数返回false时终止遍历。</p>
<b>函数签名:</b>
```go
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
var sum int
slice.ForEachWithBreak(numbers, func(_, n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum)
// Output:
// 6
}
```
### <span id="GroupBy">GroupBy</span>
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
@@ -1323,19 +1361,19 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
getEvenNumStr := func(i, num int) (string, bool) {
if num%2 == 0 {
return strconv.FormatInt(int64(num), 10), true
}
return "", false
}
result := slice.FilterMap(nums, getEvenNumStr)
result := slice.FilterMap(nums, getEvenNumStr)
fmt.Printf("%#v", result)
fmt.Printf("%#v", result)
// Output:
// []string{"2", "4"}
// Output:
// []string{"2", "4"}
}
```
@@ -1360,15 +1398,15 @@ import (
func main() {
nums := []int{1, 2, 3, 4}
result := slice.FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
result := slice.FlatMap(nums, func(i int, num int) []string {
s := "hi-" + strconv.FormatInt(int64(num), 10)
return []string{s}
})
fmt.Printf("%#v", result)
fmt.Printf("%#v", result)
// Output:
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
// Output:
// []string{"hi-1", "hi-2", "hi-3", "hi-4"}
}
```
@@ -1587,8 +1625,8 @@ func main() {
nums := []int{1, 2, 3, 4, 5}
result := slice.Shuffle(nums)
fmt.Println(res)
fmt.Println(res)
// Output:
// [3 1 5 4 2] (random order)
}
@@ -1614,17 +1652,17 @@ import (
func main() {
result1 := slice.IsAscending([]int{1, 2, 3, 4, 5})
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
result2 := slice.IsAscending([]int{5, 4, 3, 2, 1})
result3 := slice.IsAscending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
// Output:
// true
// false
// false
}
```
@@ -1648,17 +1686,17 @@ import (
func main() {
result1 := slice.IsDescending([]int{5, 4, 3, 2, 1})
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
result2 := slice.IsDescending([]int{1, 2, 3, 4, 5})
result3 := slice.IsDescending([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// false
// false
// Output:
// true
// false
// false
}
```
@@ -1682,17 +1720,17 @@ import (
func main() {
result1 := slice.IsSorted([]int{5, 4, 3, 2, 1})
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
result2 := slice.IsSorted([]int{1, 2, 3, 4, 5})
result3 := slice.IsSorted([]int{2, 1, 3, 4, 5})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
// Output:
// true
// true
// false
}
```
@@ -1716,23 +1754,23 @@ import (
func main() {
result1 := slice.IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
return len(s)
})
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
})
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
})
return len(s)
})
result2 := slice.IsSortedByKey([]string{"abc", "ab", "a"}, func(s string) int {
return len(s)
})
result3 := slice.IsSortedByKey([]string{"abc", "a", "ab"}, func(s string) int {
return len(s)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
// Output:
// true
// true
// false
}
```

353
docs/structs/field.md Normal file
View 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)
> NoteSince `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
View 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
View 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
}
```

View 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
}
```

View File

@@ -45,6 +45,7 @@ import (
- [Unwrap](#Unwrap)
- [SplitWords](#SplitWords)
- [WordCount](#WordCount)
- [RemoveNonPrintable](#RemoveNonPrintable)
<div STYLE="page-break-after: always;"></div>
@@ -937,4 +938,35 @@ func main() {
// 0
// 0
}
```
### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
<p>Remove non-printable characters from a string.</p>
<b>Signature:</b>
```go
func RemoveNonPrintable(str string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.RemoveNonPrintable("hello\u00a0 \u200bworld\n")
result2 := strutil.RemoveNonPrintable("你好😄")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// hello world
// 你好😄
}
```

View File

@@ -45,6 +45,7 @@ import (
- [Unwrap](#Unwrap)
- [SplitWords](#SplitWords)
- [WordCount](#WordCount)
- [RemoveNonPrintable](#RemoveNonPrintable)
<div STYLE="page-break-after: always;"></div>
@@ -936,4 +937,35 @@ func main() {
// 0
// 0
}
```
### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
<p>删除字符串中不可打印的字符。</p>
<b>函数签名:</b>
```go
func RemoveNonPrintable(str string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.RemoveNonPrintable("hello\u00a0 \u200bworld\n")
result2 := strutil.RemoveNonPrintable("你好😄")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// hello world
// 你好😄
}
```

View File

@@ -29,6 +29,7 @@ import (
- [IsAlpha](#IsAlpha)
- [IsAllUpper](#IsAllUpper)
- [IsAllLower](#IsAllLower)
- [IsASCII](#IsASCII)
- [IsBase64](#IsBase64)
- [IsChineseMobile](#IsChineseMobile)
- [IsChineseIdNum](#IsChineseIdNum)
@@ -50,6 +51,7 @@ import (
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
- [IsPrintable](#IsPrintable)
<div STYLE="page-break-after: always;"></div>
@@ -293,6 +295,46 @@ func main() {
}
```
### <span id="IsASCII">IsASCII</span>
<p>Checks if string is all ASCII char.</p>
<b>Signature:</b>
```go
func IsASCII(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsASCII("ABC")
result2 := validator.IsASCII("123")
result3 := validator.IsASCII("")
result4 := validator.IsASCII("😄")
result5 := validator.IsASCII("你好")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// false
// false
}
```
### <span id="IsBase64">IsBase64</span>
<p>Check if the string is base64 string.</p>
@@ -990,3 +1032,44 @@ func main() {
// true
}
```
### <span id="IsPrintable">IsPrintable</span>
<p>Checks if string is all printable chars.</p>
<b>Signature:</b>
```go
func IsPrintable(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsPrintable("ABC")
result2 := validator.IsPrintable("{id: 123}")
result3 := validator.IsPrintable("")
result4 := validator.IsPrintable("😄")
result5 := validator.IsPrintable("\u0000")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// true
// false
}
```

View File

@@ -29,6 +29,7 @@ import (
- [IsAlpha](#IsAlpha)
- [IsAllUpper](#IsAllUpper)
- [IsAllLower](#IsAllLower)
- [IsASCII](#IsASCII)
- [IsBase64](#IsBase64)
- [IsChineseMobile](#IsChineseMobile)
- [IsChineseIdNum](#IsChineseIdNum)
@@ -50,6 +51,7 @@ import (
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
- [IsPrintable](#IsPrintable)
<div STYLE="page-break-after: always;"></div>
@@ -293,6 +295,46 @@ func main() {
}
```
### <span id="IsASCII">IsASCII</span>
<p>验证字符串全部为ASCII字符。</p>
<b>函数签名:</b>
```go
func IsASCII(str string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsASCII("ABC")
result2 := validator.IsASCII("123")
result3 := validator.IsASCII("")
result4 := validator.IsASCII("😄")
result5 := validator.IsASCII("你好")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// false
// false
}
```
### <span id="IsBase64">IsBase64</span>
<p>验证字符串是否是base64编码</p>
@@ -990,3 +1032,44 @@ func main() {
// true
}
```
### <span id="IsPrintable">IsPrintable</span>
<p>检查字符串是否全部为可打印字符。</p>
<b>函数签名:</b>
```go
func IsPrintable(str string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
result1 := validator.IsPrintable("ABC")
result2 := validator.IsPrintable("{id: 123}")
result3 := validator.IsPrintable("")
result4 := validator.IsPrintable("😄")
result5 := validator.IsPrintable("\u0000")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// true
// false
}
```

View File

@@ -79,16 +79,18 @@ func (a *Assert) LessOrEqual(expected, actual any) {
}
// IsNil check if value is nil
func (a *Assert) IsNil(value any) {
if value != nil {
makeTestFailed(a.T, a.CaseName, nil, value)
func (a *Assert) IsNil(v any) {
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
return
}
makeTestFailed(a.T, a.CaseName, nil, v)
}
// IsNotNil check if value is not nil
func (a *Assert) IsNotNil(value any) {
if value == nil {
makeTestFailed(a.T, a.CaseName, "not nil", value)
func (a *Assert) IsNotNil(v any) {
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
makeTestFailed(a.T, a.CaseName, "not nil", v)
}
}

51
internal/error_join.go Normal file
View File

@@ -0,0 +1,51 @@
package internal
// Note: this file is copyed from the go standart repo (https://github.com/golang/go/blob/master/src/errors/join.go).
// just in order to adapt under go1.9
// do not use it outside lancet lib.
// Join returns an error that wraps the given errors.
// Any nil error values are discarded.
// Join returns nil if errs contains no non-nil values.
// The error formats as the concatenation of the strings obtained
// by calling the Error method of each element of errs, with a newline
// between each string.
func JoinError(errs ...error) error {
n := 0
for _, err := range errs {
if err != nil {
n++
}
}
if n == 0 {
return nil
}
e := &joinError{
errs: make([]error, 0, n),
}
for _, err := range errs {
if err != nil {
e.errs = append(e.errs, err)
}
}
return e
}
type joinError struct {
errs []error
}
func (e *joinError) Error() string {
var b []byte
for i, err := range e.errs {
if i > 0 {
b = append(b, '\n')
}
b = append(b, err.Error()...)
}
return string(b)
}
func (e *joinError) Unwrap() []error {
return e.errs
}

View File

@@ -39,7 +39,7 @@ func Values[K comparable, V any](m map[K]V) []V {
}
// KeysBy creates a slice whose element is the result of function mapper invoked by every map's key.
// Play: todo
// Play: https://go.dev/play/p/hI371iB8Up8
func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
keys := make([]T, 0, len(m))
@@ -51,7 +51,7 @@ func KeysBy[K comparable, V any, T any](m map[K]V, mapper func(item K) T) []T {
}
// ValuesBy creates a slice whose element is the result of function mapper invoked by every map's value.
// Play: todo
// Play: https://go.dev/play/p/sg9-oRidh8f
func ValuesBy[K comparable, V any, T any](m map[K]V, mapper func(item V) T) []T {
keys := make([]T, 0, len(m))
@@ -98,7 +98,7 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
}
// FilterByKeys iterates over map, return a new map whose keys are all given keys.
// Play: todo
// Play: https://go.dev/play/p/7ov6BJHbVqh
func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
result := make(map[K]V)
@@ -111,7 +111,7 @@ func FilterByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
}
// FilterByValues iterates over map, return a new map whose values are all given values.
// Play: todo
// Play: https://go.dev/play/p/P3-9MdcXegR
func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
result := make(map[K]V)
@@ -124,7 +124,7 @@ func FilterByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
}
// OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.
// Play: todo
// Play: https://go.dev/play/p/YJM4Hj5hNwm
func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
result := make(map[K]V)
@@ -137,7 +137,7 @@ func OmitBy[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
}
// OmitByKeys the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
// Play: todo
// Play: https://go.dev/play/p/jXGrWDBfSRp
func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
result := make(map[K]V)
@@ -150,7 +150,7 @@ func OmitByKeys[K comparable, V any](m map[K]V, keys []K) map[K]V {
}
// OmitByValues the opposite of FilterByValues. remov all elements whose value are in the give slice.
// Play: todo
// Play: https://go.dev/play/p/XB7Y10uw20_U
func OmitByValues[K comparable, V comparable](m map[K]V, values []V) map[K]V {
result := make(map[K]V)
@@ -227,7 +227,7 @@ type Entry[K comparable, V any] struct {
}
// Entries transforms a map into array of key/value pairs.
// Play: todo
// Play: https://go.dev/play/p/Ltb11LNcElY
func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
entries := make([]Entry[K, V], 0, len(m))
@@ -242,7 +242,7 @@ func Entries[K comparable, V any](m map[K]V) []Entry[K, V] {
}
// FromEntries creates a map based on a slice of key/value pairs
// Play: todo
// Play: https://go.dev/play/p/fTdu4sCNjQO
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
result := make(map[K]V, len(entries))
@@ -254,7 +254,7 @@ func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
}
// Transform a map to another type map.
// Play: todo
// Play: https://go.dev/play/p/P6ovfToM3zj
func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
result := make(map[K2]V2, len(m))
@@ -267,7 +267,7 @@ func Transform[K1 comparable, V1 any, K2 comparable, V2 any](m map[K1]V1, iterat
}
// MapKeys transforms a map to other type map by manipulating it's keys.
// Play: todo
// Play: https://go.dev/play/p/8scDxWeBDKd
func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K, value V) T) map[T]V {
result := make(map[T]V, len(m))
@@ -279,7 +279,7 @@ func MapKeys[K comparable, V any, T comparable](m map[K]V, iteratee func(key K,
}
// MapValues transforms a map to other type map by manipulating it's values.
// Play: todo
// Play: https://go.dev/play/p/g92aY3fc7Iw
func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value V) T) map[K]T {
result := make(map[K]T, len(m))

View File

@@ -183,3 +183,76 @@ func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
}
return sum / n
}
// Range creates a slice of numbers from start with specified count, element step is 1.
// Play: https://go.dev/play/p/9ke2opxa8ZP
func Range[T constraints.Integer | constraints.Float](start T, count int) []T {
size := count
if count < 0 {
size = -count
}
result := make([]T, size)
for i, j := 0, start; i < size; i, j = i+1, j+1 {
result[i] = j
}
return result
}
// RangeWithStep creates a slice of numbers from start to end with specified step.
// Play: https://go.dev/play/p/akLWz0EqOSM
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T {
result := []T{}
if start >= end || step == 0 {
return result
}
for i := start; i < end; i += step {
result = append(result, i)
}
return result
}
// AngleToRadian converts angle value to radian value.
// Play: todo
func AngleToRadian(angle float64) float64 {
radian := angle * (math.Pi / 180)
return radian
}
// RadianToAngle converts radian value to angle value.
// Play: todo
func RadianToAngle(radian float64) float64 {
angle := radian * (180 / math.Pi)
return angle
}
// PointDistance get two points distance.
// Play: todo
func PointDistance(x1, y1, x2, y2 float64) float64 {
a := x1 - x2
b := y1 - y2
c := math.Pow(a, 2) + math.Pow(b, 2)
return math.Sqrt(c)
}
// IsPrimes checks if number is prime number.
// Play: todo
func IsPrime(n int) bool {
if n < 2 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
if n%i == 0 {
return false
}
}
return true
}

View File

@@ -1,6 +1,9 @@
package mathutil
import "fmt"
import (
"fmt"
"math"
)
func ExampleExponent() {
result1 := Exponent(10, 0)
@@ -185,3 +188,96 @@ func ExampleMinBy() {
// ab
//
}
func ExampleRange() {
result1 := Range(1, 4)
result2 := Range(1, -4)
result3 := Range(-4, 4)
result4 := Range(1.0, 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [-4 -3 -2 -1]
// [1 2 3 4]
}
func ExampleRangeWithStep() {
result1 := RangeWithStep(1, 4, 1)
result2 := RangeWithStep(1, -1, 0)
result3 := RangeWithStep(-4, 1, 2)
result4 := RangeWithStep(1.0, 4.0, 1.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// [1 2 3]
// []
// [-4 -2 0]
// [1 2.1 3.2]
}
func ExampleAngleToRadian() {
result1 := AngleToRadian(45)
result2 := AngleToRadian(90)
result3 := AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
func ExampleRadianToAngle() {
result1 := RadianToAngle(math.Pi)
result2 := RadianToAngle(math.Pi / 2)
result3 := RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
func ExamplePointDistance() {
result1 := PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
func ExampleIsPrime() {
result1 := IsPrime(-1)
result2 := IsPrime(0)
result3 := IsPrime(1)
result4 := IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}

View File

@@ -1,6 +1,7 @@
package mathutil
import (
"math"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -137,3 +138,76 @@ func TestMinBy(t *testing.T) {
})
assert.Equal("", res3)
}
func TestRange(t *testing.T) {
assert := internal.NewAssert(t, "TestRange")
result1 := Range(1, 4)
result2 := Range(1, -4)
result3 := Range(-4, 4)
result4 := Range(1.0, 4)
result5 := Range(1, 0)
assert.Equal([]int{1, 2, 3, 4}, result1)
assert.Equal([]int{1, 2, 3, 4}, result2)
assert.Equal([]int{-4, -3, -2, -1}, result3)
assert.Equal([]float64{1.0, 2.0, 3.0, 4.0}, result4)
assert.Equal([]int{}, result5)
}
func TestRangeWithStep(t *testing.T) {
assert := internal.NewAssert(t, "TestRangeWithStep")
result1 := RangeWithStep(1, 4, 1)
result2 := RangeWithStep(1, -1, 0)
result3 := RangeWithStep(-4, 1, 2)
result4 := RangeWithStep(1.0, 4.0, 1.1)
assert.Equal([]int{1, 2, 3}, result1)
assert.Equal([]int{}, result2)
assert.Equal([]int{-4, -2, 0}, result3)
assert.Equal([]float64{1.0, 2.1, 3.2}, result4)
}
func TestAngleToRadian(t *testing.T) {
assert := internal.NewAssert(t, "TestAngleToRadian")
result1 := AngleToRadian(45)
result2 := AngleToRadian(90)
result3 := AngleToRadian(180)
assert.Equal(0.7853981633974483, result1)
assert.Equal(1.5707963267948966, result2)
assert.Equal(3.141592653589793, result3)
}
func TestRadianToAngle(t *testing.T) {
assert := internal.NewAssert(t, "TestAngleToRadian")
result1 := RadianToAngle(math.Pi)
result2 := RadianToAngle(math.Pi / 2)
result3 := RadianToAngle(math.Pi / 4)
assert.Equal(float64(180), result1)
assert.Equal(float64(90), result2)
assert.Equal(float64(45), result3)
}
func TestPointDistance(t *testing.T) {
assert := internal.NewAssert(t, "TestPointDistance")
result1 := PointDistance(1, 1, 4, 5)
assert.Equal(float64(5), result1)
}
func TestIsPrime(t *testing.T) {
assert := internal.NewAssert(t, "TestIsPrime")
assert.Equal(false, IsPrime(-1))
assert.Equal(false, IsPrime(0))
assert.Equal(false, IsPrime(1))
assert.Equal(true, IsPrime(2))
assert.Equal(true, IsPrime(3))
assert.Equal(false, IsPrime(4))
}

View File

@@ -21,12 +21,11 @@ import (
"io"
"net/http"
"net/url"
"reflect"
"regexp"
"sort"
"strings"
"time"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/slice"
)
@@ -219,7 +218,7 @@ func (client *HttpClient) setTLS(rawUrl string) {
}
}
// setHeader set http rquest header
// setHeader set http request header
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
if headers == nil {
headers = make(http.Header)
@@ -278,29 +277,15 @@ func validateRequest(req *HttpRequest) error {
// StructToUrlValues convert struct to url valuse,
// only convert the field which is exported and has `json` tag.
// Play: https://go.dev/play/p/pFqMkM40w9z
func StructToUrlValues(targetStruct any) url.Values {
rv := reflect.ValueOf(targetStruct)
rt := reflect.TypeOf(targetStruct)
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
}
func StructToUrlValues(targetStruct any) (url.Values, error) {
result := url.Values{}
fieldNum := rt.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := rt.Field(i).Name
tag := rt.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
}
s, err := convertor.StructToMap(targetStruct)
if err != nil {
return nil, err
}
for k, v := range s {
result.Add(k, fmt.Sprintf("%v", v))
}
return result
return result, nil
}

View File

@@ -217,30 +217,31 @@ func TestStructToUrlValues(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToUrlValues")
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
Id int `json:"id"`
UserId int `json:"userId"`
Name string `json:"name,omitempty"`
}
todoQuery := TodoQuery{
item1 := TodoQuery{
Id: 1,
UserId: 1,
UserId: 123,
Name: "",
}
todoValues, err := StructToUrlValues(item1)
if err != nil {
t.Errorf("params is invalid: %v", err)
}
todoValues := StructToUrlValues(todoQuery)
assert.Equal("1", todoValues.Get("id"))
assert.Equal("1", todoValues.Get("userId"))
assert.Equal("123", todoValues.Get("userId"))
assert.Equal("", todoValues.Get("name"))
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "GET",
QueryParams: todoValues,
item2 := TodoQuery{
Id: 2,
UserId: 456,
}
queryValues2, _ := StructToUrlValues(item2)
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", string(body))
assert.Equal("2", queryValues2.Get("id"))
assert.Equal("456", queryValues2.Get("userId"))
assert.Equal("", queryValues2.Get("name"))
}

View File

@@ -123,21 +123,45 @@ func ExampleHttpClient_DecodeResponse() {
func ExampleStructToUrlValues() {
type TodoQuery struct {
Id int `json:"id"`
Name string `json:"name"`
Id int `json:"id"`
UserId int `json:"userId"`
Name string `json:"name,omitempty"`
Status string
}
todoQuery := TodoQuery{
Id: 1,
Name: "Test",
item1 := TodoQuery{
Id: 1,
UserId: 123,
Name: "test",
Status: "completed",
}
queryValues1, err := StructToUrlValues(item1)
if err != nil {
return
}
todoValues := StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id"))
fmt.Println(todoValues.Get("name"))
item2 := TodoQuery{
Id: 2,
UserId: 456,
}
queryValues2, _ := StructToUrlValues(item2)
fmt.Println(queryValues1.Get("id"))
fmt.Println(queryValues1.Get("userId"))
fmt.Println(queryValues1.Get("name"))
fmt.Println(queryValues1.Get("status"))
fmt.Println(queryValues2.Get("id"))
fmt.Println(queryValues2.Get("userId"))
fmt.Println(queryValues2.Get("name"))
// Output:
// 1
// Test
// 123
// test
//
// 2
// 456
//
}
func ExampleConvertMapToQueryString() {

14
pointer/pointer.go Normal file
View 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
View File

@@ -0,0 +1,18 @@
package pointer
import (
"github.com/duke-git/lancet/v2/internal"
"testing"
)
func TestExtractPointer(t *testing.T) {
assert := internal.NewAssert(t, "TestExtractPointer")
a := 1
b := &a
c := &b
d := &c
assert.Equal(1, ExtractPointer(d))
}

279
promise/promise.go Normal file
View File

@@ -0,0 +1,279 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package promise contains some functions to support async programming.
package promise
import (
"errors"
"fmt"
"sync"
"github.com/duke-git/lancet/v2/internal"
)
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
// ref : chebyrash/promise (https://github.com/chebyrash/promise)
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
type Promise[T any] struct {
runnable func(resolve func(T), reject func(error))
result T
err error
pending bool
mu *sync.Mutex
wg *sync.WaitGroup
}
// New create a new promise instance.
func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T] {
if runnable == nil {
panic("runnable function should not be nil")
}
p := &Promise[T]{
runnable: runnable,
pending: true,
mu: &sync.Mutex{},
wg: &sync.WaitGroup{},
}
defer p.run()
return p
}
func (p *Promise[T]) run() {
p.wg.Add(1)
go func() {
defer func() {
if !p.pending {
return
}
if err := recover(); err != nil {
p.reject(errors.New(fmt.Sprint(err)))
}
}()
p.runnable(p.resolve, p.reject)
}()
}
// Resolve returns a Promise that has been resolved with a given value.
func Resolve[T any](resolution T) *Promise[T] {
return &Promise[T]{
result: resolution,
pending: false,
mu: &sync.Mutex{},
wg: &sync.WaitGroup{},
}
}
func (p *Promise[T]) resolve(value T) {
p.mu.Lock()
defer p.mu.Unlock()
if !p.pending {
return
}
p.result = value
p.pending = false
p.wg.Done()
}
// Reject returns a Promise that has been rejected with a given error.
func Reject[T any](err error) *Promise[T] {
return &Promise[T]{
err: err,
pending: false,
mu: &sync.Mutex{},
wg: &sync.WaitGroup{},
}
}
func (p *Promise[T]) reject(err error) {
p.mu.Lock()
defer p.mu.Unlock()
if !p.pending {
return
}
p.err = err
p.pending = false
p.wg.Done()
}
// Then allows chain calls to other promise methods.
func Then[T1, T2 any](promise *Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
return New(func(resolve2 func(T2), reject func(error)) {
result, err := promise.Await()
if err != nil {
reject(err)
return
}
resolve2(resolve1(result))
})
}
// Then allows chain calls to other promise methods.
func (p *Promise[T]) Then(resolve func(value T) T) *Promise[T] {
return New(func(_resolve func(T), reject func(error)) {
result, err := p.Await()
if err != nil {
reject(err)
return
}
_resolve(resolve(result))
})
}
// Catch allows to chain promises.
func Catch[T any](promise *Promise[T], rejection func(err error) error) *Promise[T] {
return New(func(resolve func(T), reject func(error)) {
result, err := promise.Await()
if err != nil {
reject(rejection(err))
return
}
resolve(result)
})
}
// Catch chain an existing promise with an intermediate reject function.
func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] {
return New(func(resolve func(T), rej func(error)) {
resutl, err := p.Await()
if err != nil {
rej(reject(err))
return
}
resolve(resutl)
})
}
// Await blocks until the 'runable' to finish execution.
func (p *Promise[T]) Await() (T, error) {
p.wg.Wait()
return p.result, p.err
}
type tuple[T1, T2 any] struct {
_1 T1
_2 T2
}
// All resolves when all of the promises have resolved, reject immediately upon any of the input promises rejecting.
func All[T any](promises []*Promise[T]) *Promise[[]T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func([]T), reject func(error)) {
valsChan := make(chan tuple[T, int], len(promises))
errsChan := make(chan error, 1)
for idx, p := range promises {
idx := idx
_ = Then(p, func(data T) T {
valsChan <- tuple[T, int]{_1: data, _2: idx}
return data
})
_ = Catch(p, func(err error) error {
errsChan <- err
return err
})
}
resolutions := make([]T, len(promises))
for idx := 0; idx < len(promises); idx++ {
select {
case val := <-valsChan:
resolutions[val._2] = val._1
case err := <-errsChan:
reject(err)
return
}
}
resolve(resolutions)
})
}
// Race will settle the first fullfiled promise among muti promises.
func Race[T any](promises []*Promise[T]) *Promise[T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func(T), reject func(error)) {
valsChan := make(chan T, 1)
errsChan := make(chan error, 1)
for _, p := range promises {
_ = Then(p, func(data T) T {
valsChan <- data
return data
})
_ = Catch(p, func(err error) error {
errsChan <- err
return err
})
}
select {
case val := <-valsChan:
resolve(val)
case err := <-errsChan:
reject(err)
}
})
}
// Any resolves as soon as any of the input's Promises resolve, with the value of the resolved Promise.
// Any rejects if all of the given Promises are rejected with a combination of all errors.
func Any[T any](promises []*Promise[T]) *Promise[T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func(T), reject func(error)) {
valsChan := make(chan T, 1)
errsChan := make(chan tuple[error, int], len(promises))
for idx, p := range promises {
idx := idx
_ = Then(p, func(data T) T {
valsChan <- data
return data
})
_ = Catch(p, func(err error) error {
errsChan <- tuple[error, int]{_1: err, _2: idx}
return err
})
}
errs := make([]error, len(promises))
for idx := 0; idx < len(promises); idx++ {
select {
case val := <-valsChan:
resolve(val)
return
case err := <-errsChan:
errs[err._2] = err._1
}
}
errCombo := errs[0]
for _, err := range errs[1:] {
errCombo = internal.JoinError(err)
}
reject(errCombo)
})
}

View File

@@ -0,0 +1,195 @@
package promise
import (
"errors"
"fmt"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func ExampleNew() {
p := New(func(resolve func(string), reject func(error)) {
resolve("hello")
})
val, err := p.Await()
if err != nil {
return
}
fmt.Println(val)
// Output:
// hello
}
func ExampleThen() {
p1 := New(func(resolve func(string), reject func(error)) {
resolve("hello ")
})
p2 := Then(p1, func(s string) string {
return s + "world"
})
result, err := p2.Await()
if err != nil {
return
}
fmt.Println(result)
// Output:
// hello world
}
func ExamplePromise_Then() {
p1 := New(func(resolve func(string), reject func(error)) {
resolve("hello ")
})
p2 := p1.Then(func(s string) string {
return s + "world"
})
result, err := p2.Await()
if err != nil {
return
}
fmt.Println(result)
// Output:
// hello world
}
func ExampleCatch() {
p1 := New(func(resolve func(string), reject func(error)) {
err := errors.New("error1")
reject(err)
})
p2 := Catch(p1, func(err error) error {
e := errors.New("error2")
return internal.JoinError(err, e)
})
_, err := p1.Await()
fmt.Println(err.Error())
result2, err := p2.Await()
fmt.Println(result2)
fmt.Println(err.Error())
// Output:
// error1
//
// error1
// error2
}
func ExamplePromise_Catch() {
p1 := New(func(resolve func(string), reject func(error)) {
err := errors.New("error1")
reject(err)
})
p2 := p1.Catch(func(err error) error {
e := errors.New("error2")
return internal.JoinError(err, e)
})
_, err := p1.Await()
fmt.Println(err.Error())
result2, err := p2.Await()
fmt.Println(result2)
fmt.Println(err.Error())
// Output:
// error1
//
// error1
// error2
}
func ExampleAll() {
p1 := New(func(resolve func(string), reject func(error)) {
resolve("a")
})
p2 := New(func(resolve func(string), reject func(error)) {
resolve("b")
})
p3 := New(func(resolve func(string), reject func(error)) {
resolve("c")
})
pms := []*Promise[string]{p1, p2, p3}
p := All(pms)
result, err := p.Await()
if err != nil {
return
}
fmt.Println(result)
// Output:
// [a b c]
}
func ExampleAny() {
p1 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 250)
resolve("fast")
})
p2 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 500)
resolve("slow")
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error"))
})
pms := []*Promise[string]{p1, p2, p3}
p := Any(pms)
result, err := p.Await()
if err != nil {
return
}
fmt.Println(result)
// Output:
// fast
}
func ExampleRace() {
p1 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 100)
resolve("fast")
})
p2 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 300)
resolve("slow")
})
pms := []*Promise[string]{p1, p2}
p := Race(pms)
result, err := p.Await()
if err != nil {
return
}
fmt.Println(result)
// Output:
// fast
}

302
promise/promise_test.go Normal file
View File

@@ -0,0 +1,302 @@
package promise
import (
"errors"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestResolve(t *testing.T) {
assert := internal.NewAssert(t, "TestResolve")
p := Resolve("abc")
assert.Equal("abc", p.result)
assert.Equal(false, p.pending)
}
func TestReject(t *testing.T) {
assert := internal.NewAssert(t, "TestReject")
err := errors.New("error")
p := Reject[string](err)
assert.Equal("error", p.err.Error())
assert.Equal(false, p.pending)
}
func TestThen(t *testing.T) {
assert := internal.NewAssert(t, "TestThen")
p1 := New(func(resolve func(string), reject func(error)) {
resolve("abc")
})
p2 := Then(p1, func(data string) string {
return data + "de"
})
val, err := p1.Await()
assert.IsNil(err)
assert.Equal("abc", val)
val, err = p2.Await()
assert.IsNil(err)
assert.Equal("abcde", val)
}
func TestPromise_Then(t *testing.T) {
assert := internal.NewAssert(t, "TestPromise_Then")
p1 := New(func(resolve func(int), reject func(error)) {
resolve(1)
})
p2 := p1.Then(func(n int) int {
return n + 2
})
val, err := p1.Await()
assert.IsNil(err)
assert.Equal(1, val)
val, err = p2.Await()
assert.IsNil(err)
assert.Equal(3, val)
}
func TestCatch(t *testing.T) {
assert := internal.NewAssert(t, "TestCatch")
p1 := New(func(resolve func(string), reject func(error)) {
err := errors.New("error1")
reject(err)
})
p2 := Catch(p1, func(err error) error {
e := errors.New("error2")
return internal.JoinError(err, e)
})
val, err := p1.Await()
assert.Equal("", val)
assert.IsNotNil(err)
assert.Equal("error1", err.Error())
val, err = p2.Await()
assert.Equal("", val)
assert.IsNotNil(err)
assert.Equal("error1\nerror2", err.Error())
}
func TestPromise_Catch(t *testing.T) {
assert := internal.NewAssert(t, "TestPromise_Catch")
p1 := New(func(resolve func(string), reject func(error)) {
err := errors.New("error1")
reject(err)
})
p2 := p1.Catch(func(err error) error {
e := errors.New("error2")
return internal.JoinError(err, e)
})
val, err := p1.Await()
assert.Equal("", val)
assert.IsNotNil(err)
assert.Equal("error1", err.Error())
val, err = p2.Await()
assert.Equal("", val)
assert.IsNotNil(err)
assert.Equal("error1\nerror2", err.Error())
}
func TestAll(t *testing.T) {
assert := internal.NewAssert(t, "TestPromise_All")
t.Run("AllPromisesFullfilled", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
resolve("a")
})
p2 := New(func(resolve func(string), reject func(error)) {
resolve("b")
})
p3 := New(func(resolve func(string), reject func(error)) {
resolve("c")
})
p := All([]*Promise[string]{p1, p2, p3})
val, err := p.Await()
assert.Equal([]string{"a", "b", "c"}, val)
assert.IsNil(err)
})
t.Run("EmptyPromises", func(_ *testing.T) {
var empty = []*Promise[any]{}
p := All(empty)
assert.IsNil(p)
})
t.Run("PromisesContainRejected", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
resolve("a")
})
p2 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error1"))
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error2"))
})
p := All([]*Promise[string]{p1, p2, p3})
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error1"))
})
p2 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error2"))
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error3"))
})
p := All([]*Promise[string]{p1, p2, p3})
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}
func TestAny(t *testing.T) {
assert := internal.NewAssert(t, "TestPromise_Any")
t.Run("AnyFullfilled", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 250)
resolve("fast")
})
p2 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 500)
resolve("slow")
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error"))
})
p := Any([]*Promise[string]{p1, p2, p3})
val, err := p.Await()
assert.Equal("fast", val)
assert.IsNil(err)
})
t.Run("EmptyPromises", func(_ *testing.T) {
var empty = []*Promise[any]{}
p := Any(empty)
assert.IsNil(p)
})
t.Run("OnlyRejected", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error1"))
})
p2 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error2"))
})
p := Any([]*Promise[string]{p1, p2})
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}
func TestRace(t *testing.T) {
assert := internal.NewAssert(t, "TestPromise_Race")
t.Run("PromisesFullfilled", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 100)
resolve("a")
})
p2 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 300)
resolve("b")
})
p := Race([]*Promise[string]{p1, p2})
val, err := p.Await()
assert.Equal("a", val)
assert.IsNil(err)
})
t.Run("EmptyPromises", func(_ *testing.T) {
var empty = []*Promise[any]{}
p := Race(empty)
assert.IsNil(p)
})
t.Run("PromisesContainRejected", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
time.Sleep(time.Millisecond * 100)
resolve("a")
})
p2 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error1"))
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error2"))
})
p := Race([]*Promise[string]{p1, p2, p3})
val, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
assert.Equal("", val)
})
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
p1 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error1"))
})
p2 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error2"))
})
p3 := New(func(resolve func(string), reject func(error)) {
reject(errors.New("error3"))
})
p := Race([]*Promise[string]{p1, p2, p3})
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}

View File

@@ -22,7 +22,7 @@ var (
)
// Contain check if the target value is in the slice or not.
// Play: todo
// Play: https://go.dev/play/p/_454yEHcNjf
func Contain[T comparable](slice []T, target T) bool {
for _, item := range slice {
if item == target {
@@ -34,6 +34,7 @@ func Contain[T comparable](slice []T, target T) bool {
}
// ContainBy returns true if predicate function return true.
// Play: https://go.dev/play/p/49tkHfX4GNc
func ContainBy[T any](slice []T, predicate func(item T) bool) bool {
for _, item := range slice {
if predicate(item) {
@@ -420,6 +421,17 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
}
}
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
// when iteratee return false, will break the for each loop.
// Play: https://go.dev/play/p/qScs39f3D9W
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
for i, v := range slice {
if !iteratee(i, v) {
break
}
}
}
// Map creates an slice of values by running each element of slice thru iteratee function.
// Play: https://go.dev/play/p/biaTefqPquw
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
@@ -436,7 +448,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
// iteratee callback function should returntwo values:
// 1, mapping result.
// 2, whether the result element should be included or not
// Play: todo
// Play: https://go.dev/play/p/J94SZ_9MiIe
func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, bool)) []U {
result := []U{}
@@ -450,7 +462,7 @@ func FilterMap[T any, U any](slice []T, iteratee func(index int, item T) (U, boo
}
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
// Play: todo
// Play: https://go.dev/play/p/_QARWlWs1N_F
func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U {
result := make([]U, 0, len(slice))
@@ -1082,7 +1094,7 @@ func IndexOf[T comparable](arr []T, val T) int {
// LastIndexOf returns the index at which the last occurrence of the item is found in a slice or return -1 if the then cannot be found.
// Play: https://go.dev/play/p/DokM4cf1IKH
func LastIndexOf[T comparable](slice []T, item T) int {
for i := len(slice) - 1; i > 0; i-- {
for i := len(slice) - 1; i >= 0; i-- {
if item == slice[i] {
return i
}

View File

@@ -379,6 +379,25 @@ func ExampleForEach() {
// [2 3 4]
}
func ExampleForEachWithBreak() {
numbers := []int{1, 2, 3, 4, 5}
var sum int
ForEachWithBreak(numbers, func(_, n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
fmt.Println(sum)
// Output:
// 6
}
func ExampleMap() {
nums := []int{1, 2, 3}

View File

@@ -307,6 +307,23 @@ func TestForEach(t *testing.T) {
assert.Equal(expected, numbersAddTwo)
}
func TestForEachWithBreak(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5}
var sum int
ForEachWithBreak(numbers, func(_, n int) bool {
if n > 3 {
return false
}
sum += n
return true
})
assert := internal.NewAssert(t, "TestForEach")
assert.Equal(6, sum)
}
func TestMap(t *testing.T) {
nums := []int{1, 2, 3, 4}
multiplyTwo := func(i, num int) int {
@@ -648,8 +665,8 @@ func TestDifferenceWith(t *testing.T) {
func TestDifferenceBy(t *testing.T) {
assert := internal.NewAssert(t, "TestDifferenceBy")
s1 := []int{1, 2, 3, 4, 5} //after add one: 2 3 4 5 6
s2 := []int{3, 4, 5} //after add one: 4 5 6
s1 := []int{1, 2, 3, 4, 5} // after add one: 2 3 4 5 6
s2 := []int{3, 4, 5} // after add one: 4 5 6
addOne := func(i int, v int) int {
return v + 1
}
@@ -856,8 +873,9 @@ func TestIndexOf(t *testing.T) {
func TestLastIndexOf(t *testing.T) {
assert := internal.NewAssert(t, "TestLastIndexOf")
arr := []string{"a", "a", "b", "c"}
assert.Equal(1, LastIndexOf(arr, "a"))
arr := []string{"a", "b", "b", "c"}
assert.Equal(0, LastIndexOf(arr, "a"))
assert.Equal(2, LastIndexOf(arr, "b"))
assert.Equal(-1, LastIndexOf(arr, "d"))
}

View File

@@ -64,6 +64,7 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
var zeroValue T
for next, item, ok := generator(), zeroValue, true; ok; {
item, ok = next()
if ok {
source = append(source, item)
@@ -98,7 +99,7 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
}
l := int((end-start)/step) + 1
source := make([]T, l, l)
source := make([]T, l)
for i := 0; i < l; i++ {
source[i] = start + (T(i) * step)
@@ -160,7 +161,7 @@ func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
source := make([]T, s.Count(), s.Count())
source := make([]T, s.Count())
for i, v := range s.source {
source[i] = mapper(v)

112
structs/field.go Normal file
View 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
View File

@@ -0,0 +1,272 @@
package structs
import (
"github.com/duke-git/lancet/v2/internal"
"reflect"
"testing"
)
func TestField_Tag(t *testing.T) {
assert := internal.NewAssert(t, "TestField_Tag")
type Parent struct {
Name string `json:"name,omitempty"`
}
p1 := &Parent{"111"}
s := New(p1)
n, _ := s.Field("Name")
tag := n.Tag()
assert.Equal("name", tag.Name)
assert.Equal(true, tag.HasOption("omitempty"))
}
func TestField_Value(t *testing.T) {
assert := internal.NewAssert(t, "TestField_Value")
type Parent struct {
Name string `json:"name,omitempty"`
}
p1 := &Parent{"111"}
s := New(p1)
n, _ := s.Field("Name")
assert.Equal("111", n.Value())
}
func TestField_IsEmbedded(t *testing.T) {
assert := internal.NewAssert(t, "TestField_IsEmbedded")
type Parent struct {
Name string
}
type Child struct {
Parent
Age int
}
c1 := &Child{}
c1.Name = "111"
c1.Age = 11
s := New(c1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal(true, n.IsEmbedded())
assert.Equal(false, a.IsEmbedded())
}
func TestField_IsExported(t *testing.T) {
assert := internal.NewAssert(t, "TestField_IsEmbedded")
type Parent struct {
Name string
age int
}
p1 := &Parent{Name: "11", age: 11}
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("age")
assert.Equal(true, n.IsExported())
assert.Equal(false, a.IsExported())
}
func TestField_IsZero(t *testing.T) {
assert := internal.NewAssert(t, "TestField_IsZero")
type Parent struct {
Name string
Age int
}
p1 := &Parent{Age: 11}
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal(true, n.IsZero())
assert.Equal(false, a.IsZero())
}
func TestField_Name(t *testing.T) {
assert := internal.NewAssert(t, "TestField_Name")
type Parent struct {
Name string
Age int
}
p1 := &Parent{Age: 11}
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal("Name", n.Name())
assert.Equal("Age", a.Name())
}
func TestField_Kind(t *testing.T) {
assert := internal.NewAssert(t, "TestField_Kind")
type Parent struct {
Name string
Age int
}
p1 := &Parent{Age: 11}
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal(reflect.String, n.Kind())
assert.Equal(reflect.Int, a.Kind())
}
func TestField_IsSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestField_IsSlice")
type Parent struct {
Name string
arr []int
}
p1 := &Parent{arr: []int{1, 2, 3}}
s := New(p1)
a, _ := s.Field("arr")
assert.Equal(true, a.IsSlice())
}
func TestField_MapValue(t *testing.T) {
assert := internal.NewAssert(t, "TestField_MapValue")
t.Run("nested struct", func(t *testing.T) {
type Child struct {
Name string `json:"name"`
}
type Parent struct {
Name string `json:"name"`
Child *Child `json:"child"`
}
c1 := &Child{"11-1"}
p1 := &Parent{
Name: "11",
Child: c1,
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
assert.Equal(map[string]any{"name": "11-1"}, val)
})
t.Run("nested ptr struct", func(t *testing.T) {
type Child struct {
Name string `json:"name"`
}
type Parent struct {
Name string `json:"name"`
Child any `json:"child"`
}
c1 := &Child{"11-1"}
c2 := &c1
c3 := &c2
p1 := &Parent{
Name: "11",
Child: c3,
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
assert.Equal(map[string]any{"name": "11-1"}, val)
})
t.Run("nested array", func(t *testing.T) {
type Parent struct {
Name string `json:"name"`
Child []int `json:"child"`
}
p1 := &Parent{
Name: "11",
Child: []int{1, 2, 3},
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
assert.Equal([]int{1, 2, 3}, val)
})
t.Run("nested array struct", func(t *testing.T) {
type Child struct {
Name string `json:"name"`
}
type Parent struct {
Name string `json:"name"`
Child []*Child `json:"child"`
}
c1 := &Child{"11-1"}
c2 := &Child{"11-2"}
p1 := &Parent{
Name: "11",
Child: []*Child{c1, c2},
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
assert.Equal(arr, val)
})
t.Run("nested ptr array struct", func(t *testing.T) {
type Child struct {
Name string `json:"name"`
}
type Parent struct {
Name string `json:"name"`
Child *[]*Child `json:"child"`
}
c1 := &Child{"11-1"}
c2 := &Child{"11-2"}
p1 := &Parent{
Name: "11",
Child: &[]*Child{c1, c2},
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
arr := []any{map[string]any{"name": "11-1"}, map[string]any{"name": "11-2"}}
assert.Equal(arr, val)
})
t.Run("nested map in struct", func(t *testing.T) {
type Parent struct {
Name string `json:"name"`
Child map[string]any `json:"child"`
}
p1 := &Parent{
Name: "11",
Child: map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}},
}
s := New(p1)
f, ok := s.Field("Child")
val := f.mapValue(f.Value())
assert.Equal(true, ok)
assert.Equal(map[string]any{"a": 1, "b": map[string]any{"name": "11-1"}}, val)
})
}

117
structs/struct.go Normal file
View File

@@ -0,0 +1,117 @@
// Package structs provide several high level functions to manipulate struct, tag, and field.
package structs
import (
"reflect"
"github.com/duke-git/lancet/v2/pointer"
)
// defaultTagName is the default tag for struct fields to lookup.
var defaultTagName = "json"
// Struct is abstract struct for provide several high level functions
type Struct struct {
raw any
rtype reflect.Type
rvalue reflect.Value
TagName string
}
// New returns a new *Struct
func New(value any, tagName ...string) *Struct {
value = pointer.ExtractPointer(value)
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
tn := defaultTagName
if len(tagName) > 0 {
tn = tagName[0]
}
// if need: can also set defaultTagName to tn across structs package level
// defaultTagName = tn
return &Struct{
raw: value,
rtype: t,
rvalue: v,
TagName: tn,
}
}
// ToMap converts the given struct to a map[string]any, where the keys
// of the keys are the field names and the values of the map are the values
// of the fields. The default map key is the struct field name, but you can
// change it. The `json` key is the default tag key. Example:
//
// // default
// Name string `json:"name"`
//
// // ignore the field
// Name string // no tag
// Age string `json:"-"` // json ignore tag
// sex string // unexported field
// Goal int `json:"goal,omitempty"` // omitempty if the field is zero value
//
// // custom map key
// Name string `json:"myName"`
//
// ToMap convert the exported fields of a struct to map.
func (s *Struct) ToMap() (map[string]any, error) {
if !s.IsStruct() {
return nil, errInvalidStruct(s)
}
result := make(map[string]any)
fields := s.Fields()
for _, f := range fields {
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
continue
}
if f.IsZero() && f.tag.HasOption("omitempty") {
continue
}
result[f.tag.Name] = f.mapValue(f.Value())
}
return result, nil
}
// Fields returns all the struct fields within a slice
func (s *Struct) Fields() []*Field {
var fields []*Field
fieldNum := s.rvalue.NumField()
for i := 0; i < fieldNum; i++ {
v := s.rvalue.Field(i)
sf := s.rtype.Field(i)
field := newField(v, sf, s.TagName)
fields = append(fields, field)
}
return fields
}
// Field returns a Field if the given field name was found
func (s *Struct) Field(name string) (*Field, bool) {
f, ok := s.rtype.FieldByName(name)
if !ok {
return nil, false
}
return newField(s.rvalue.FieldByName(name), f, s.TagName), true
}
// IsStruct returns true if the given rvalue is a struct
func (s *Struct) IsStruct() bool {
k := s.rvalue.Kind()
if k == reflect.Invalid {
return false
}
return k == reflect.Struct
}
// ToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value.
func ToMap(v any) (map[string]any, error) {
return New(v).ToMap()
}

View 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
View 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
View 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)
}

View File

@@ -69,7 +69,7 @@ func LowerFirst(s string) string {
// PadStart pads string on the left and right side if it's shorter than size.
// Padding characters are truncated if they exceed size.
// Play: todo
// Play: https://go.dev/play/p/NzImQq-VF8q
func Pad(source string, size int, padStr string) string {
return padAtPosition(source, size, padStr, 0)
}
@@ -289,7 +289,7 @@ func Substring(s string, offset int, length uint) string {
}
// SplitWords splits a string into words, word only contains alphabetic characters.
// Play: todo
// Play: https://go.dev/play/p/KLiX4WiysMM
func SplitWords(s string) []string {
var word string
var words []string
@@ -331,7 +331,7 @@ func SplitWords(s string) []string {
}
// WordCount return the number of meaningful word, word only contains alphabetic characters.
// Play: todo
// Play: https://go.dev/play/p/bj7_odx3vRf
func WordCount(s string) int {
var r rune
var size, count int
@@ -360,3 +360,16 @@ func WordCount(s string) int {
return count
}
// RemoveNonPrintable remove non-printable characters from a string.
// Play: todo
func RemoveNonPrintable(str string) string {
result := strings.Map(func(r rune) rune {
if unicode.IsPrint(r) {
return r
}
return -1
}, str)
return result
}

View File

@@ -438,3 +438,14 @@ func ExampleWordCount() {
// 0
// 0
}
func ExampleRemoveNonPrintable() {
result1 := RemoveNonPrintable("hello\u00a0 \u200bworld\n")
result2 := RemoveNonPrintable("你好😄")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// hello world
// 你好😄
}

View File

@@ -342,3 +342,10 @@ func TestWordCount(t *testing.T) {
assert.Equal(v, WordCount(k))
}
}
func TestRemoveNonPrintable(t *testing.T) {
assert := internal.NewAssert(t, "TestRemoveNonPrintable")
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
assert.Equal("你好😄", RemoveNonPrintable("你好😄"))
}

View File

@@ -58,6 +58,31 @@ func IsAllLower(str string) bool {
return str != ""
}
// IsASCII checks if string is all ASCII char.
// Play: todo
func IsASCII(str string) bool {
for i := 0; i < len(str); i++ {
if str[i] > unicode.MaxASCII {
return false
}
}
return true
}
// IsPrintable checks if string is all printable chars.
// Play: todo
func IsPrintable(str string) bool {
for _, r := range str {
if !unicode.IsPrint(r) {
if r == '\n' || r == '\r' || r == '\t' || r == '`' {
continue
}
return false
}
}
return true
}
// ContainUpper check if the string contain at least one upper case letter A-Z.
// Play: https://go.dev/play/p/CmWeBEk27-z
func ContainUpper(str string) bool {

View File

@@ -407,3 +407,45 @@ func ExampleIsGBK() {
// Output:
// true
}
func ExampleIsASCII() {
result1 := IsASCII("ABC")
result2 := IsASCII("123")
result3 := IsASCII("")
result4 := IsASCII("😄")
result5 := IsASCII("你好")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// false
// false
}
func ExampleIsPrintable() {
result1 := IsPrintable("ABC")
result2 := IsPrintable("{id: 123}")
result3 := IsPrintable("")
result4 := IsPrintable("😄")
result5 := IsPrintable("\u0000")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// true
// true
// false
}

View File

@@ -401,3 +401,23 @@ func TestIsGBK(t *testing.T) {
assert.Equal(true, IsGBK(gbkData))
assert.Equal(false, utf8.Valid(gbkData))
}
func TestIsASCII(t *testing.T) {
assert := internal.NewAssert(t, "TestIsASCII")
assert.Equal(true, IsASCII("ABC"))
assert.Equal(true, IsASCII("123"))
assert.Equal(true, IsASCII(""))
assert.Equal(false, IsASCII("😄"))
assert.Equal(false, IsASCII("你好"))
}
func TestIsPrintable(t *testing.T) {
assert := internal.NewAssert(t, "TestIsPrintable")
assert.Equal(true, IsPrintable("ABC"))
assert.Equal(true, IsPrintable("{id: 123}"))
assert.Equal(true, IsPrintable(""))
assert.Equal(true, IsPrintable("😄"))
assert.Equal(false, IsPrintable("\u0000"))
}