mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-16 10:42:27 +08:00
Compare commits
63 Commits
47dccd63af
...
v2.1.19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
975c303a31 | ||
|
|
3b8dd94a5c | ||
|
|
815791c0b6 | ||
|
|
a12a691ee6 | ||
|
|
247cf89947 | ||
|
|
c3fad62d8c | ||
|
|
a8a96be21b | ||
|
|
8e297769b2 | ||
|
|
98cdf1c040 | ||
|
|
d7976e31a4 | ||
|
|
5b11a8b457 | ||
|
|
d4a16534f2 | ||
|
|
ecf0688788 | ||
|
|
90f9cad1ea | ||
|
|
4a298876e9 | ||
|
|
74474cd9ef | ||
|
|
f23f18457e | ||
|
|
18f01ffd75 | ||
|
|
c53d541a6b | ||
|
|
5b9b4c4344 | ||
|
|
6e7300bbbf | ||
|
|
3685aee02b | ||
|
|
046f3e0bf9 | ||
|
|
c01c9d14b4 | ||
|
|
f198191063 | ||
|
|
8bdd46bda4 | ||
|
|
e29b56c3c3 | ||
|
|
c357fc68c8 | ||
|
|
bc25e7a037 | ||
|
|
217350042b | ||
|
|
e56a8a1ef5 | ||
|
|
6453f755a6 | ||
|
|
027abd6ad5 | ||
|
|
91503b1656 | ||
|
|
e2522cd29b | ||
|
|
da69b77892 | ||
|
|
05772d8d7d | ||
|
|
3b497532f3 | ||
|
|
1cd3be508c | ||
|
|
a41d461910 | ||
|
|
cde5946bf0 | ||
|
|
c28803b25e | ||
|
|
f09e521783 | ||
|
|
0aa41f337d | ||
|
|
48814a720a | ||
|
|
04b79b3dfe | ||
|
|
302007ebdf | ||
|
|
965e5fbcda | ||
|
|
70d0adde42 | ||
|
|
0b80074bb7 | ||
|
|
90945a0399 | ||
|
|
4ae7e59829 | ||
|
|
8f0c60cade | ||
|
|
3f6aef1432 | ||
|
|
a714e04470 | ||
|
|
7456621153 | ||
|
|
73ac9825e9 | ||
|
|
930bb9c839 | ||
|
|
3d8f1be212 | ||
|
|
13a4ed59fa | ||
|
|
c799d10ce9 | ||
|
|
5ab322ade2 | ||
|
|
d0ffc61842 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,4 +7,5 @@ fileutil/*.zip
|
||||
fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
cryptor/*.pem
|
||||
test
|
||||
203
README.md
203
README.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -24,7 +24,7 @@ English | [简体中文](./README_zh-CN.md)
|
||||
## Feature
|
||||
|
||||
- 👏 Comprehensive, efficient and reusable.
|
||||
- 💪 400+ go util functions, support string, slice, datetime, net, crypt...
|
||||
- 💪 500+ go util functions, support string, slice, datetime, net, crypt...
|
||||
- 💅 Only depend on the go standard library.
|
||||
- 🌍 Unit test for every exported function.
|
||||
|
||||
@@ -41,7 +41,7 @@ go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.7. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.3.7 // below go1.18, install latest version of v1.x.x
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -541,6 +541,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>UnZip</big>** : unzip the zip file and save it to dest path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)]
|
||||
[[play](https://go.dev/play/p/g0w34kS7B8m)]
|
||||
- **<big>CurrentPath</big>** : return current absolute path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CurrentPath)]
|
||||
|
||||
### 9. Formatter contains some functions for data formatting.
|
||||
|
||||
@@ -553,6 +555,18 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
- **<big>Comma</big>** : add comma to a number value by every 3 numbers from right, ahead by symbol char.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Pretty</big>** : pretty print data to JSON string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Pretty)]
|
||||
- **<big>PrettyToWriter</big>** : pretty encode data to writer.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#PrettyToWriter)]
|
||||
- **<big>DecimalBytes</big>** : returns a human readable byte size under decimal standard (base 1000).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#DecimalBytes)]
|
||||
- **<big>BinaryBytes</big>** : returns a human-readable byte size under binary standard (base 1024).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#BinaryBytes)]
|
||||
- **<big>ParseDecimalBytes</big>** : return the human readable bytes size string into the amount it represents(base 1000).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseDecimalBytes)]
|
||||
- **<big>ParseBinaryBytes</big>** : return the human readable bytes size string into the amount it represents(base 1024).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseBinaryBytes)]
|
||||
|
||||
### 10. Function package can control the flow of function execution and support part of functional programming
|
||||
|
||||
@@ -598,6 +612,8 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>MapTo</big>** : quick map any value to struct or any base type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapTo)]
|
||||
- **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/OaThj6iNVXK)]
|
||||
@@ -703,6 +719,24 @@ 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)]
|
||||
[[play](https://go.dev/play/p/CIvlICqrHql)]
|
||||
- **<big>RadianToAngle</big>** : converts radian value to angle value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RadianToAngle)]
|
||||
[[play](https://go.dev/play/p/dQtmOTUOMgi)]
|
||||
- **<big>PointDistance</big>** : get two points distance.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#PointDistance)]
|
||||
[[play](https://go.dev/play/p/RrG4JIaziM8)]
|
||||
- **<big>IsPrime</big>** : checks if number is prime number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#IsPrime)]
|
||||
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
|
||||
|
||||
### 13. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
@@ -754,15 +788,15 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- **<big>StructToUrlValues</big>** : convert struct to url valuse.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)]
|
||||
[[play](https://go.dev/play/p/pFqMkM40w9z)]
|
||||
- **<big>HttpGet<sup>deprecated</sup></big>** : send get http request.
|
||||
- **<big>HttpGet<sup>deprecated</sup></big>** : send http get request.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)]
|
||||
- **<big>HttpDelete<sup>deprecated</sup></big>** : send delete http request.
|
||||
- **<big>HttpDelete<sup>deprecated</sup></big>** : send http delete request.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)]
|
||||
- **<big>HttpPost<sup>deprecated</sup></big>** : send post http request.
|
||||
- **<big>HttpPost<sup>deprecated</sup></big>** : send http post request.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)]
|
||||
- **<big>HttpPut<sup>deprecated</sup></big>** : send put http request.
|
||||
- **<big>HttpPut<sup>deprecated</sup></big>** : send http put request.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)]
|
||||
- **<big>HttpPatch<sup>deprecated</sup></big>** : send patch http request.
|
||||
- **<big>HttpPatch<sup>deprecated</sup></big>** : send http patch request.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)]
|
||||
- **<big>ParseHttpResponse</big>** : decode http response into target object.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)]
|
||||
@@ -916,6 +950,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<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)]
|
||||
@@ -949,8 +986,12 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Reverse</big>** : return slice of element order is reversed to the given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/8uI8f1lwNrQ)]
|
||||
- **<big>Reduce</big>** : creates an slice of values by running each element of slice thru iteratee function.
|
||||
- **<big>Reduce<sup>deprecated</sup></big>** : creates an slice of values by running each element of slice thru iteratee function.(Deprecated: use ReduceBy)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)]
|
||||
- **<big>ReduceBy</big>** : produces a value from slice by accumulating the result of each element as passed through the reducer function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceBy)]
|
||||
- **<big>ReduceRight</big>** : ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceRight)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)]
|
||||
@@ -1022,7 +1063,124 @@ 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. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>Of</big>** : creates a stream whose elements are the specified values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Of)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
- **<big>FromSlice</big>** : creates a stream from slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#FromSlice)]
|
||||
[[play](https://go.dev/play/p/wywTO0XZtI4)]
|
||||
- **<big>FromChannel</big>** : creates a stream from channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#FromChannel)]
|
||||
[[play](https://go.dev/play/p/9TZYugGMhXZ)]
|
||||
- **<big>FromRange</big>** : creates a number stream from start to end. both start and end are included. [start, end]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#FromRange)]
|
||||
[[play](https://go.dev/play/p/9Ex1-zcg-B-)]
|
||||
- **<big>Generate</big>** : creates a stream where each element is generated by the provided generater function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Generate)]
|
||||
[[play](https://go.dev/play/p/rkOWL1yA3j9)]
|
||||
- **<big>Concat</big>** : creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Concat)]
|
||||
[[play](https://go.dev/play/p/HM4OlYk_OUC)]
|
||||
- **<big>Distinct</big>** : creates returns a stream that removes the duplicated items.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Distinct)]
|
||||
[[play](https://go.dev/play/p/eGkOSrm64cB)]
|
||||
- **<big>Filter</big>** : returns a stream consisting of the elements of this stream that match the given predicate.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Filter)]
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>Map</big>** : returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
- **<big>Peek</big>** : returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Peek)]
|
||||
[[play](https://go.dev/play/p/u1VNzHs6cb2)]
|
||||
- **<big>Skip</big>** : returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Skip)]
|
||||
[[play](https://go.dev/play/p/fNdHbqjahum)]
|
||||
- **<big>Limit</big>** : returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Limit)]
|
||||
[[play](https://go.dev/play/p/qsO4aniDcGf)]
|
||||
- **<big>Reverse</big>** : returns a stream whose elements are reverse order of given stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/A8_zkJnLHm4)]
|
||||
- **<big>Range</big>** : returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Range)]
|
||||
[[play](https://go.dev/play/p/indZY5V2f4j)]
|
||||
- **<big>Sorted</big>** : returns a stream consisting of the elements of this stream, sorted according to the provided less function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Sorted)]
|
||||
[[play](https://go.dev/play/p/XXtng5uonFj)]
|
||||
- **<big>ForEach</big>** : performs an action for each element of this stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/Dsm0fPqcidk)]
|
||||
- **<big>Reduce</big>** : performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/6uzZjq_DJLU)]
|
||||
- **<big>FindFirst</big>** : returns the first element of this stream and true, or zero value and false if the stream is empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#FindFirst)]
|
||||
[[play](https://go.dev/play/p/9xEf0-6C1e3)]
|
||||
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less fuction: a > b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Max)]
|
||||
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
|
||||
- **<big>Min</big>** : returns the minimum element of this stream according to the provided less function. less fuction: a < b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Min)]
|
||||
[[play](https://go.dev/play/p/vZfIDgGNRe_0)]
|
||||
- **<big>AllMatch</big>** : returns whether all elements of this stream match the provided predicate.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#AllMatch)]
|
||||
[[play](https://go.dev/play/p/V5TBpVRs-Cx)]
|
||||
- **<big>AnyMatch</big>** : returns whether any elements of this stream match the provided predicate.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#AnyMatch)]
|
||||
[[play](https://go.dev/play/p/PTCnWn4OxSn)]
|
||||
- **<big>NoneMatch</big>** : returns whether no elements of this stream match the provided predicate.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#NoneMatch)]
|
||||
[[play](https://go.dev/play/p/iWS64pL1oo3)]
|
||||
- **<big>Count</big>** : returns the count of elements in the stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Count)]
|
||||
[[play](https://go.dev/play/p/r3koY6y_Xo-)]
|
||||
- **<big>ToSlice</big>** : returns the elements in the stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
|
||||
### 18. 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)]
|
||||
|
||||
### 19. Strutil package contains some functions to manipulate string.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1098,8 +1256,11 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/og47F5x_jTZ)]
|
||||
|
||||
### 19. System package contain some functions about os, runtime, shell command.
|
||||
### 20. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1135,7 +1296,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.
|
||||
### 21. Validator package contains some functions for data validation.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1188,18 +1349,24 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsEmptyString</big>** : check if the string is empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)]
|
||||
[[play](https://go.dev/play/p/dpzgUjFnBCX)]
|
||||
- **<big>IsFloat</big>** : check if the value is float(float32, float34) or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloat)]
|
||||
- **<big>IsFloatStr</big>** : check if the string can convert to a float.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#LOYwS_Oyl7U)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)]
|
||||
[[play](https://go.dev/play/p/LOYwS_Oyl7U)]
|
||||
- **<big>IsNumber</big>** : check if the value is number(integer, float) or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumber)]
|
||||
- **<big>IsNumberStr</big>** : check if the string can convert to a number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)]
|
||||
[[play](https://go.dev/play/p/LzaKocSV79u)]
|
||||
- **<big>IsJSON</big>** : check if the string is valid JSON.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)]
|
||||
[[play](https://go.dev/play/p/sRS6c4K8jGk)]
|
||||
[[play](https://go.dev/play/p/8Kip1Itjiil)]
|
||||
- **<big>IsRegexMatch</big>** : check if the string match the regexp.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)]
|
||||
[[play](https://go.dev/play/p/z_XeZo_litG)]
|
||||
- **<big>IsInt</big>** : check if the string can convert to a number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsInt)]
|
||||
- **<big>IsIntStr</big>** : check if the string can convert to a integer.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)]
|
||||
[[play](https://go.dev/play/p/jQRtFv-a0Rk)]
|
||||
@@ -1227,8 +1394,14 @@ 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)]
|
||||
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
|
||||
- **<big>IsPrintable</big>** : checks if string is all printable chars.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
|
||||
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
|
||||
|
||||
### 20. xerror package implements helpers for errors.
|
||||
### 22. xerror package implements helpers for errors.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
196
README_zh-CN.md
196
README_zh-CN.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -23,7 +23,7 @@
|
||||
## 特性
|
||||
|
||||
- 👏 全面、高效、可复用
|
||||
- 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
|
||||
- 💪 500+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
|
||||
- 💅 只依赖 go 标准库
|
||||
- 🌍 所有导出函数单元测试覆盖率 100%
|
||||
|
||||
@@ -40,7 +40,7 @@ go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.7。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.3.7 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
```
|
||||
|
||||
## 用法
|
||||
@@ -540,6 +540,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>UnZip</big>** : zip 解压缩文件并保存在目录中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)]
|
||||
[[play](https://go.dev/play/p/g0w34kS7B8m)]
|
||||
- **<big>CurrentPath</big>** : 返回当前位置的绝对路径。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CurrentPath)]
|
||||
|
||||
### 9. formatter 格式化器包含一些数据格式化处理方法。
|
||||
|
||||
@@ -552,6 +554,18 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
- **<big>Comma</big>** : 用逗号每隔 3 位分割数字/字符串,支持前缀添加符号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Pretty</big>** : 返回 pretty JSON 字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Pretty)]
|
||||
- **<big>PrettyToWriter</big>** : Pretty encode 数据到 writer。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#PrettyToWriter)]
|
||||
- **<big>DecimalBytes</big>** : 返回十进制标准(以 1000 为基数)下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#DecimalBytes)]
|
||||
- **<big>BinaryBytes</big>** : 返回 binary 标准(以 1024 为基数)下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#BinaryBytes)]
|
||||
- **<big>ParseDecimalBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1000 为基数)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseDecimalBytes)]
|
||||
- **<big>ParseBinaryBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1024 为基数)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)]
|
||||
|
||||
### 10. function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
@@ -597,6 +611,8 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>MapTo</big>** : 快速将 map 或者其他类型映射到结构体或者指定类型。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapTo)]
|
||||
- **<big>ForEach</big>** : 对 map 中的每对 key 和 value 执行 iteratee 函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/OaThj6iNVXK)]
|
||||
@@ -702,6 +718,24 @@ 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)]
|
||||
[[play](https://go.dev/play/p/CIvlICqrHql)]
|
||||
- **<big>RadianToAngle</big>** : 将弧度值转为角度值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RadianToAngle)]
|
||||
[[play](https://go.dev/play/p/dQtmOTUOMgi)]
|
||||
- **<big>PointDistance</big>** : 计算两个坐标点的距离。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#PointDistance)]
|
||||
[[play](https://go.dev/play/p/RrG4JIaziM8)]
|
||||
- **<big>IsPrime</big>** : 判断质数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#IsPrime)]
|
||||
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
|
||||
|
||||
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
|
||||
@@ -915,6 +949,9 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<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)]
|
||||
@@ -948,9 +985,13 @@ 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<sup>deprecated</sup></big>** : 将切片中的元素依次运行 iteratee 函数,返回运行结果。(废弃:建议使用 ReduceBy)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>ReduceBy</big>** : 对切片元素执行 reduce 操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceBy)]
|
||||
- **<big>ReduceRight</big>** : 类似 ReduceBy 操作,迭代切片元素顺序从右至左。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceRight)]
|
||||
- **<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)]
|
||||
@@ -1021,7 +1062,126 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[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. Stream 流,该包仅验证简单的 stream 实现,功能有限。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>Of</big>** : 创建元素为指定值的 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Of)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
- **<big>FromSlice</big>** : 从切片创建 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FromSlice)]
|
||||
[[play](https://go.dev/play/p/wywTO0XZtI4)]
|
||||
- **<big>FromChannel</big>** : 从通道创建 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FromChannel)]
|
||||
[[play](https://go.dev/play/p/9TZYugGMhXZ)]
|
||||
- **<big>FromRange</big>** : 指定一个数字范围创建 stream, 范围两端点值都包括在内。. [start, end]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FromRange)]
|
||||
[[play](https://go.dev/play/p/9Ex1-zcg-B-)]
|
||||
- **<big>Generate</big>** : 创建一个 stream,其中每个元素都由提供的生成器函数生成。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Generate)]
|
||||
[[play](https://go.dev/play/p/rkOWL1yA3j9)]
|
||||
- **<big>Concat</big>** : 创建一个延迟连接 stream,其元素是第一个 stream 的所有元素,后跟第二个 stream 的全部元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Concat)]
|
||||
[[play](https://go.dev/play/p/HM4OlYk_OUC)]
|
||||
- **<big>Distinct</big>** : 创建并返回一个 stream,用于删除重复的项。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Distinct)]
|
||||
[[play](https://go.dev/play/p/eGkOSrm64cB)]
|
||||
- **<big>Filter</big>** : 返回一个通过判定函数的 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Filter)]
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>Map</big>** : 返回一个 stream,该 stream 由将给定函数应用于源 stream 元素的元素组成。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
- **<big>Peek</big>** : 返回一个由源 stream 的元素组成的 stream,并在从生成的 stream 中消耗元素时对每个元素执行所提供的操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Peek)]
|
||||
[[play](https://go.dev/play/p/u1VNzHs6cb2)]
|
||||
- **<big>Skip</big>** : 在丢弃 stream 的前 n 个元素后,返回由源 stream 的其余元素组成的 stream。如果此 stream 包含的元素少于 n 个,则将返回一个空 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Skip)]
|
||||
[[play](https://go.dev/play/p/fNdHbqjahum)]
|
||||
- **<big>Limit</big>** : 返回由源 stream 的元素组成的 stream,该 stream 被截断为长度不超过 maxSize。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Limit)]
|
||||
[[play](https://go.dev/play/p/qsO4aniDcGf)]
|
||||
- **<big>Reverse</big>** : 返回元素与源 stream 的顺序相反的 stream。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/A8_zkJnLHm4)]
|
||||
- **<big>Range</big>** : 返回一个 stream,该 stream 的元素在从源 stream 的开始(包含)到结束(排除)的范围内。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Range)]
|
||||
[[play](https://go.dev/play/p/indZY5V2f4j)]
|
||||
- **<big>Sorted</big>** : 返回一个 stream,该 stream 由源 stream 的元素组成,并根据提供的 less 函数进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Sorted)]
|
||||
[[play](https://go.dev/play/p/XXtng5uonFj)]
|
||||
- **<big>ForEach</big>** : 对 stream 的每个元素执行一个操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/Dsm0fPqcidk)]
|
||||
- **<big>Reduce</big>** : 使用关联累加函数对 stream 的元素执行 reduce 操作,并 reduce 操作结果(如果有)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/6uzZjq_DJLU)]
|
||||
- **<big>FindFirst</big>** : 返回此 stream 的第一个元素和 true,如果 stream 为空,则返回零值和 false。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FindFirst)]
|
||||
[[play](https://go.dev/play/p/9xEf0-6C1e3)]
|
||||
- **<big>Max</big>** : 根据提供的 less 函数返回 stream 的最大元素。less 函数: a > b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Max)]
|
||||
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
|
||||
- **<big>Min</big>** : 根据提供的 less 函数返回 stream 的最小元素。less 函数: a < b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Min)]
|
||||
[[play](https://go.dev/play/p/vZfIDgGNRe_0)]
|
||||
- **<big>AllMatch</big>** : 判断 stream 的所有元素是否全部匹配指定判定函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#AllMatch)]
|
||||
[[play](https://go.dev/play/p/V5TBpVRs-Cx)]
|
||||
- **<big>AnyMatch</big>** : 判断 stream 是否包含匹配指定判定函数的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#AnyMatch)]
|
||||
[[play](https://go.dev/play/p/PTCnWn4OxSn)]
|
||||
- **<big>NoneMatch</big>** : 判断 stream 的元素是否全部不匹配指定的判定函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#NoneMatch)]
|
||||
[[play](https://go.dev/play/p/iWS64pL1oo3)]
|
||||
- **<big>Count</big>** : 返回 stream 中元素的数量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Count)]
|
||||
[[play](https://go.dev/play/p/r3koY6y_Xo-)]
|
||||
- **<big>ToSlice</big>** : 返回 stream 中的元素切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
|
||||
|
||||
### 18. 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)]
|
||||
|
||||
### 19. strutil 包含字符串处理的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1098,9 +1258,11 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/og47F5x_jTZ)]
|
||||
|
||||
|
||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
||||
### 20. system 包含 os, runtime, shell command 的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1136,7 +1298,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 验证器包,包含常用字符串格式验证函数。
|
||||
### 21. validator 验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1189,18 +1351,24 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsEmptyString</big>** : 验证字符串是否是空字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmptyString)]
|
||||
[[play](https://go.dev/play/p/dpzgUjFnBCX)]
|
||||
- **<big>IsFloat</big>** : 验证参数是否是浮点数((float32,float34)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloat)]
|
||||
- **<big>IsFloatStr</big>** : 验证字符串是否是可以转换为浮点数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#LOYwS_Oyl7U)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)]
|
||||
[[play](https://go.dev/play/p/LOYwS_Oyl7U)]
|
||||
- **<big>IsNumber</big>** : 验证参数是否是数字(integer,float)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumber)]
|
||||
- **<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。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)]
|
||||
[[play](https://go.dev/play/p/sRS6c4K8jGk)]
|
||||
[[play](https://go.dev/play/p/8Kip1Itjiil)]
|
||||
- **<big>IsRegexMatch</big>** : 验证字符串是否可以匹配正则表达式。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsRegexMatch)]
|
||||
[[play](https://go.dev/play/p/z_XeZo_litG)]
|
||||
- **<big>IsInt</big>** : 验证参数是否是整数(int, unit)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsInt)]
|
||||
- **<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)]
|
||||
@@ -1228,8 +1396,14 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
|
||||
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
|
||||
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
|
||||
|
||||
### 20. xerror 包实现一些错误处理函数
|
||||
### 22. xerror 包实现一些错误处理函数
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
// }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Concurrency
|
||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Concurrency
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
@@ -151,6 +152,32 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurrentPath">CurrentPath</span>
|
||||
|
||||
<p>return current absolute path.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CurrentPath() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
absPath := CurrentPath()
|
||||
fmt.Println(absPath)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FileMode">FileMode</span>
|
||||
|
||||
<p>Return file mode infomation.</p>
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
@@ -150,6 +151,32 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurrentPath">CurrentPath</span>
|
||||
|
||||
<p>返回当前位置的绝对路径。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CurrentPath() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
absPath := CurrentPath()
|
||||
fmt.Println(absPath)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FileMode">FileMode</span>
|
||||
|
||||
<p>获取文件mode信息</p>
|
||||
|
||||
@@ -7,6 +7,7 @@ formatter contains some functions for data formatting.
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/byte.go](https://github.com/duke-git/lancet/blob/main/formatter/byte.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -23,6 +24,12 @@ import (
|
||||
## Index
|
||||
|
||||
- [Comma](#Comma)
|
||||
- [Pretty](#Pretty)
|
||||
- [PrettyToWriter](#PrettyToWriter)
|
||||
- [DecimalBytes](#DecimalBytes)
|
||||
- [BinaryBytes](#BinaryBytes)
|
||||
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -63,3 +70,241 @@ func main() {
|
||||
// ¥1,234,567
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pretty">Pretty</span>
|
||||
|
||||
<p>Pretty data to JSON string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Pretty(v any) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [
|
||||
// "a",
|
||||
// "b",
|
||||
// "c"
|
||||
// ]
|
||||
// {
|
||||
// "a": 1
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||
|
||||
<p>Pretty encode data to writer.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func PrettyToWriter(v any, out io.Writer) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := formatter.PrettyToWriter(user, buf)
|
||||
|
||||
fmt.Println(buf)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// "name": "King",
|
||||
// "age": 10000
|
||||
// }
|
||||
//
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecimalBytes">DecimalBytes</span>
|
||||
|
||||
<p>Returns a human readable byte size under decimal standard (base 1000). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DecimalBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.DecimalBytes(1000)
|
||||
result2 := formatter.DecimalBytes(1024)
|
||||
result3 := formatter.DecimalBytes(1234567)
|
||||
result4 := formatter.DecimalBytes(1234567, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KB
|
||||
// 1.024KB
|
||||
// 1.2346MB
|
||||
// 1.235MB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BinaryBytes">BinaryBytes</span>
|
||||
|
||||
<p>Returns a human readable byte size under binary standard (base 1024). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinaryBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.BinaryBytes(1024)
|
||||
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||
result3 := formatter.BinaryBytes(1234567)
|
||||
result4 := formatter.BinaryBytes(1234567, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KiB
|
||||
// 1MiB
|
||||
// 1.1774MiB
|
||||
// 1.18MiB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||
|
||||
<p>Returns the human readable bytes size string into the amount it represents(base 1000).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ParseDecimalBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseDecimalBytes("12")
|
||||
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12000
|
||||
// 12000
|
||||
// 12200
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||
|
||||
<p>Returns the human readable bytes size string into the amount it represents(base 1024).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ParseBinaryBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseBinaryBytes("12")
|
||||
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12288
|
||||
// 12288
|
||||
// 12492
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7,6 +7,7 @@ formatter 格式化器包含一些数据格式化处理方法。
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/byte.go](https://github.com/duke-git/lancet/blob/main/formatter/byte.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -23,6 +24,12 @@ import (
|
||||
## 目录
|
||||
|
||||
- [Comma](#Comma)
|
||||
- [Pretty](#Pretty)
|
||||
- [PrettyToWriter](#PrettyToWriter)
|
||||
- [DecimalBytes](#DecimalBytes)
|
||||
- [BinaryBytes](#BinaryBytes)
|
||||
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -63,3 +70,241 @@ func main() {
|
||||
// ¥1,234,567
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pretty">Pretty</span>
|
||||
|
||||
<p>返回pretty JSON字符串.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Pretty(v any) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [
|
||||
// "a",
|
||||
// "b",
|
||||
// "c"
|
||||
// ]
|
||||
// {
|
||||
// "a": 1
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||
|
||||
<p>Pretty encode数据到writer。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func PrettyToWriter(v any, out io.Writer) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := formatter.PrettyToWriter(user, buf)
|
||||
|
||||
fmt.Println(buf)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// "name": "King",
|
||||
// "age": 10000
|
||||
// }
|
||||
//
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecimalBytes">DecimalBytes</span>
|
||||
|
||||
<p>返回十进制标准(以1000为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DecimalBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.DecimalBytes(1000)
|
||||
result2 := formatter.DecimalBytes(1024)
|
||||
result3 := formatter.DecimalBytes(1234567)
|
||||
result4 := formatter.DecimalBytes(1234567, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KB
|
||||
// 1.024KB
|
||||
// 1.2346MB
|
||||
// 1.235MB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BinaryBytes">BinaryBytes</span>
|
||||
|
||||
<p>返回binary标准(以1024为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.BinaryBytes(1024)
|
||||
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||
result3 := formatter.BinaryBytes(1234567)
|
||||
result4 := formatter.BinaryBytes(1234567, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KiB
|
||||
// 1MiB
|
||||
// 1.1774MiB
|
||||
// 1.18MiB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||
|
||||
<p>将字节单位字符串转换成其所表示的字节数(以1000为基数)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ParseDecimalBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseDecimalBytes("12")
|
||||
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12000
|
||||
// 12000
|
||||
// 12200
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||
|
||||
<p>将字节单位字符串转换成其所表示的字节数(以1024为基数)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ParseBinaryBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseBinaryBytes("12")
|
||||
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12288
|
||||
// 12288
|
||||
// 12492
|
||||
}
|
||||
```
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
## Index
|
||||
|
||||
- [MapTo](#MapTo)
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [FilterByKeys](#FilterByKeys)
|
||||
@@ -47,6 +48,64 @@ import (
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
### <span id="MapTo">MapTo</span>
|
||||
|
||||
<p>Rry to map any interface to struct or base type.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MapTo(src any, dst any) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type (
|
||||
Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Phone string `json:"phone"`
|
||||
Addr Address `json:"address"`
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street string `json:"street"`
|
||||
Number int `json:"number"`
|
||||
}
|
||||
)
|
||||
|
||||
personInfo := map[string]interface{}{
|
||||
"name": "Nothin",
|
||||
"age": 28,
|
||||
"phone": "123456789",
|
||||
"address": map[string]interface{}{
|
||||
"street": "test",
|
||||
"number": 1,
|
||||
},
|
||||
}
|
||||
|
||||
var p Person
|
||||
err := MapTo(personInfo, &p)
|
||||
|
||||
fmt.Println(err)
|
||||
fmt.Println(p)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
// {Nothin 28 123456789 {test 1}}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>Executes iteratee funcation for every key and value pair in map.</p>
|
||||
@@ -123,7 +182,7 @@ func main() {
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
|
||||
result := maputil.Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
@@ -133,7 +192,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FilterByKeys">FilterByKeys</span>
|
||||
|
||||
<p>Iterates over map, return a new map whose keys are all given keys.</p>
|
||||
@@ -172,7 +230,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FilterByValues">FilterByValues</span>
|
||||
|
||||
<p>Iterates over map, return a new map whose values are all given values.</p>
|
||||
@@ -211,7 +268,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitBy">OmitBy</span>
|
||||
|
||||
<p>OmitBy is the opposite of Filter, removes all the map elements for which the predicate function returns true.</p>
|
||||
@@ -253,7 +309,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitByKeys">OmitByKeys</span>
|
||||
|
||||
<p>The opposite of FilterByKeys, extracts all the map elements which keys are not omitted.</p>
|
||||
@@ -292,7 +347,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitByValues">OmitByValues</span>
|
||||
|
||||
<p>The opposite of FilterByValues. remov all elements whose value are in the give slice.</p>
|
||||
@@ -331,7 +385,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Intersect">Intersect</span>
|
||||
|
||||
<p>Iterates over maps, return a new map of key and value pairs in all given maps.</p>
|
||||
@@ -419,7 +472,7 @@ func main() {
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
@@ -498,7 +551,7 @@ func main() {
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
|
||||
result := maputil.Minus(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
@@ -638,7 +691,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="MapKeys">MapKeys</span>
|
||||
|
||||
<p>Transforms a map to other type map by manipulating it's keys.</p>
|
||||
@@ -717,7 +769,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Entry">Entry</span>
|
||||
|
||||
<p>Transforms a map into array of key/value pairs.</p>
|
||||
@@ -763,7 +814,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FromEntries">FromEntries</span>
|
||||
|
||||
<p>Creates a map based on a slice of key/value pairs.</p>
|
||||
@@ -841,7 +891,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsDisjoint">IsDisjoint</span>
|
||||
|
||||
<p>Checks two maps are disjoint if they have no keys in common</p>
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
## 目录:
|
||||
|
||||
- [MapTo](#MapTo)
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [FilterByKeys](#FilterByKeys)
|
||||
@@ -47,6 +48,63 @@ import (
|
||||
|
||||
## API 文档:
|
||||
|
||||
### <span id="MapTo">MapTo</span>
|
||||
|
||||
<p>快速将map或者其他类型映射到结构体或者指定类型。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MapTo(src any, dst any) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type (
|
||||
Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Phone string `json:"phone"`
|
||||
Addr Address `json:"address"`
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street string `json:"street"`
|
||||
Number int `json:"number"`
|
||||
}
|
||||
)
|
||||
|
||||
personInfo := map[string]interface{}{
|
||||
"name": "Nothin",
|
||||
"age": 28,
|
||||
"phone": "123456789",
|
||||
"address": map[string]interface{}{
|
||||
"street": "test",
|
||||
"number": 1,
|
||||
},
|
||||
}
|
||||
|
||||
var p Person
|
||||
err := MapTo(personInfo, &p)
|
||||
|
||||
fmt.Println(err)
|
||||
fmt.Println(p)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
// {Nothin 28 123456789 {test 1}}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>对map中的每对key和value执行iteratee函数</p>
|
||||
@@ -80,7 +138,7 @@ func main() {
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
@@ -123,7 +181,7 @@ func main() {
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
|
||||
result := Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
@@ -171,7 +229,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FilterByValues">FilterByValues</span>
|
||||
|
||||
<p>迭代map, 返回一个新map,其value都是给定的value值。</p>
|
||||
@@ -210,7 +267,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitBy">OmitBy</span>
|
||||
|
||||
<p>Filter的反向操作, 迭代map中的每对key和value, 删除符合predicate函数的key, value, 返回新map。</p>
|
||||
@@ -252,7 +308,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitByKeys">OmitByKeys</span>
|
||||
|
||||
<p>FilterByKeys的反向操作, 迭代map, 返回一个新map,其key不包括给定的key值。</p>
|
||||
@@ -291,7 +346,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OmitByValues">OmitByValues</span>
|
||||
|
||||
<p>FilterByValues的反向操作, 迭代map, 返回一个新map,其value不包括给定的value值。</p>
|
||||
@@ -416,7 +470,7 @@ func main() {
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
@@ -453,7 +507,7 @@ func main() {
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
|
||||
|
||||
result := maputil.Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
@@ -632,7 +686,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="MapKeys">MapKeys</span>
|
||||
|
||||
<p>操作map的每个key,然后转为新的map。</p>
|
||||
@@ -711,7 +764,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Entry">Entry</span>
|
||||
|
||||
<p>将map转换为键/值对切片。</p>
|
||||
@@ -757,7 +809,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FromEntries">FromEntries</span>
|
||||
|
||||
<p>基于键/值对的切片创建map。</p>
|
||||
|
||||
187
docs/mathutil.md
187
docs/mathutil.md
@@ -36,6 +36,10 @@ import (
|
||||
- [TruncRound](#TruncRound)
|
||||
- [Range](#Range)
|
||||
- [RangeWithStep](#RangeWithStep)
|
||||
- [AngleToRadian](#AngleToRadian)
|
||||
- [RadianToAngle](#RadianToAngle)
|
||||
- [PointDistance](#PointDistance)
|
||||
- [IsPrime](#IsPrime)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -501,20 +505,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Range(1, 4)
|
||||
result2 := mathutil.Range(1, -4)
|
||||
result3 := mathutil.Range(-4, 4)
|
||||
result4 := mathutil.Range(1.0, 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)
|
||||
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]
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [1 2 3 4]
|
||||
// [-4 -3 -2 -1]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -540,9 +544,152 @@ import (
|
||||
|
||||
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)
|
||||
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)
|
||||
@@ -550,9 +697,9 @@ func main() {
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// []
|
||||
// [-4 -2 0]
|
||||
// [1 2.1 3.2]
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -36,6 +36,10 @@ import (
|
||||
- [TruncRound](#TruncRound)
|
||||
- [Range](#Range)
|
||||
- [RangeWithStep](#RangeWithStep)
|
||||
- [AngleToRadian](#AngleToRadian)
|
||||
- [RadianToAngle](#RadianToAngle)
|
||||
- [PointDistance](#PointDistance)
|
||||
- [IsPrime](#IsPrime)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -501,20 +505,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Range(1, 4)
|
||||
result2 := mathutil.Range(1, -4)
|
||||
result3 := mathutil.Range(-4, 4)
|
||||
result4 := mathutil.Range(1.0, 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)
|
||||
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]
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [1 2 3 4]
|
||||
// [-4 -3 -2 -1]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -540,9 +544,152 @@ import (
|
||||
|
||||
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)
|
||||
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)
|
||||
@@ -550,9 +697,8 @@ func main() {
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// []
|
||||
// [-4 -2 0]
|
||||
// [1 2.1 3.2]
|
||||
}
|
||||
```
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
361
docs/slice.md
361
docs/slice.md
@@ -62,7 +62,9 @@ import (
|
||||
- [FlatMap](#FlatMap)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||
- [ReduceBy](#ReduceBy)
|
||||
- [ReduceRight](#ReduceRight)
|
||||
- [Replace](#Replace)
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
@@ -173,28 +175,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -561,20 +563,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]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -598,20 +600,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]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -635,23 +637,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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -676,24 +678,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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1002,10 +1004,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||
|
||||
<p>Iterates over elements of slice and invokes function for each element, when iteratee return true, will break the for each loop.</p>
|
||||
<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>
|
||||
|
||||
@@ -1024,20 +1025,20 @@ import (
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
var sum int
|
||||
var sum int
|
||||
|
||||
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||
if n > 3 {
|
||||
return false
|
||||
}
|
||||
sum += n
|
||||
return true
|
||||
})
|
||||
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||
if n > 3 {
|
||||
return false
|
||||
}
|
||||
sum += n
|
||||
return true
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1361,19 +1362,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"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1398,15 +1399,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"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1473,7 +1474,7 @@ func main() {
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>Reduce slice.</p>
|
||||
<p>Reduce slice.(Deprecated: use ReduceBy)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -1505,6 +1506,72 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReduceBy">ReduceBy</span>
|
||||
|
||||
<p>Produces a value from slice by accumulating the result of each element as passed through the reducer function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||
return agg + item
|
||||
})
|
||||
|
||||
result2 := slice.ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1234
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReduceRight">ReduceRight</span>
|
||||
|
||||
<p>ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 4321
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Replace">Replace</span>
|
||||
|
||||
<p>Returns a copy of the slice with the first n non-overlapping instances of old replaced by new.</p>
|
||||
@@ -1652,17 +1719,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1686,17 +1753,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1720,17 +1787,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1754,23 +1821,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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -62,7 +62,9 @@ import (
|
||||
- [FlatMap](#FlatMap)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||
- [ReduceBy](#ReduceBy)
|
||||
- [ReduceRight](#ReduceRight)
|
||||
- [Replace](#Replace)
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
@@ -173,28 +175,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -542,7 +544,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Drop">Drop</span>
|
||||
|
||||
<p>从切片的头部删除n个元素。</p>
|
||||
@@ -563,20 +564,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]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -600,20 +601,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]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -637,23 +638,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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -678,24 +679,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]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1004,7 +1005,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||
|
||||
<p>遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||
@@ -1026,24 +1026,23 @@ import (
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
var sum int
|
||||
var sum int
|
||||
|
||||
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||
if n > 3 {
|
||||
return false
|
||||
}
|
||||
sum += n
|
||||
return true
|
||||
})
|
||||
slice.ForEachWithBreak(numbers, func(_, n int) bool {
|
||||
if n > 3 {
|
||||
return false
|
||||
}
|
||||
sum += n
|
||||
return true
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GroupBy">GroupBy</span>
|
||||
|
||||
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
||||
@@ -1364,19 +1363,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"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1401,15 +1400,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"}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1476,7 +1475,7 @@ func main() {
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果</p>
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果(废弃:建议使用ReduceBy)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1508,6 +1507,72 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReduceBy">ReduceBy</span>
|
||||
|
||||
<p>对切片元素执行reduce操作。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||
return agg + item
|
||||
})
|
||||
|
||||
result2 := slice.ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1234
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReduceRight">ReduceRight</span>
|
||||
|
||||
<p>类似ReduceBy操作,迭代切片元素顺序从右至左。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 4321
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Replace">Replace</span>
|
||||
|
||||
<p>返回切片的副本,其中前n个不重叠的old替换为new</p>
|
||||
@@ -1628,8 +1693,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)
|
||||
}
|
||||
@@ -1655,17 +1720,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1689,17 +1754,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1723,17 +1788,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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1757,23 +1822,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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
907
docs/stream.md
Normal file
907
docs/stream.md
Normal file
@@ -0,0 +1,907 @@
|
||||
# Stream
|
||||
|
||||
Package stream implements a sequence of elements supporting sequential and operations. This package is an experiment to explore if stream in go can work as the way java does. it's feature is very limited.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/stream/stream.go](https://github.com/duke-git/lancet/blob/main/stream/stream.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [Of](#Of)
|
||||
- [FromSlice](#FromSlice)
|
||||
- [FromChannel](#FromChannel)
|
||||
- [FromRange](#FromRange)
|
||||
- [Generate](#Generate)
|
||||
- [Concat](#Concat)
|
||||
- [Distinct](#Distinct)
|
||||
- [Filter](#Filter)
|
||||
- [Map](#Map)
|
||||
- [Peek](#Peek)
|
||||
- [Skip](#Skip)
|
||||
- [Limit](#Limit)
|
||||
- [Reverse](#Reverse)
|
||||
- [Range](#Range)
|
||||
- [Sorted](#Sorted)
|
||||
- [ForEach](#ForEach)
|
||||
- [Reduce](#Reduce)
|
||||
- [FindFirst](#FindFirst)
|
||||
- [Max](#Max)
|
||||
- [Min](#Min)
|
||||
- [AllMatch](#AllMatch)
|
||||
- [AnyMatch](#AnyMatch)
|
||||
- [NoneMatch](#NoneMatch)
|
||||
- [Count](#Count)
|
||||
- [ToSlice](#ToSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Of">Of</span>
|
||||
|
||||
<p>Creates a stream whose elements are the specified values.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Of[T any](elems ...T) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.Of(1, 2, 3)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromSlice">FromSlice</span>
|
||||
|
||||
<p>Creates a stream from slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FromSlice[T any](source []T) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromChannel">FromChannel</span>
|
||||
|
||||
<p>Creates a stream from channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FromChannel[T any](source <-chan T) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
for i := 1; i < 4; i++ {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
s := stream.FromChannel(ch)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromRange">FromRange</span>
|
||||
|
||||
<p>Creates a number stream from start to end. both start and end are included. [start, end]</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromRange(1, 5, 1)
|
||||
|
||||
data := s.ToSlice()
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>Creates a stream where each element is generated by the provided generater function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Generate[T any](generator func() func() (item T, ok bool)) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 0
|
||||
max := 4
|
||||
|
||||
generator := func() func() (int, bool) {
|
||||
return func() (int, bool) {
|
||||
n++
|
||||
return n, n < max
|
||||
}
|
||||
}
|
||||
|
||||
s := stream.Generate(generator)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](a, b stream[T]) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := stream.FromSlice([]int{1, 2, 3})
|
||||
s2 := stream.FromSlice([]int{4, 5, 6})
|
||||
|
||||
s := Concat(s1, s2)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Distinct">Distinct</span>
|
||||
|
||||
<p>Creates returns a stream that removes the duplicated items. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Distinct() stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 2, 3, 3, 3})
|
||||
distinct := original.Distinct()
|
||||
|
||||
data1 := original.ToSlice()
|
||||
data2 := distinct.ToSlice()
|
||||
|
||||
fmt.Println(data1)
|
||||
fmt.Println(data2)
|
||||
|
||||
// Output:
|
||||
// [1 2 2 3 3 3]
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
|
||||
<p>Returns a stream consisting of the elements of this stream that match the given predicate. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Filter(predicate func(item T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
isEven := func(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
even := original.Filter(isEven)
|
||||
|
||||
fmt.Println(even.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Map">Map</span>
|
||||
|
||||
<p>Returns a stream consisting of the elements of this stream that apply the given function to elements of stream. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Map(mapper func(item T) T) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
addOne := func(n int) int {
|
||||
return n + 1
|
||||
}
|
||||
|
||||
increament := original.Map(addOne)
|
||||
|
||||
fmt.Println(increament.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Peek">Peek</span>
|
||||
|
||||
<p>Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Peek(consumer func(item T)) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := []string{}
|
||||
peekStream := original.Peek(func(n int) {
|
||||
data = append(data, fmt.Sprint("value", n))
|
||||
})
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(peekStream.ToSlice())
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [1 2 3]
|
||||
// [value1 value2 value3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Skip">Skip</span>
|
||||
|
||||
<p>Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Skip(n int) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Skip(-1)
|
||||
s2 := original.Skip(0)
|
||||
s3 := original.Skip(1)
|
||||
s4 := original.Skip(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [1 2 3 4]
|
||||
// [2 3 4]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Limit">Limit</span>
|
||||
|
||||
<p>Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Limit(maxSize int) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Limit(-1)
|
||||
s2 := original.Limit(0)
|
||||
s3 := original.Limit(1)
|
||||
s4 := original.Limit(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
|
||||
<p>Returns a stream whose elements are reverse order of given stream. <b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Reverse() stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
reverse := original.Reverse()
|
||||
|
||||
fmt.Println(reverse.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [3 2 1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Range">Range</span>
|
||||
|
||||
<p>Returns a stream whose elements are in the range from start(included) to end(excluded) original stream.<b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Range(start, end int) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
s1 := original.Range(0, 0)
|
||||
s2 := original.Range(0, 1)
|
||||
s3 := original.Range(0, 3)
|
||||
s4 := original.Range(1, 2)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3]
|
||||
// [2]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sorted">Sorted</span>
|
||||
|
||||
<p>Returns a stream consisting of the elements of this stream, sorted according to the provided less function.<b>Support chainable operation</b></p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
sorted := original.Sorted(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(sorted.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [4 2 1 3]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>Performs an action for each element of this stream.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) ForEach(action func(item T))
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := 0
|
||||
original.ForEach(func(item int) {
|
||||
result += item
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := original.Reduce(0, func(a, b int) int {
|
||||
return a + b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindFirst">FindFirst</span>
|
||||
|
||||
<p>Returns the first element of this stream and true, or zero value and false if the stream is empty.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) FindFirst() (T, bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result, ok := original.FindFirst()
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>Returns the maximum element of this stream according to the provided less function. less fuction: a > b</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Max(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
max, ok := original.Max(func(a, b int) bool { return a > b })
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>Returns the minimum element of this stream according to the provided less function. less fuction: a < b</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Min(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
min, ok := original.Min(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(min)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AllMatch">AllMatch</span>
|
||||
|
||||
<p>Returns whether all elements of this stream match the provided predicate.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) AllMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AllMatch(func(item int) bool {
|
||||
return item > 0
|
||||
})
|
||||
|
||||
result2 := original.AllMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AnyMatch">AnyMatch</span>
|
||||
|
||||
<p>Returns whether any elements of this stream match the provided predicate.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AnyMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
result2 := original.AnyMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="NoneMatch">NoneMatch</span>
|
||||
|
||||
<p>Returns whether no elements of this stream match the provided predicate.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.NoneMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
result2 := original.NoneMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Count">Count</span>
|
||||
|
||||
<p>Returns the count of elements in the stream.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Count() int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := stream.FromSlice([]int{1, 2, 3})
|
||||
s2 := stream.FromSlice([]int{})
|
||||
|
||||
fmt.Println(s1.Count())
|
||||
fmt.Println(s2.Count())
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSlice">ToSlice</span>
|
||||
|
||||
<p>Returns the elements in the stream.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) ToSlice() []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.Of(1, 2, 3)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
907
docs/stream_zh-CN.md
Normal file
907
docs/stream_zh-CN.md
Normal file
@@ -0,0 +1,907 @@
|
||||
# Stream
|
||||
|
||||
Stream 流,该包仅验证简单 stream 实现,功能有限。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/stream/stream.go](https://github.com/duke-git/lancet/blob/main/stream/stream.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Of](#Of)
|
||||
- [FromSlice](#FromSlice)
|
||||
- [FromChannel](#FromChannel)
|
||||
- [FromRange](#FromRange)
|
||||
- [Generate](#Generate)
|
||||
- [Concat](#Concat)
|
||||
- [Distinct](#Distinct)
|
||||
- [Filter](#Filter)
|
||||
- [Map](#Map)
|
||||
- [Peek](#Peek)
|
||||
- [Skip](#Skip)
|
||||
- [Limit](#Limit)
|
||||
- [Reverse](#Reverse)
|
||||
- [Range](#Range)
|
||||
- [Sorted](#Sorted)
|
||||
- [ForEach](#ForEach)
|
||||
- [Reduce](#Reduce)
|
||||
- [FindFirst](#FindFirst)
|
||||
- [Max](#Max)
|
||||
- [Min](#Min)
|
||||
- [AllMatch](#AllMatch)
|
||||
- [AnyMatch](#AnyMatch)
|
||||
- [NoneMatch](#NoneMatch)
|
||||
- [Count](#Count)
|
||||
- [ToSlice](#ToSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Of">Of</span>
|
||||
|
||||
<p>创建元素为指定值的stream。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Of[T any](elems ...T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.Of(1, 2, 3)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromSlice">FromSlice</span>
|
||||
|
||||
<p>从切片创建stream。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FromSlice[T any](source []T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromChannel">FromChannel</span>
|
||||
|
||||
<p>从通道创建stream。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FromChannel[T any](source <-chan T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
for i := 1; i < 4; i++ {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
s := stream.FromChannel(ch)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromRange">FromRange</span>
|
||||
|
||||
<p>指定一个范围创建stream, 范围两端点值都包括在内。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromRange(1, 5, 1)
|
||||
|
||||
data := s.ToSlice()
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>创建一个stream,其中每个元素都由提供的生成器函数生成</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Generate[T any](generator func() func() (item T, ok bool)) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 0
|
||||
max := 4
|
||||
|
||||
generator := func() func() (int, bool) {
|
||||
return func() (int, bool) {
|
||||
n++
|
||||
return n, n < max
|
||||
}
|
||||
}
|
||||
|
||||
s := stream.Generate(generator)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>创建一个延迟连接stream,其元素是第一个stream的所有元素,后跟第二个stream的全部元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](a, b stream[T]) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := stream.FromSlice([]int{1, 2, 3})
|
||||
s2 := stream.FromSlice([]int{4, 5, 6})
|
||||
|
||||
s := Concat(s1, s2)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Distinct">Distinct</span>
|
||||
|
||||
<p>创建并返回一个stream,用于删除重复的项。 <b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Distinct() stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 2, 3, 3, 3})
|
||||
distinct := original.Distinct()
|
||||
|
||||
data1 := original.ToSlice()
|
||||
data2 := distinct.ToSlice()
|
||||
|
||||
fmt.Println(data1)
|
||||
fmt.Println(data2)
|
||||
|
||||
// Output:
|
||||
// [1 2 2 3 3 3]
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
|
||||
<p>返回一个通过判定函数的stream <b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Filter(predicate func(item T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
isEven := func(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
even := original.Filter(isEven)
|
||||
|
||||
fmt.Println(even.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Map">Map</span>
|
||||
|
||||
<p>返回一个stream,该stream由将给定函数应用于源stream元素的元素组成。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Map(mapper func(item T) T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
addOne := func(n int) int {
|
||||
return n + 1
|
||||
}
|
||||
|
||||
increament := original.Map(addOne)
|
||||
|
||||
fmt.Println(increament.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Peek">Peek</span>
|
||||
|
||||
<p>返回一个由源stream的元素组成的stream,并在从生成的stream中消耗元素时对每个元素执行所提供的操作。 <b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Peek(consumer func(item T)) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := []string{}
|
||||
peekStream := original.Peek(func(n int) {
|
||||
data = append(data, fmt.Sprint("value", n))
|
||||
})
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(peekStream.ToSlice())
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [1 2 3]
|
||||
// [value1 value2 value3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Skip">Skip</span>
|
||||
|
||||
<p>在丢弃stream的前n个元素后,返回由源stream的其余元素组成的stream。如果此stream包含的元素少于n个,则将返回一个空stream。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Skip(n int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Skip(-1)
|
||||
s2 := original.Skip(0)
|
||||
s3 := original.Skip(1)
|
||||
s4 := original.Skip(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [1 2 3 4]
|
||||
// [2 3 4]
|
||||
// []
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Limit">Limit</span>
|
||||
|
||||
<p>返回由源stream的元素组成的stream,该stream被截断为长度不超过maxSize。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Limit(maxSize int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Limit(-1)
|
||||
s2 := original.Limit(0)
|
||||
s3 := original.Limit(1)
|
||||
s4 := original.Limit(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
|
||||
<p>返回元素与源stream的顺序相反的stream。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Reverse() stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
reverse := original.Reverse()
|
||||
|
||||
fmt.Println(reverse.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [3 2 1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Range">Range</span>
|
||||
|
||||
<p>返回一个stream,该stream的元素在从源stream的开始(包含)到结束(排除)的范围内。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Range(start, end int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
s1 := original.Range(0, 0)
|
||||
s2 := original.Range(0, 1)
|
||||
s3 := original.Range(0, 3)
|
||||
s4 := original.Range(1, 2)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3]
|
||||
// [2]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sorted">Sorted</span>
|
||||
|
||||
<p>返回一个stream,该stream由源stream的元素组成,并根据提供的less函数进行排序。<b>支持链式操作</b></p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
sorted := original.Sorted(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(sorted.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [4 2 1 3]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>对stream的每个元素执行一个操作。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) ForEach(action func(item T))
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := 0
|
||||
original.ForEach(func(item int) {
|
||||
result += item
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>使用关联累加函数对stream的元素执行reduce操作,并reduce操作结果(如果有)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := original.Reduce(0, func(a, b int) int {
|
||||
return a + b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindFirst">FindFirst</span>
|
||||
|
||||
<p>返回此stream的第一个元素和true,如果stream为空,则返回零值和false。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) FindFirst() (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result, ok := original.FindFirst()
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>根据提供的less函数返回stream的最大元素。less 函数: a > b</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Max(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
max, ok := original.Max(func(a, b int) bool { return a > b })
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>根据提供的less函数返回stream的最小元素。less函数: a < b</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Min(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
min, ok := original.Min(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(min)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AllMatch">AllMatch</span>
|
||||
|
||||
<p>判断stream的所有元素是否全部匹配指定判定函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) AllMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AllMatch(func(item int) bool {
|
||||
return item > 0
|
||||
})
|
||||
|
||||
result2 := original.AllMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AnyMatch">AnyMatch</span>
|
||||
|
||||
<p>判断stream是否包含匹配指定判定函数的元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AnyMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
result2 := original.AnyMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="NoneMatch">NoneMatch</span>
|
||||
|
||||
<p>判断stream的元素是否全部不匹配指定的判定函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := stream.FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.NoneMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
result2 := original.NoneMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Count">Count</span>
|
||||
|
||||
<p>返回stream中元素的数量。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) Count() int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := stream.FromSlice([]int{1, 2, 3})
|
||||
s2 := stream.FromSlice([]int{})
|
||||
|
||||
fmt.Println(s1.Count())
|
||||
fmt.Println(s2.Count())
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSlice">ToSlice</span>
|
||||
|
||||
<p>返回stream中的元素切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s stream[T]) ToSlice() []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.Of(1, 2, 3)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
// 你好😄
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
// 你好😄
|
||||
}
|
||||
```
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
- [IsAlpha](#IsAlpha)
|
||||
- [IsAllUpper](#IsAllUpper)
|
||||
- [IsAllLower](#IsAllLower)
|
||||
- [IsASCII](#IsASCII)
|
||||
- [IsBase64](#IsBase64)
|
||||
- [IsChineseMobile](#IsChineseMobile)
|
||||
- [IsChineseIdNum](#IsChineseIdNum)
|
||||
@@ -37,11 +38,14 @@ import (
|
||||
- [IsDns](#IsDns)
|
||||
- [IsEmail](#IsEmail)
|
||||
- [IsEmptyString](#IsEmptyString)
|
||||
- [IsInt](#IsInt)
|
||||
- [IsFloat](#IsFloat)
|
||||
- [IsNumber](#IsNumber)
|
||||
- [IsIntStr](#IsIntStr)
|
||||
- [IsFloatStr](#IsFloatStr)
|
||||
- [IsNumberStr](#IsNumberStr)
|
||||
- [IsJSON](#IsJSON)
|
||||
- [IsRegexMatch](#IsRegexMatch)
|
||||
- [IsIntStr](#IsIntStr)
|
||||
- [IsIp](#IsIp)
|
||||
- [IsIpV4](#IsIpV4)
|
||||
- [IsIpV6](#IsIpV6)
|
||||
@@ -50,6 +54,7 @@ import (
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
- [IsPrintable](#IsPrintable)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -293,6 +298,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>
|
||||
@@ -547,6 +592,154 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsInt">IsInt</span>
|
||||
|
||||
<p>Check if the value is integer(int, unit) or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsInt(v any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsInt("")
|
||||
result2 := validator.IsInt("3")
|
||||
result3 := validator.IsInt(0.1)
|
||||
result4 := validator.IsInt(0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsFloat">IsFloat</span>
|
||||
|
||||
<p>Check if the value is float(float32, float34) or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsFloat(v any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsFloat("")
|
||||
result2 := validator.IsFloat("3")
|
||||
result3 := validator.IsFloat(0)
|
||||
result4 := validator.IsFloat(0.1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsNumber">IsNumber</span>
|
||||
|
||||
<p>Check if the value is number(integer, float) or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsNumber(v any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsNumber("")
|
||||
result2 := validator.IsNumber("3")
|
||||
result3 := validator.IsNumber(0.1)
|
||||
result4 := validator.IsNumber(0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
|
||||
<p>Check if the string can convert to a integer.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsIntStr(s string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIntStr("+3")
|
||||
result2 := validator.IsIntStr("-3")
|
||||
result3 := validator.IsIntStr("3.")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
|
||||
<p>Check if the string can convert to a float.</p>
|
||||
@@ -642,8 +835,8 @@ import (
|
||||
func main() {
|
||||
result1 := validator.IsJSON("{}")
|
||||
result2 := validator.IsJSON("{\"name\": \"test\"}")
|
||||
result3 := validator.IsIntStr("")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
result3 := validator.IsJSON("")
|
||||
result4 := validator.IsJSON("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -689,43 +882,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
|
||||
<p>Check if the string can convert to a integer.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsIntStr(s string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIntStr("+3")
|
||||
result2 := validator.IsIntStr("-3")
|
||||
result3 := validator.IsIntStr("3.")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIp">IsIp</span>
|
||||
|
||||
<p>Check if the string is a ip address.</p>
|
||||
@@ -990,3 +1146,43 @@ 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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
- [IsAlpha](#IsAlpha)
|
||||
- [IsAllUpper](#IsAllUpper)
|
||||
- [IsAllLower](#IsAllLower)
|
||||
- [IsASCII](#IsASCII)
|
||||
- [IsBase64](#IsBase64)
|
||||
- [IsChineseMobile](#IsChineseMobile)
|
||||
- [IsChineseIdNum](#IsChineseIdNum)
|
||||
@@ -37,11 +38,14 @@ import (
|
||||
- [IsDns](#IsDns)
|
||||
- [IsEmail](#IsEmail)
|
||||
- [IsEmptyString](#IsEmptyString)
|
||||
- [IsInt](#IsInt)
|
||||
- [IsFloat](#IsFloat)
|
||||
- [IsNumber](#IsNumber)
|
||||
- [IsIntStr](#IsIntStr)
|
||||
- [IsFloatStr](#IsFloatStr)
|
||||
- [IsNumberStr](#IsNumberStr)
|
||||
- [IsJSON](#IsJSON)
|
||||
- [IsRegexMatch](#IsRegexMatch)
|
||||
- [IsIntStr](#IsIntStr)
|
||||
- [IsIp](#IsIp)
|
||||
- [IsIpV4](#IsIpV4)
|
||||
- [IsIpV6](#IsIpV6)
|
||||
@@ -50,6 +54,7 @@ import (
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
- [IsPrintable](#IsPrintable)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -293,6 +298,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>
|
||||
@@ -547,6 +592,155 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsInt">IsInt</span>
|
||||
|
||||
<p>验证参数是否是整数(int, unit)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsInt(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsInt("")
|
||||
result2 := validator.IsInt("3")
|
||||
result3 := validator.IsInt(0.1)
|
||||
result4 := validator.IsInt(0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsFloat">IsFloat</span>
|
||||
|
||||
<p>验证参数是否是浮点数((float32, float34)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsFloat(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsFloat("")
|
||||
result2 := validator.IsFloat("3")
|
||||
result3 := validator.IsFloat(0)
|
||||
result4 := validator.IsFloat(0.1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsNumber">IsNumber</span>
|
||||
|
||||
<p>验证参数是否是数字(integer or float)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsNumber(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsNumber("")
|
||||
result2 := validator.IsNumber("3")
|
||||
result3 := validator.IsNumber(0.1)
|
||||
result4 := validator.IsNumber(0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsIntStr(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIntStr("+3")
|
||||
result2 := validator.IsIntStr("-3")
|
||||
result3 := validator.IsIntStr("3.")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为浮点数</p>
|
||||
@@ -642,8 +836,8 @@ import (
|
||||
func main() {
|
||||
result1 := validator.IsJSON("{}")
|
||||
result2 := validator.IsJSON("{\"name\": \"test\"}")
|
||||
result3 := validator.IsIntStr("")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
result3 := validator.IsJSON("")
|
||||
result4 := validator.IsJSON("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -689,42 +883,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsIntStr(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsIntStr("+3")
|
||||
result2 := validator.IsIntStr("-3")
|
||||
result3 := validator.IsIntStr("3.")
|
||||
result4 := validator.IsIntStr("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsIp">IsIp</span>
|
||||
|
||||
@@ -990,3 +1149,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
|
||||
}
|
||||
```
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -345,3 +346,15 @@ func MiMeType(file any) string {
|
||||
}
|
||||
return mediatype
|
||||
}
|
||||
|
||||
// CurrentPath return current absolute path.
|
||||
// Play: todo
|
||||
func CurrentPath() string {
|
||||
var absPath string
|
||||
_, filename, _, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
absPath = path.Dir(filename)
|
||||
}
|
||||
|
||||
return absPath
|
||||
}
|
||||
|
||||
@@ -175,11 +175,11 @@ func ExampleReadFileByLine() {
|
||||
}
|
||||
|
||||
func ExampleListFileNames() {
|
||||
fileList, _ := ListFileNames("../formatter/")
|
||||
fileList, _ := ListFileNames("./")
|
||||
fmt.Println(fileList)
|
||||
|
||||
// Output:
|
||||
// [formatter.go formatter_example_test.go formatter_test.go]
|
||||
// [file.go file_example_test.go file_test.go]
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
|
||||
@@ -235,9 +235,14 @@ func TestMiMeType(t *testing.T) {
|
||||
func TestListFileNames(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListFileNames")
|
||||
|
||||
filesInPath, err := ListFileNames("../formatter/")
|
||||
filesInPath, err := ListFileNames("./")
|
||||
assert.IsNil(err)
|
||||
|
||||
expected := []string{"formatter.go", "formatter_example_test.go", "formatter_test.go"}
|
||||
expected := []string{"file.go", "file_example_test.go", "file_test.go"}
|
||||
assert.Equal(expected, filesInPath)
|
||||
}
|
||||
|
||||
func TestCurrentPath(t *testing.T) {
|
||||
absPath := CurrentPath()
|
||||
t.Log(absPath)
|
||||
}
|
||||
|
||||
178
formatter/byte.go
Normal file
178
formatter/byte.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
//
|
||||
// code logic come from:
|
||||
// https://github.com/docker/go-units/blob/master/size.go
|
||||
|
||||
// http://en.wikipedia.org/wiki/Binary_prefix
|
||||
const (
|
||||
// Decimal
|
||||
UnitB = 1
|
||||
UnitKB = 1000
|
||||
UnitMB = 1000 * UnitKB
|
||||
UnitGB = 1000 * UnitMB
|
||||
UnitTB = 1000 * UnitGB
|
||||
UnitPB = 1000 * UnitTB
|
||||
UnitEB = 1000 * UnitPB
|
||||
|
||||
// Binary
|
||||
UnitBiB = 1
|
||||
UnitKiB = 1024
|
||||
UnitMiB = 1024 * UnitKiB
|
||||
UnitGiB = 1024 * UnitMiB
|
||||
UnitTiB = 1024 * UnitGiB
|
||||
UnitPiB = 1024 * UnitTiB
|
||||
UnitEiB = 1024 * UnitPiB
|
||||
)
|
||||
|
||||
// type byteUnitMap map[byte]int64
|
||||
|
||||
var (
|
||||
decimalByteMap = map[string]uint64{
|
||||
"b": UnitB,
|
||||
"kb": UnitKB,
|
||||
"mb": UnitMB,
|
||||
"gb": UnitGB,
|
||||
"tb": UnitTB,
|
||||
"pb": UnitPB,
|
||||
"eb": UnitEB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitB,
|
||||
"k": UnitKB,
|
||||
"m": UnitMB,
|
||||
"g": UnitGB,
|
||||
"t": UnitTB,
|
||||
"p": UnitPB,
|
||||
"e": UnitEB,
|
||||
}
|
||||
|
||||
binaryByteMap = map[string]uint64{
|
||||
"bi": UnitBiB,
|
||||
"kib": UnitKiB,
|
||||
"mib": UnitMiB,
|
||||
"gib": UnitGiB,
|
||||
"tib": UnitTiB,
|
||||
"pib": UnitPiB,
|
||||
"eib": UnitEiB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitBiB,
|
||||
"ki": UnitKiB,
|
||||
"mi": UnitMiB,
|
||||
"gi": UnitGiB,
|
||||
"ti": UnitTiB,
|
||||
"pi": UnitPiB,
|
||||
"ei": UnitEiB,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
decimalByteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||
binaryByteUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||
)
|
||||
|
||||
// DecimalBytes returns a human readable byte size under decimal standard (base 1000)
|
||||
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||
// Play: todo
|
||||
func DecimalBytes(size float64, precision ...int) string {
|
||||
p := 5
|
||||
if len(precision) > 0 {
|
||||
p = precision[0] + 1
|
||||
}
|
||||
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
|
||||
|
||||
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||
}
|
||||
|
||||
// BinaryBytes returns a human-readable byte size under binary standard (base 1024)
|
||||
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||
// Play: todo
|
||||
func BinaryBytes(size float64, precision ...int) string {
|
||||
p := 5
|
||||
if len(precision) > 0 {
|
||||
p = precision[0] + 1
|
||||
}
|
||||
size, unit := calculateByteSize(size, 1024.0, binaryByteUnits)
|
||||
|
||||
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||
}
|
||||
|
||||
func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) {
|
||||
i := 0
|
||||
unitsLimit := len(byteUnits) - 1
|
||||
for size >= base && i < unitsLimit {
|
||||
size = size / base
|
||||
i++
|
||||
}
|
||||
return size, byteUnits[i]
|
||||
}
|
||||
|
||||
// ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000).
|
||||
// ParseDecimalBytes("42 MB") -> 42000000, nil
|
||||
// Play: todo
|
||||
func ParseDecimalBytes(size string) (uint64, error) {
|
||||
return parseBytes(size, "decimal")
|
||||
}
|
||||
|
||||
// ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024).
|
||||
// ParseBinaryBytes("42 mib") -> 44040192, nil
|
||||
// Play: todo
|
||||
func ParseBinaryBytes(size string) (uint64, error) {
|
||||
return parseBytes(size, "binary")
|
||||
}
|
||||
|
||||
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
|
||||
func parseBytes(s string, kind string) (uint64, error) {
|
||||
lastDigit := 0
|
||||
hasComma := false
|
||||
for _, r := range s {
|
||||
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
||||
break
|
||||
}
|
||||
if r == ',' {
|
||||
hasComma = true
|
||||
}
|
||||
lastDigit++
|
||||
}
|
||||
|
||||
num := s[:lastDigit]
|
||||
if hasComma {
|
||||
num = strings.Replace(num, ",", "", -1)
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(num, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
|
||||
|
||||
if kind == "decimal" {
|
||||
if m, ok := decimalByteMap[extra]; ok {
|
||||
f *= float64(m)
|
||||
if f >= math.MaxUint64 {
|
||||
return 0, fmt.Errorf("too large: %v", s)
|
||||
}
|
||||
return uint64(f), nil
|
||||
}
|
||||
} else {
|
||||
if m, ok := binaryByteMap[extra]; ok {
|
||||
f *= float64(m)
|
||||
if f >= math.MaxUint64 {
|
||||
return 0, fmt.Errorf("too large: %v", s)
|
||||
}
|
||||
return uint64(f), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("unhandled size name: %v", extra)
|
||||
}
|
||||
87
formatter/byte_test.go
Normal file
87
formatter/byte_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestDecimalBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDecimalBytes")
|
||||
|
||||
assert.Equal("1KB", DecimalBytes(1000))
|
||||
assert.Equal("1.024KB", DecimalBytes(1024))
|
||||
assert.Equal("1.2346MB", DecimalBytes(1234567))
|
||||
assert.Equal("1.235MB", DecimalBytes(1234567, 3))
|
||||
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB)))
|
||||
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB)))
|
||||
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB)))
|
||||
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB)))
|
||||
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB)))
|
||||
}
|
||||
|
||||
func TestBinaryBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBinaryBytes")
|
||||
|
||||
assert.Equal("1KiB", BinaryBytes(1024))
|
||||
assert.Equal("1MiB", BinaryBytes(1024*1024))
|
||||
assert.Equal("1.1774MiB", BinaryBytes(1234567))
|
||||
assert.Equal("1.18MiB", BinaryBytes(1234567, 2))
|
||||
}
|
||||
|
||||
func TestParseDecimalBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestParseDecimalBytes")
|
||||
|
||||
cases := map[string]uint64{
|
||||
"12": uint64(12),
|
||||
"12 k": uint64(12000),
|
||||
"12 kb": uint64(12000),
|
||||
"12kb": uint64(12000),
|
||||
"12k": uint64(12000),
|
||||
"12K": uint64(12000),
|
||||
"12KB": uint64(12000),
|
||||
"12 K": uint64(12000),
|
||||
"12 KB": uint64(12000),
|
||||
"12 Kb": uint64(12000),
|
||||
"12 kB": uint64(12000),
|
||||
"12.2 KB": uint64(12200),
|
||||
}
|
||||
|
||||
for k, v := range cases {
|
||||
result, err := ParseDecimalBytes(k)
|
||||
assert.Equal(v, result)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
_, err := ParseDecimalBytes("12 AB")
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
func TestParseBinaryBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestParseBinaryBytes")
|
||||
|
||||
cases := map[string]uint64{
|
||||
"12": uint64(12),
|
||||
"12 ki": uint64(12288),
|
||||
"12 kib": uint64(12288),
|
||||
"12kib": uint64(12288),
|
||||
"12ki": uint64(12288),
|
||||
"12KI": uint64(12288),
|
||||
"12KIB": uint64(12288),
|
||||
"12KiB": uint64(12288),
|
||||
"12 Ki": uint64(12288),
|
||||
"12 KiB": uint64(12288),
|
||||
"12 Kib": uint64(12288),
|
||||
"12 kiB": uint64(12288),
|
||||
"12.2 KiB": uint64(12492),
|
||||
}
|
||||
|
||||
for k, v := range cases {
|
||||
result, err := ParseBinaryBytes(k)
|
||||
assert.Equal(v, result)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
_, err := ParseDecimalBytes("12 AB")
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
@@ -5,11 +5,13 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"io"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@@ -18,54 +20,49 @@ import (
|
||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||
// Play: https://go.dev/play/p/eRD5k2vzUVX
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
|
||||
s, err := numberToString(value)
|
||||
if err != nil {
|
||||
if validator.IsInt(value) {
|
||||
v, err := convertor.ToInt(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaInt(v)
|
||||
}
|
||||
|
||||
if validator.IsFloat(value) {
|
||||
v, err := convertor.ToFloat(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaFloat(v)
|
||||
}
|
||||
|
||||
if strutil.IsString(value) {
|
||||
v := fmt.Sprintf("%v", value)
|
||||
if validator.IsNumberStr(v) {
|
||||
return symbol + commaStr(v)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return symbol + commaString(s)
|
||||
return ""
|
||||
}
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
// Pretty data to JSON string.
|
||||
// Play: todo
|
||||
func Pretty(v any) (string, error) {
|
||||
out, err := json.MarshalIndent(v, "", " ")
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
func numberToString(value any) (string, error) {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
// PrettyToWriter pretty encode data to writer.
|
||||
// Play: todo
|
||||
func PrettyToWriter(v any, out io.Writer) error {
|
||||
enc := json.NewEncoder(out)
|
||||
enc.SetIndent("", " ")
|
||||
|
||||
// todo: need to handle 12345678.9 => 1.23456789e+07
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sv, nil
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return sv, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", nil
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package formatter
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleComma() {
|
||||
result1 := Comma("123", "")
|
||||
@@ -16,3 +19,115 @@ func ExampleComma() {
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
|
||||
func ExamplePretty() {
|
||||
result1, _ := Pretty([]string{"a", "b", "c"})
|
||||
result2, _ := Pretty(map[string]int{"a": 1})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [
|
||||
// "a",
|
||||
// "b",
|
||||
// "c"
|
||||
// ]
|
||||
// {
|
||||
// "a": 1
|
||||
// }
|
||||
}
|
||||
|
||||
func ExamplePrettyToWriter() {
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := PrettyToWriter(user, buf)
|
||||
|
||||
fmt.Println(buf)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// "name": "King",
|
||||
// "age": 10000
|
||||
// }
|
||||
//
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleDecimalBytes() {
|
||||
result1 := DecimalBytes(1000)
|
||||
result2 := DecimalBytes(1024)
|
||||
result3 := DecimalBytes(1234567)
|
||||
result4 := DecimalBytes(1234567, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KB
|
||||
// 1.024KB
|
||||
// 1.2346MB
|
||||
// 1.235MB
|
||||
}
|
||||
|
||||
func ExampleBinaryBytes() {
|
||||
result1 := BinaryBytes(1024)
|
||||
result2 := BinaryBytes(1024 * 1024)
|
||||
result3 := BinaryBytes(1234567)
|
||||
result4 := BinaryBytes(1234567, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KiB
|
||||
// 1MiB
|
||||
// 1.1774MiB
|
||||
// 1.18MiB
|
||||
}
|
||||
|
||||
func ExampleParseDecimalBytes() {
|
||||
result1, _ := ParseDecimalBytes("12")
|
||||
result2, _ := ParseDecimalBytes("12k")
|
||||
result3, _ := ParseDecimalBytes("12 Kb")
|
||||
result4, _ := ParseDecimalBytes("12.2 kb")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12000
|
||||
// 12000
|
||||
// 12200
|
||||
}
|
||||
|
||||
func ExampleParseBinaryBytes() {
|
||||
result1, _ := ParseBinaryBytes("12")
|
||||
result2, _ := ParseBinaryBytes("12ki")
|
||||
result3, _ := ParseBinaryBytes("12 KiB")
|
||||
result4, _ := ParseBinaryBytes("12.2 kib")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12288
|
||||
// 12288
|
||||
// 12492
|
||||
}
|
||||
|
||||
85
formatter/formatter_internal.go
Normal file
85
formatter/formatter_internal.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// see https://github.com/dustin/go-humanize/blob/master/comma.go
|
||||
func commaInt(v int64) string {
|
||||
sign := ""
|
||||
|
||||
// Min int64 can't be negated to a usable value, so it has to be special cased.
|
||||
if v == math.MinInt64 {
|
||||
return "-9,223,372,036,854,775,808"
|
||||
}
|
||||
|
||||
if v < 0 {
|
||||
sign = "-"
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
parts := []string{"", "", "", "", "", "", ""}
|
||||
j := len(parts) - 1
|
||||
|
||||
for v > 999 {
|
||||
parts[j] = strconv.FormatInt(v%1000, 10)
|
||||
switch len(parts[j]) {
|
||||
case 2:
|
||||
parts[j] = "0" + parts[j]
|
||||
case 1:
|
||||
parts[j] = "00" + parts[j]
|
||||
}
|
||||
v = v / 1000
|
||||
j--
|
||||
}
|
||||
parts[j] = strconv.Itoa(int(v))
|
||||
return sign + strings.Join(parts[j:], ",")
|
||||
}
|
||||
|
||||
func commaFloat(v float64) string {
|
||||
buf := &bytes.Buffer{}
|
||||
if v < 0 {
|
||||
buf.Write([]byte{'-'})
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
comma := []byte{','}
|
||||
|
||||
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
|
||||
pos := 0
|
||||
if len(parts[0])%3 != 0 {
|
||||
pos += len(parts[0]) % 3
|
||||
buf.WriteString(parts[0][:pos])
|
||||
buf.Write(comma)
|
||||
}
|
||||
for ; pos < len(parts[0]); pos += 3 {
|
||||
buf.WriteString(parts[0][pos : pos+3])
|
||||
buf.Write(comma)
|
||||
}
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
|
||||
if len(parts) > 1 {
|
||||
buf.Write([]byte{'.'})
|
||||
buf.WriteString(parts[1])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func commaStr(s string) string {
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return commaStrRecursive(s)
|
||||
}
|
||||
|
||||
func commaStrRecursive(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -16,12 +17,64 @@ func TestComma(t *testing.T) {
|
||||
assert.Equal("12,345", Comma("12345", ""))
|
||||
assert.Equal("12,345.6789", Comma("12345.6789", ""))
|
||||
assert.Equal("123,456,789,000", Comma("123456789000", ""))
|
||||
assert.Equal("12,345,678.9", Comma("12345678.9", ""))
|
||||
|
||||
assert.Equal("12,345", Comma(12345, ""))
|
||||
assert.Equal("$12,345", Comma(12345, "$"))
|
||||
assert.Equal("¥12,345", Comma(12345, "¥"))
|
||||
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
||||
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
|
||||
// assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||
assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||
assert.Equal("123,456,789,000", Comma(123456789000, ""))
|
||||
}
|
||||
|
||||
func TestPretty(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPretty")
|
||||
|
||||
cases := []any{
|
||||
"",
|
||||
"abc",
|
||||
123,
|
||||
[]string{"a", "b", "c"},
|
||||
map[string]int{"a": 1},
|
||||
struct {
|
||||
Abc int `json:"abc"`
|
||||
}{Abc: 123},
|
||||
}
|
||||
|
||||
expects := []string{
|
||||
"\"\"",
|
||||
`"abc"`,
|
||||
"123",
|
||||
"[\n \"a\",\n \"b\",\n \"c\"\n]",
|
||||
"{\n \"a\": 1\n}",
|
||||
"{\n \"abc\": 123\n}",
|
||||
}
|
||||
|
||||
for i, v := range cases {
|
||||
result, err := Pretty(v)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("result -> ", result)
|
||||
assert.Equal(expects[i], result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrettyToWriter(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPrettyToWriter")
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
expects := "{\n \"name\": \"King\",\n \"age\": 10000\n}\n"
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := PrettyToWriter(user, buf)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(expects, buf.String())
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -44,6 +45,52 @@ func (a *Assert) NotEqual(expected, actual any) {
|
||||
}
|
||||
}
|
||||
|
||||
// EqualValues asserts that two objects are equal or convertable to the same types and equal.
|
||||
// https://github.com/stretchr/testify/assert/assertions.go
|
||||
func (a *Assert) EqualValues(expected, actual any) {
|
||||
if !objectsAreEqualValues(expected, actual) {
|
||||
makeTestFailed(a.T, a.CaseName, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func objectsAreEqualValues(expected, actual interface{}) bool {
|
||||
if objectsAreEqual(expected, actual) {
|
||||
return true
|
||||
}
|
||||
|
||||
actualType := reflect.TypeOf(actual)
|
||||
if actualType == nil {
|
||||
return false
|
||||
}
|
||||
expectedValue := reflect.ValueOf(expected)
|
||||
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
||||
// Attempt comparison after type conversion
|
||||
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func objectsAreEqual(expected, actual interface{}) bool {
|
||||
if expected == nil || actual == nil {
|
||||
return expected == actual
|
||||
}
|
||||
|
||||
exp, ok := expected.([]byte)
|
||||
if !ok {
|
||||
return reflect.DeepEqual(expected, actual)
|
||||
}
|
||||
|
||||
act, ok := actual.([]byte)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if exp == nil || act == nil {
|
||||
return exp == nil && act == nil
|
||||
}
|
||||
return bytes.Equal(exp, act)
|
||||
}
|
||||
|
||||
// Greater check if expected is greate than actual
|
||||
func (a *Assert) Greater(expected, actual any) {
|
||||
if compare(expected, actual) != compareGreater {
|
||||
@@ -79,16 +126,18 @@ func (a *Assert) LessOrEqual(expected, actual any) {
|
||||
}
|
||||
|
||||
// IsNil check if value is nil
|
||||
func (a *Assert) IsNil(value any) {
|
||||
if value != nil {
|
||||
makeTestFailed(a.T, a.CaseName, nil, value)
|
||||
func (a *Assert) IsNil(v any) {
|
||||
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||
return
|
||||
}
|
||||
|
||||
makeTestFailed(a.T, a.CaseName, nil, v)
|
||||
}
|
||||
|
||||
// IsNotNil check if value is not nil
|
||||
func (a *Assert) IsNotNil(value any) {
|
||||
if value == nil {
|
||||
makeTestFailed(a.T, a.CaseName, "not nil", value)
|
||||
func (a *Assert) IsNotNil(v any) {
|
||||
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||
makeTestFailed(a.T, a.CaseName, "not nil", v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
51
internal/error_join.go
Normal file
51
internal/error_join.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package internal
|
||||
|
||||
// Note: this file is copyed from the go standart repo (https://github.com/golang/go/blob/master/src/errors/join.go).
|
||||
// just in order to adapt under go1.9
|
||||
// do not use it outside lancet lib.
|
||||
|
||||
// Join returns an error that wraps the given errors.
|
||||
// Any nil error values are discarded.
|
||||
// Join returns nil if errs contains no non-nil values.
|
||||
// The error formats as the concatenation of the strings obtained
|
||||
// by calling the Error method of each element of errs, with a newline
|
||||
// between each string.
|
||||
func JoinError(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &joinError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type joinError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *joinError) Error() string {
|
||||
var b []byte
|
||||
for i, err := range e.errs {
|
||||
if i > 0 {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
b = append(b, err.Error()...)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (e *joinError) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
@@ -397,3 +397,39 @@ func ExampleOmitByValues() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
|
||||
func ExampleMapTo() {
|
||||
type (
|
||||
Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Phone string `json:"phone"`
|
||||
Addr Address `json:"address"`
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street string `json:"street"`
|
||||
Number int `json:"number"`
|
||||
}
|
||||
)
|
||||
|
||||
personInfo := map[string]interface{}{
|
||||
"name": "Nothin",
|
||||
"age": 28,
|
||||
"phone": "123456789",
|
||||
"address": map[string]interface{}{
|
||||
"street": "test",
|
||||
"number": 1,
|
||||
},
|
||||
}
|
||||
|
||||
var p Person
|
||||
err := MapTo(personInfo, &p)
|
||||
|
||||
fmt.Println(err)
|
||||
fmt.Println(p)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
// {Nothin 28 123456789 {test 1}}
|
||||
}
|
||||
|
||||
180
maputil/typemap.go
Normal file
180
maputil/typemap.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var mapHandlers = map[reflect.Kind]func(reflect.Value, reflect.Value) error{
|
||||
reflect.String: convertNormal,
|
||||
reflect.Int: convertNormal,
|
||||
reflect.Int16: convertNormal,
|
||||
reflect.Int32: convertNormal,
|
||||
reflect.Int64: convertNormal,
|
||||
reflect.Uint: convertNormal,
|
||||
reflect.Uint16: convertNormal,
|
||||
reflect.Uint32: convertNormal,
|
||||
reflect.Uint64: convertNormal,
|
||||
reflect.Float32: convertNormal,
|
||||
reflect.Float64: convertNormal,
|
||||
reflect.Uint8: convertNormal,
|
||||
reflect.Int8: convertNormal,
|
||||
reflect.Struct: convertNormal,
|
||||
reflect.Complex64: convertNormal,
|
||||
reflect.Complex128: convertNormal,
|
||||
}
|
||||
|
||||
var _ = func() struct{} {
|
||||
mapHandlers[reflect.Map] = convertMap
|
||||
mapHandlers[reflect.Array] = convertSlice
|
||||
mapHandlers[reflect.Slice] = convertSlice
|
||||
return struct{}{}
|
||||
}()
|
||||
|
||||
// MapTo try to map any interface to struct or base type
|
||||
/*
|
||||
Eg:
|
||||
v := map[string]interface{}{
|
||||
"service":map[string]interface{}{
|
||||
"ip":"127.0.0.1",
|
||||
"port":1234,
|
||||
},
|
||||
version:"v1.0.01"
|
||||
}
|
||||
|
||||
type Target struct {
|
||||
Service struct {
|
||||
Ip string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
} `json:"service"`
|
||||
Ver string `json:"version"`
|
||||
}
|
||||
|
||||
var dist Target
|
||||
if err := maputil.MapTo(v,&dist); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println(dist)
|
||||
|
||||
*/
|
||||
func MapTo(src any, dst any) error {
|
||||
|
||||
dstRef := reflect.ValueOf(dst)
|
||||
if dstRef.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("dst is not ptr")
|
||||
}
|
||||
|
||||
dstRef = reflect.Indirect(dstRef)
|
||||
|
||||
srcRef := reflect.ValueOf(src)
|
||||
if srcRef.Kind() == reflect.Ptr || srcRef.Kind() == reflect.Interface {
|
||||
srcRef = srcRef.Elem()
|
||||
}
|
||||
if f, ok := mapHandlers[srcRef.Kind()]; ok {
|
||||
return f(srcRef, dstRef)
|
||||
}
|
||||
|
||||
return fmt.Errorf("no implemented:%s", srcRef.Type())
|
||||
}
|
||||
|
||||
func convertNormal(src reflect.Value, dst reflect.Value) error {
|
||||
if dst.CanSet() {
|
||||
if src.Type() == dst.Type() {
|
||||
dst.Set(src)
|
||||
} else if src.CanConvert(dst.Type()) {
|
||||
dst.Set(src.Convert(dst.Type()))
|
||||
} else {
|
||||
return fmt.Errorf("can not convert:%s:%s", src.Type().String(), dst.Type().String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertSlice(src reflect.Value, dst reflect.Value) error {
|
||||
if dst.Kind() != reflect.Array && dst.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("error type:%s", dst.Type().String())
|
||||
}
|
||||
l := src.Len()
|
||||
target := reflect.MakeSlice(dst.Type(), l, l)
|
||||
if dst.CanSet() {
|
||||
dst.Set(target)
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
srcValue := src.Index(i)
|
||||
if srcValue.Kind() == reflect.Ptr || srcValue.Kind() == reflect.Interface {
|
||||
srcValue = srcValue.Elem()
|
||||
}
|
||||
if f, ok := mapHandlers[srcValue.Kind()]; ok {
|
||||
err := f(srcValue, dst.Index(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertMap(src reflect.Value, dst reflect.Value) error {
|
||||
if src.Kind() != reflect.Map || dst.Kind() != reflect.Struct {
|
||||
if src.Kind() == reflect.Interface {
|
||||
return convertMap(src.Elem(), dst)
|
||||
} else {
|
||||
return fmt.Errorf("src or dst type error,%s,%s", src.Type().String(), dst.Type().String())
|
||||
}
|
||||
}
|
||||
dstType := dst.Type()
|
||||
num := dstType.NumField()
|
||||
exist := map[string]int{}
|
||||
for i := 0; i < num; i++ {
|
||||
k := dstType.Field(i).Tag.Get("json")
|
||||
if k == "" {
|
||||
k = dstType.Field(i).Name
|
||||
}
|
||||
if strings.Contains(k, ",") {
|
||||
taglist := strings.Split(k, ",")
|
||||
if taglist[0] == "" {
|
||||
|
||||
k = dstType.Field(i).Name
|
||||
} else {
|
||||
k = taglist[0]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
exist[k] = i
|
||||
}
|
||||
|
||||
keys := src.MapKeys()
|
||||
for _, key := range keys {
|
||||
if index, ok := exist[key.String()]; ok {
|
||||
v := dst.Field(index)
|
||||
if v.Kind() == reflect.Struct {
|
||||
err := convertMap(src.MapIndex(key), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if v.CanSet() {
|
||||
if v.Type() == src.MapIndex(key).Elem().Type() {
|
||||
v.Set(src.MapIndex(key).Elem())
|
||||
} else if src.MapIndex(key).Elem().CanConvert(v.Type()) {
|
||||
v.Set(src.MapIndex(key).Elem().Convert(v.Type()))
|
||||
} else if f, ok := mapHandlers[src.MapIndex(key).Elem().Kind()]; ok && f != nil {
|
||||
err := f(src.MapIndex(key).Elem(), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("error type:d(%s)s(%s)", v.Type(), src.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
111
maputil/typemap_test.go
Normal file
111
maputil/typemap_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
type (
|
||||
Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Phone string `json:"phone"`
|
||||
Addr Address `json:"address"`
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street string `json:"street"`
|
||||
Number int `json:"number"`
|
||||
}
|
||||
)
|
||||
|
||||
func TestStructType(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStructType")
|
||||
|
||||
src := map[string]interface{}{
|
||||
"name": "Nothin",
|
||||
"age": 28,
|
||||
"phone": "123456789",
|
||||
"address": map[string]interface{}{
|
||||
"street": "test",
|
||||
"number": 1,
|
||||
},
|
||||
}
|
||||
|
||||
var p Person
|
||||
err := MapTo(src, &p)
|
||||
assert.IsNil(err)
|
||||
assert.Equal(src["name"], p.Name)
|
||||
assert.Equal(src["age"], p.Age)
|
||||
assert.Equal(src["phone"], p.Phone)
|
||||
assert.Equal("test", p.Addr.Street)
|
||||
assert.Equal(1, p.Addr.Number)
|
||||
}
|
||||
|
||||
func TestBaseType(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBaseType")
|
||||
|
||||
tc := map[string]interface{}{
|
||||
"i32": -32,
|
||||
"i8": -8,
|
||||
"i16": -16,
|
||||
"i64": -64,
|
||||
"i": -1,
|
||||
"u32": 32,
|
||||
"u8": 8,
|
||||
"u16": 16,
|
||||
"u64": 64,
|
||||
"u": 1,
|
||||
"tf": true,
|
||||
"f32": 1.32,
|
||||
"f64": 1.64,
|
||||
"str": "hello mapto",
|
||||
"complex": 1 + 3i,
|
||||
}
|
||||
|
||||
type BaseType struct {
|
||||
I int `json:"i"`
|
||||
I8 int8 `json:"i8"`
|
||||
I16 int16 `json:"i16"`
|
||||
I32 int32 `json:"i32"`
|
||||
I64 int64 `json:"i64"`
|
||||
U uint `json:"u"`
|
||||
U8 uint8 `json:"u8"`
|
||||
U16 uint16 `json:"u16"`
|
||||
U32 uint32 `json:"u32"`
|
||||
U64 uint64 `json:"u64"`
|
||||
F32 float32 `json:"f32"`
|
||||
F64 float64 `json:"f64"`
|
||||
Tf bool `json:"tf"`
|
||||
Str string `json:"str"`
|
||||
Comp complex128 `json:"complex"`
|
||||
}
|
||||
|
||||
var dist BaseType
|
||||
err := MapTo(tc, &dist)
|
||||
assert.IsNil(err)
|
||||
|
||||
var number float64
|
||||
|
||||
MapTo(tc["i"], &number)
|
||||
assert.EqualValues(-1, number)
|
||||
MapTo(tc["i8"], &number)
|
||||
assert.EqualValues(-8, number)
|
||||
MapTo(tc["i16"], &number)
|
||||
assert.EqualValues(-16, number)
|
||||
MapTo(tc["i32"], &number)
|
||||
assert.EqualValues(-32, number)
|
||||
MapTo(tc["i64"], &number)
|
||||
assert.EqualValues(-64, number)
|
||||
MapTo(tc["u"], &number)
|
||||
assert.EqualValues(1, number)
|
||||
MapTo(tc["u8"], &number)
|
||||
assert.EqualValues(8, number)
|
||||
MapTo(tc["u16"], &number)
|
||||
assert.EqualValues(16, number)
|
||||
MapTo(tc["u32"], &number)
|
||||
assert.EqualValues(32, number)
|
||||
MapTo(tc["u64"], &number)
|
||||
assert.EqualValues(64, number)
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
}
|
||||
|
||||
// Range creates a slice of numbers from start with specified count, element step is 1.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/9ke2opxa8ZP
|
||||
func Range[T constraints.Integer | constraints.Float](start T, count int) []T {
|
||||
size := count
|
||||
if count < 0 {
|
||||
@@ -202,7 +202,7 @@ func Range[T constraints.Integer | constraints.Float](start T, count int) []T {
|
||||
}
|
||||
|
||||
// RangeWithStep creates a slice of numbers from start to end with specified step.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/akLWz0EqOSM
|
||||
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -216,3 +216,43 @@ func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// AngleToRadian converts angle value to radian value.
|
||||
// Play: https://go.dev/play/p/CIvlICqrHql
|
||||
func AngleToRadian(angle float64) float64 {
|
||||
radian := angle * (math.Pi / 180)
|
||||
return radian
|
||||
}
|
||||
|
||||
// RadianToAngle converts radian value to angle value.
|
||||
// Play: https://go.dev/play/p/dQtmOTUOMgi
|
||||
func RadianToAngle(radian float64) float64 {
|
||||
angle := radian * (180 / math.Pi)
|
||||
return angle
|
||||
}
|
||||
|
||||
// PointDistance get two points distance.
|
||||
// Play: https://go.dev/play/p/RrG4JIaziM8
|
||||
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: https://go.dev/play/p/Rdd8UTHZJ7u
|
||||
func IsPrime(n int) bool {
|
||||
if n < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
|
||||
if n%i == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package mathutil
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func ExampleExponent() {
|
||||
result1 := Exponent(10, 0)
|
||||
@@ -221,3 +224,60 @@ func ExampleRangeWithStep() {
|
||||
// [-4 -2 0]
|
||||
// [1 2.1 3.2]
|
||||
}
|
||||
|
||||
func ExampleAngleToRadian() {
|
||||
result1 := AngleToRadian(45)
|
||||
result2 := AngleToRadian(90)
|
||||
result3 := AngleToRadian(180)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.7853981633974483
|
||||
// 1.5707963267948966
|
||||
// 3.141592653589793
|
||||
}
|
||||
|
||||
func ExampleRadianToAngle() {
|
||||
result1 := RadianToAngle(math.Pi)
|
||||
result2 := RadianToAngle(math.Pi / 2)
|
||||
result3 := RadianToAngle(math.Pi / 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 180
|
||||
// 90
|
||||
// 45
|
||||
}
|
||||
|
||||
func ExamplePointDistance() {
|
||||
result1 := PointDistance(1, 1, 4, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleIsPrime() {
|
||||
result1 := IsPrime(-1)
|
||||
result2 := IsPrime(0)
|
||||
result3 := IsPrime(1)
|
||||
result4 := IsPrime(2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -139,7 +140,7 @@ func TestMinBy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "Range")
|
||||
assert := internal.NewAssert(t, "TestRange")
|
||||
|
||||
result1 := Range(1, 4)
|
||||
result2 := Range(1, -4)
|
||||
@@ -155,7 +156,7 @@ func TestRange(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRangeWithStep(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "Range")
|
||||
assert := internal.NewAssert(t, "TestRangeWithStep")
|
||||
|
||||
result1 := RangeWithStep(1, 4, 1)
|
||||
result2 := RangeWithStep(1, -1, 0)
|
||||
@@ -167,3 +168,46 @@ func TestRangeWithStep(t *testing.T) {
|
||||
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))
|
||||
}
|
||||
|
||||
279
promise/promise.go
Normal file
279
promise/promise.go
Normal file
@@ -0,0 +1,279 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package promise contains some functions to support async programming.
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
|
||||
// ref : chebyrash/promise (https://github.com/chebyrash/promise)
|
||||
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||
type Promise[T any] struct {
|
||||
runnable func(resolve func(T), reject func(error))
|
||||
result T
|
||||
err error
|
||||
|
||||
pending bool
|
||||
|
||||
mu *sync.Mutex
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// New create a new promise instance.
|
||||
func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T] {
|
||||
if runnable == nil {
|
||||
panic("runnable function should not be nil")
|
||||
}
|
||||
|
||||
p := &Promise[T]{
|
||||
runnable: runnable,
|
||||
pending: true,
|
||||
mu: &sync.Mutex{},
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
|
||||
defer p.run()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Promise[T]) run() {
|
||||
p.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if !p.pending {
|
||||
return
|
||||
}
|
||||
|
||||
if err := recover(); err != nil {
|
||||
p.reject(errors.New(fmt.Sprint(err)))
|
||||
}
|
||||
}()
|
||||
|
||||
p.runnable(p.resolve, p.reject)
|
||||
}()
|
||||
}
|
||||
|
||||
// Resolve returns a Promise that has been resolved with a given value.
|
||||
func Resolve[T any](resolution T) *Promise[T] {
|
||||
return &Promise[T]{
|
||||
result: resolution,
|
||||
pending: false,
|
||||
mu: &sync.Mutex{},
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Promise[T]) resolve(value T) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if !p.pending {
|
||||
return
|
||||
}
|
||||
|
||||
p.result = value
|
||||
p.pending = false
|
||||
|
||||
p.wg.Done()
|
||||
}
|
||||
|
||||
// Reject returns a Promise that has been rejected with a given error.
|
||||
func Reject[T any](err error) *Promise[T] {
|
||||
return &Promise[T]{
|
||||
err: err,
|
||||
pending: false,
|
||||
mu: &sync.Mutex{},
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Promise[T]) reject(err error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if !p.pending {
|
||||
return
|
||||
}
|
||||
|
||||
p.err = err
|
||||
p.pending = false
|
||||
|
||||
p.wg.Done()
|
||||
}
|
||||
|
||||
// Then allows chain calls to other promise methods.
|
||||
func Then[T1, T2 any](promise *Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
|
||||
return New(func(resolve2 func(T2), reject func(error)) {
|
||||
result, err := promise.Await()
|
||||
if err != nil {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
resolve2(resolve1(result))
|
||||
})
|
||||
}
|
||||
|
||||
// Then allows chain calls to other promise methods.
|
||||
func (p *Promise[T]) Then(resolve func(value T) T) *Promise[T] {
|
||||
return New(func(_resolve func(T), reject func(error)) {
|
||||
result, err := p.Await()
|
||||
if err != nil {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
_resolve(resolve(result))
|
||||
})
|
||||
}
|
||||
|
||||
// Catch allows to chain promises.
|
||||
func Catch[T any](promise *Promise[T], rejection func(err error) error) *Promise[T] {
|
||||
return New(func(resolve func(T), reject func(error)) {
|
||||
result, err := promise.Await()
|
||||
if err != nil {
|
||||
reject(rejection(err))
|
||||
return
|
||||
}
|
||||
resolve(result)
|
||||
})
|
||||
}
|
||||
|
||||
// Catch chain an existing promise with an intermediate reject function.
|
||||
func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] {
|
||||
return New(func(resolve func(T), rej func(error)) {
|
||||
resutl, err := p.Await()
|
||||
if err != nil {
|
||||
rej(reject(err))
|
||||
return
|
||||
}
|
||||
resolve(resutl)
|
||||
})
|
||||
}
|
||||
|
||||
// Await blocks until the 'runable' to finish execution.
|
||||
func (p *Promise[T]) Await() (T, error) {
|
||||
p.wg.Wait()
|
||||
return p.result, p.err
|
||||
}
|
||||
|
||||
type tuple[T1, T2 any] struct {
|
||||
_1 T1
|
||||
_2 T2
|
||||
}
|
||||
|
||||
// All resolves when all of the promises have resolved, reject immediately upon any of the input promises rejecting.
|
||||
func All[T any](promises []*Promise[T]) *Promise[[]T] {
|
||||
if len(promises) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return New(func(resolve func([]T), reject func(error)) {
|
||||
valsChan := make(chan tuple[T, int], len(promises))
|
||||
errsChan := make(chan error, 1)
|
||||
|
||||
for idx, p := range promises {
|
||||
idx := idx
|
||||
_ = Then(p, func(data T) T {
|
||||
valsChan <- tuple[T, int]{_1: data, _2: idx}
|
||||
return data
|
||||
})
|
||||
_ = Catch(p, func(err error) error {
|
||||
errsChan <- err
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
resolutions := make([]T, len(promises))
|
||||
for idx := 0; idx < len(promises); idx++ {
|
||||
select {
|
||||
case val := <-valsChan:
|
||||
resolutions[val._2] = val._1
|
||||
case err := <-errsChan:
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
resolve(resolutions)
|
||||
})
|
||||
}
|
||||
|
||||
// Race will settle the first fullfiled promise among muti promises.
|
||||
func Race[T any](promises []*Promise[T]) *Promise[T] {
|
||||
if len(promises) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return New(func(resolve func(T), reject func(error)) {
|
||||
valsChan := make(chan T, 1)
|
||||
errsChan := make(chan error, 1)
|
||||
|
||||
for _, p := range promises {
|
||||
_ = Then(p, func(data T) T {
|
||||
valsChan <- data
|
||||
return data
|
||||
})
|
||||
_ = Catch(p, func(err error) error {
|
||||
errsChan <- err
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
select {
|
||||
case val := <-valsChan:
|
||||
resolve(val)
|
||||
case err := <-errsChan:
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Any resolves as soon as any of the input's Promises resolve, with the value of the resolved Promise.
|
||||
// Any rejects if all of the given Promises are rejected with a combination of all errors.
|
||||
func Any[T any](promises []*Promise[T]) *Promise[T] {
|
||||
if len(promises) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return New(func(resolve func(T), reject func(error)) {
|
||||
valsChan := make(chan T, 1)
|
||||
errsChan := make(chan tuple[error, int], len(promises))
|
||||
|
||||
for idx, p := range promises {
|
||||
idx := idx
|
||||
_ = Then(p, func(data T) T {
|
||||
valsChan <- data
|
||||
return data
|
||||
})
|
||||
_ = Catch(p, func(err error) error {
|
||||
errsChan <- tuple[error, int]{_1: err, _2: idx}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
errs := make([]error, len(promises))
|
||||
for idx := 0; idx < len(promises); idx++ {
|
||||
select {
|
||||
case val := <-valsChan:
|
||||
resolve(val)
|
||||
return
|
||||
case err := <-errsChan:
|
||||
errs[err._2] = err._1
|
||||
}
|
||||
}
|
||||
|
||||
errCombo := errs[0]
|
||||
for _, err := range errs[1:] {
|
||||
errCombo = internal.JoinError(err)
|
||||
}
|
||||
|
||||
reject(errCombo)
|
||||
})
|
||||
}
|
||||
195
promise/promise_example_test.go
Normal file
195
promise/promise_example_test.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
p := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("hello")
|
||||
})
|
||||
|
||||
val, err := p.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(val)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleThen() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("hello ")
|
||||
})
|
||||
|
||||
p2 := Then(p1, func(s string) string {
|
||||
return s + "world"
|
||||
})
|
||||
|
||||
result, err := p2.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExamplePromise_Then() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("hello ")
|
||||
})
|
||||
|
||||
p2 := p1.Then(func(s string) string {
|
||||
return s + "world"
|
||||
})
|
||||
|
||||
result, err := p2.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleCatch() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
err := errors.New("error1")
|
||||
reject(err)
|
||||
})
|
||||
|
||||
p2 := Catch(p1, func(err error) error {
|
||||
e := errors.New("error2")
|
||||
return internal.JoinError(err, e)
|
||||
})
|
||||
|
||||
_, err := p1.Await()
|
||||
|
||||
fmt.Println(err.Error())
|
||||
|
||||
result2, err := p2.Await()
|
||||
|
||||
fmt.Println(result2)
|
||||
fmt.Println(err.Error())
|
||||
|
||||
// Output:
|
||||
// error1
|
||||
//
|
||||
// error1
|
||||
// error2
|
||||
}
|
||||
|
||||
func ExamplePromise_Catch() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
err := errors.New("error1")
|
||||
reject(err)
|
||||
})
|
||||
|
||||
p2 := p1.Catch(func(err error) error {
|
||||
e := errors.New("error2")
|
||||
return internal.JoinError(err, e)
|
||||
})
|
||||
|
||||
_, err := p1.Await()
|
||||
|
||||
fmt.Println(err.Error())
|
||||
|
||||
result2, err := p2.Await()
|
||||
|
||||
fmt.Println(result2)
|
||||
fmt.Println(err.Error())
|
||||
|
||||
// Output:
|
||||
// error1
|
||||
//
|
||||
// error1
|
||||
// error2
|
||||
}
|
||||
|
||||
func ExampleAll() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("a")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("b")
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("c")
|
||||
})
|
||||
|
||||
pms := []*Promise[string]{p1, p2, p3}
|
||||
p := All(pms)
|
||||
|
||||
result, err := p.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleAny() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
resolve("fast")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
resolve("slow")
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error"))
|
||||
})
|
||||
|
||||
pms := []*Promise[string]{p1, p2, p3}
|
||||
p := Any(pms)
|
||||
|
||||
result, err := p.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// fast
|
||||
}
|
||||
|
||||
func ExampleRace() {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
resolve("fast")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 300)
|
||||
resolve("slow")
|
||||
})
|
||||
|
||||
pms := []*Promise[string]{p1, p2}
|
||||
p := Race(pms)
|
||||
|
||||
result, err := p.Await()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// fast
|
||||
}
|
||||
302
promise/promise_test.go
Normal file
302
promise/promise_test.go
Normal file
@@ -0,0 +1,302 @@
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestResolve(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestResolve")
|
||||
|
||||
p := Resolve("abc")
|
||||
|
||||
assert.Equal("abc", p.result)
|
||||
assert.Equal(false, p.pending)
|
||||
}
|
||||
|
||||
func TestReject(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReject")
|
||||
|
||||
err := errors.New("error")
|
||||
p := Reject[string](err)
|
||||
|
||||
assert.Equal("error", p.err.Error())
|
||||
assert.Equal(false, p.pending)
|
||||
}
|
||||
|
||||
func TestThen(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestThen")
|
||||
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("abc")
|
||||
})
|
||||
|
||||
p2 := Then(p1, func(data string) string {
|
||||
return data + "de"
|
||||
})
|
||||
|
||||
val, err := p1.Await()
|
||||
assert.IsNil(err)
|
||||
assert.Equal("abc", val)
|
||||
|
||||
val, err = p2.Await()
|
||||
assert.IsNil(err)
|
||||
assert.Equal("abcde", val)
|
||||
}
|
||||
|
||||
func TestPromise_Then(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPromise_Then")
|
||||
|
||||
p1 := New(func(resolve func(int), reject func(error)) {
|
||||
resolve(1)
|
||||
})
|
||||
|
||||
p2 := p1.Then(func(n int) int {
|
||||
return n + 2
|
||||
})
|
||||
|
||||
val, err := p1.Await()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(1, val)
|
||||
|
||||
val, err = p2.Await()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(3, val)
|
||||
}
|
||||
|
||||
func TestCatch(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCatch")
|
||||
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
err := errors.New("error1")
|
||||
reject(err)
|
||||
})
|
||||
|
||||
p2 := Catch(p1, func(err error) error {
|
||||
e := errors.New("error2")
|
||||
return internal.JoinError(err, e)
|
||||
})
|
||||
|
||||
val, err := p1.Await()
|
||||
assert.Equal("", val)
|
||||
assert.IsNotNil(err)
|
||||
assert.Equal("error1", err.Error())
|
||||
|
||||
val, err = p2.Await()
|
||||
|
||||
assert.Equal("", val)
|
||||
assert.IsNotNil(err)
|
||||
assert.Equal("error1\nerror2", err.Error())
|
||||
}
|
||||
|
||||
func TestPromise_Catch(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPromise_Catch")
|
||||
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
err := errors.New("error1")
|
||||
reject(err)
|
||||
})
|
||||
|
||||
p2 := p1.Catch(func(err error) error {
|
||||
e := errors.New("error2")
|
||||
return internal.JoinError(err, e)
|
||||
})
|
||||
|
||||
val, err := p1.Await()
|
||||
assert.Equal("", val)
|
||||
assert.IsNotNil(err)
|
||||
assert.Equal("error1", err.Error())
|
||||
|
||||
val, err = p2.Await()
|
||||
|
||||
assert.Equal("", val)
|
||||
assert.IsNotNil(err)
|
||||
assert.Equal("error1\nerror2", err.Error())
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPromise_All")
|
||||
|
||||
t.Run("AllPromisesFullfilled", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("a")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("b")
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("c")
|
||||
})
|
||||
|
||||
p := All([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
val, err := p.Await()
|
||||
assert.Equal([]string{"a", "b", "c"}, val)
|
||||
assert.IsNil(err)
|
||||
})
|
||||
|
||||
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||
var empty = []*Promise[any]{}
|
||||
p := All(empty)
|
||||
assert.IsNil(p)
|
||||
})
|
||||
|
||||
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
resolve("a")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error1"))
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error2"))
|
||||
})
|
||||
|
||||
p := All([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
_, err := p.Await()
|
||||
|
||||
assert.IsNotNil(err)
|
||||
// assert.Equal("error1", err.Error())
|
||||
})
|
||||
|
||||
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error1"))
|
||||
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error2"))
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error3"))
|
||||
})
|
||||
|
||||
p := All([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
_, err := p.Await()
|
||||
|
||||
assert.IsNotNil(err)
|
||||
// assert.Equal("error1", err.Error())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPromise_Any")
|
||||
|
||||
t.Run("AnyFullfilled", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
resolve("fast")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
resolve("slow")
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error"))
|
||||
})
|
||||
|
||||
p := Any([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
val, err := p.Await()
|
||||
assert.Equal("fast", val)
|
||||
assert.IsNil(err)
|
||||
})
|
||||
|
||||
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||
var empty = []*Promise[any]{}
|
||||
p := Any(empty)
|
||||
assert.IsNil(p)
|
||||
})
|
||||
|
||||
t.Run("OnlyRejected", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error1"))
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error2"))
|
||||
})
|
||||
|
||||
p := Any([]*Promise[string]{p1, p2})
|
||||
|
||||
_, err := p.Await()
|
||||
|
||||
assert.IsNotNil(err)
|
||||
// assert.Equal("error1", err.Error())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRace(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPromise_Race")
|
||||
|
||||
t.Run("PromisesFullfilled", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
resolve("a")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 300)
|
||||
resolve("b")
|
||||
})
|
||||
|
||||
p := Race([]*Promise[string]{p1, p2})
|
||||
|
||||
val, err := p.Await()
|
||||
assert.Equal("a", val)
|
||||
assert.IsNil(err)
|
||||
})
|
||||
|
||||
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||
var empty = []*Promise[any]{}
|
||||
p := Race(empty)
|
||||
assert.IsNil(p)
|
||||
})
|
||||
|
||||
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
resolve("a")
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error1"))
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error2"))
|
||||
})
|
||||
|
||||
p := Race([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
val, err := p.Await()
|
||||
|
||||
assert.IsNotNil(err)
|
||||
// assert.Equal("error1", err.Error())
|
||||
assert.Equal("", val)
|
||||
})
|
||||
|
||||
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||
p1 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error1"))
|
||||
|
||||
})
|
||||
p2 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error2"))
|
||||
})
|
||||
p3 := New(func(resolve func(string), reject func(error)) {
|
||||
reject(errors.New("error3"))
|
||||
})
|
||||
|
||||
p := Race([]*Promise[string]{p1, p2, p3})
|
||||
|
||||
_, err := p.Await()
|
||||
|
||||
assert.IsNotNil(err)
|
||||
// assert.Equal("error1", err.Error())
|
||||
})
|
||||
|
||||
}
|
||||
@@ -422,12 +422,12 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
}
|
||||
|
||||
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||
// when iteratee return true, will break the for each loop.
|
||||
// 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) {
|
||||
loop:
|
||||
for i, v := range slice {
|
||||
if !iteratee(i, v) {
|
||||
break loop
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -492,6 +492,30 @@ func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initia
|
||||
return result
|
||||
}
|
||||
|
||||
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
|
||||
// Play: todo
|
||||
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
|
||||
accumulator := initial
|
||||
|
||||
for i, v := range slice {
|
||||
accumulator = reducer(i, v, accumulator)
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}
|
||||
|
||||
// ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.
|
||||
// Play: todo
|
||||
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
|
||||
accumulator := initial
|
||||
|
||||
for i := len(slice) - 1; i >= 0; i-- {
|
||||
accumulator = reducer(i, slice[i], accumulator)
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}
|
||||
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/P5mZp7IhOFo
|
||||
func Replace[T comparable](slice []T, old T, new T, n int) []T {
|
||||
@@ -1094,7 +1118,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
|
||||
}
|
||||
|
||||
@@ -460,6 +460,34 @@ func ExampleReduce() {
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleReduceBy() {
|
||||
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||
return agg + item
|
||||
})
|
||||
|
||||
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1234
|
||||
}
|
||||
|
||||
func ExampleReduceRight() {
|
||||
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 4321
|
||||
}
|
||||
|
||||
func ExampleReplace() {
|
||||
strs := []string{"a", "b", "c", "a"}
|
||||
|
||||
|
||||
@@ -405,6 +405,32 @@ func TestReduce(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReduceBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReduceBy")
|
||||
|
||||
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||
return agg + item
|
||||
})
|
||||
|
||||
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
assert.Equal(10, result1)
|
||||
assert.Equal("1234", result2)
|
||||
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "ReduceRight")
|
||||
|
||||
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
})
|
||||
|
||||
assert.Equal("4321", result)
|
||||
}
|
||||
|
||||
func TestIntSlice(t *testing.T) {
|
||||
var nums []any
|
||||
nums = append(nums, 1, 2, 3)
|
||||
@@ -665,8 +691,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
|
||||
}
|
||||
@@ -873,8 +899,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"))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package stream implements a sequence of elements supporting sequential and parallel aggregate operations.
|
||||
// this package is an experiment to explore if stream in go can work as the way java does. it's complete, but not
|
||||
// powerful like other libs
|
||||
// Package stream implements a sequence of elements supporting sequential and operations.
|
||||
// this package is an experiment to explore if stream in go can work as the way java does. its function is very limited.
|
||||
package stream
|
||||
|
||||
import (
|
||||
@@ -52,13 +51,14 @@ type stream[T any] struct {
|
||||
source []T
|
||||
}
|
||||
|
||||
// Of creates a stream stream whose elements are the specified values.
|
||||
// Of creates a stream whose elements are the specified values.
|
||||
// Play: https://go.dev/play/p/jI6_iZZuVFE
|
||||
func Of[T any](elems ...T) stream[T] {
|
||||
return FromSlice(elems)
|
||||
}
|
||||
|
||||
// Generate stream where each element is generated by the provided generater function
|
||||
// generater function: func() func() (item T, ok bool) {}
|
||||
// Play: https://go.dev/play/p/rkOWL1yA3j9
|
||||
func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
||||
source := make([]T, 0)
|
||||
|
||||
@@ -75,11 +75,13 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
|
||||
}
|
||||
|
||||
// FromSlice creates stream from slice.
|
||||
// Play: https://go.dev/play/p/wywTO0XZtI4
|
||||
func FromSlice[T any](source []T) stream[T] {
|
||||
return stream[T]{source: source}
|
||||
}
|
||||
|
||||
// FromChannel creates stream from channel.
|
||||
// Play: https://go.dev/play/p/9TZYugGMhXZ
|
||||
func FromChannel[T any](source <-chan T) stream[T] {
|
||||
s := make([]T, 0)
|
||||
|
||||
@@ -91,6 +93,7 @@ func FromChannel[T any](source <-chan T) stream[T] {
|
||||
}
|
||||
|
||||
// FromRange creates a number stream from start to end. both start and end are included. [start, end]
|
||||
// Play: https://go.dev/play/p/9Ex1-zcg-B-
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T] {
|
||||
if end < start {
|
||||
panic("stream.FromRange: param start should be before param end")
|
||||
@@ -109,6 +112,7 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
|
||||
}
|
||||
|
||||
// Concat creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
|
||||
// Play: https://go.dev/play/p/HM4OlYk_OUC
|
||||
func Concat[T any](a, b stream[T]) stream[T] {
|
||||
source := make([]T, 0)
|
||||
|
||||
@@ -119,6 +123,7 @@ func Concat[T any](a, b stream[T]) stream[T] {
|
||||
}
|
||||
|
||||
// Distinct returns a stream that removes the duplicated items.
|
||||
// Play: https://go.dev/play/p/eGkOSrm64cB
|
||||
func (s stream[T]) Distinct() stream[T] {
|
||||
source := make([]T, 0)
|
||||
|
||||
@@ -147,6 +152,7 @@ func hashKey(data any) string {
|
||||
}
|
||||
|
||||
// Filter returns a stream consisting of the elements of this stream that match the given predicate.
|
||||
// Play: https://go.dev/play/p/MFlSANo-buc
|
||||
func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
|
||||
source := make([]T, 0)
|
||||
|
||||
@@ -160,6 +166,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.
|
||||
// Play: https://go.dev/play/p/OtNQUImdYko
|
||||
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
||||
source := make([]T, s.Count())
|
||||
|
||||
@@ -171,6 +178,7 @@ func (s stream[T]) Map(mapper func(item T) T) stream[T] {
|
||||
}
|
||||
|
||||
// Peek returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
|
||||
// Play: https://go.dev/play/p/u1VNzHs6cb2
|
||||
func (s stream[T]) Peek(consumer func(item T)) stream[T] {
|
||||
for _, v := range s.source {
|
||||
consumer(v)
|
||||
@@ -181,6 +189,7 @@ func (s stream[T]) Peek(consumer func(item T)) stream[T] {
|
||||
|
||||
// Skip returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
|
||||
// If this stream contains fewer than n elements then an empty stream will be returned.
|
||||
// Play: https://go.dev/play/p/fNdHbqjahum
|
||||
func (s stream[T]) Skip(n int) stream[T] {
|
||||
if n <= 0 {
|
||||
return s
|
||||
@@ -201,6 +210,7 @@ func (s stream[T]) Skip(n int) stream[T] {
|
||||
}
|
||||
|
||||
// Limit returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
|
||||
// Play: https://go.dev/play/p/qsO4aniDcGf
|
||||
func (s stream[T]) Limit(maxSize int) stream[T] {
|
||||
if s.source == nil {
|
||||
return s
|
||||
@@ -220,6 +230,7 @@ func (s stream[T]) Limit(maxSize int) stream[T] {
|
||||
}
|
||||
|
||||
// AllMatch returns whether all elements of this stream match the provided predicate.
|
||||
// Play: https://go.dev/play/p/V5TBpVRs-Cx
|
||||
func (s stream[T]) AllMatch(predicate func(item T) bool) bool {
|
||||
for _, v := range s.source {
|
||||
if !predicate(v) {
|
||||
@@ -231,6 +242,7 @@ func (s stream[T]) AllMatch(predicate func(item T) bool) bool {
|
||||
}
|
||||
|
||||
// AnyMatch returns whether any elements of this stream match the provided predicate.
|
||||
// Play: https://go.dev/play/p/PTCnWn4OxSn
|
||||
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool {
|
||||
for _, v := range s.source {
|
||||
if predicate(v) {
|
||||
@@ -242,11 +254,13 @@ func (s stream[T]) AnyMatch(predicate func(item T) bool) bool {
|
||||
}
|
||||
|
||||
// NoneMatch returns whether no elements of this stream match the provided predicate.
|
||||
// Play: https://go.dev/play/p/iWS64pL1oo3
|
||||
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool {
|
||||
return !s.AnyMatch(predicate)
|
||||
}
|
||||
|
||||
// ForEach performs an action for each element of this stream.
|
||||
// Play: https://go.dev/play/p/Dsm0fPqcidk
|
||||
func (s stream[T]) ForEach(action func(item T)) {
|
||||
for _, v := range s.source {
|
||||
action(v)
|
||||
@@ -254,20 +268,23 @@ func (s stream[T]) ForEach(action func(item T)) {
|
||||
}
|
||||
|
||||
// Reduce performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
|
||||
func (s stream[T]) Reduce(init T, accumulator func(a, b T) T) T {
|
||||
// Play: https://go.dev/play/p/6uzZjq_DJLU
|
||||
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T {
|
||||
for _, v := range s.source {
|
||||
init = accumulator(init, v)
|
||||
initial = accumulator(initial, v)
|
||||
}
|
||||
|
||||
return init
|
||||
return initial
|
||||
}
|
||||
|
||||
// Count returns the count of elements in the stream.
|
||||
// Play: https://go.dev/play/p/r3koY6y_Xo-
|
||||
func (s stream[T]) Count() int {
|
||||
return len(s.source)
|
||||
}
|
||||
|
||||
// FindFirst returns the first element of this stream and true, or zero value and false if the stream is empty.
|
||||
// Play: https://go.dev/play/p/9xEf0-6C1e3
|
||||
func (s stream[T]) FindFirst() (T, bool) {
|
||||
var result T
|
||||
|
||||
@@ -279,6 +296,7 @@ func (s stream[T]) FindFirst() (T, bool) {
|
||||
}
|
||||
|
||||
// Reverse returns a stream whose elements are reverse order of given stream.
|
||||
// Play: https://go.dev/play/p/A8_zkJnLHm4
|
||||
func (s stream[T]) Reverse() stream[T] {
|
||||
l := len(s.source)
|
||||
source := make([]T, l)
|
||||
@@ -290,6 +308,7 @@ func (s stream[T]) Reverse() stream[T] {
|
||||
}
|
||||
|
||||
// Range returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
|
||||
// Play: https://go.dev/play/p/indZY5V2f4j
|
||||
func (s stream[T]) Range(start, end int) stream[T] {
|
||||
if start < 0 {
|
||||
start = 0
|
||||
@@ -315,6 +334,7 @@ func (s stream[T]) Range(start, end int) stream[T] {
|
||||
}
|
||||
|
||||
// Sorted returns a stream consisting of the elements of this stream, sorted according to the provided less function.
|
||||
// Play: https://go.dev/play/p/XXtng5uonFj
|
||||
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
|
||||
source := []T{}
|
||||
source = append(source, s.source...)
|
||||
@@ -326,6 +346,7 @@ func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
|
||||
|
||||
// Max returns the maximum element of this stream according to the provided less function.
|
||||
// less: a > b
|
||||
// Play: https://go.dev/play/p/fm-1KOPtGzn
|
||||
func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
|
||||
var max T
|
||||
|
||||
@@ -343,6 +364,7 @@ func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
|
||||
|
||||
// Min returns the minimum element of this stream according to the provided less function.
|
||||
// less: a < b
|
||||
// Play: https://go.dev/play/p/vZfIDgGNRe_0
|
||||
func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
||||
var min T
|
||||
|
||||
@@ -360,6 +382,7 @@ func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
|
||||
}
|
||||
|
||||
// ToSlice return the elements in the stream.
|
||||
// Play: https://go.dev/play/p/jI6_iZZuVFE
|
||||
func (s stream[T]) ToSlice() []T {
|
||||
return s.source
|
||||
}
|
||||
|
||||
373
stream/stream_example_test.go
Normal file
373
stream/stream_example_test.go
Normal file
@@ -0,0 +1,373 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleOf() {
|
||||
s := Of(1, 2, 3)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleFromSlice() {
|
||||
s := FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleFromChannel() {
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
for i := 1; i < 4; i++ {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
s := FromChannel(ch)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleFromRange() {
|
||||
s := FromRange(1, 5, 1)
|
||||
|
||||
data := s.ToSlice()
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleGenerate() {
|
||||
n := 0
|
||||
max := 4
|
||||
|
||||
generator := func() func() (int, bool) {
|
||||
return func() (int, bool) {
|
||||
n++
|
||||
return n, n < max
|
||||
}
|
||||
}
|
||||
|
||||
s := Generate(generator)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleConcat() {
|
||||
s1 := FromSlice([]int{1, 2, 3})
|
||||
s2 := FromSlice([]int{4, 5, 6})
|
||||
|
||||
s := Concat(s1, s2)
|
||||
|
||||
data := s.ToSlice()
|
||||
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleStream_Distinct() {
|
||||
original := FromSlice([]int{1, 2, 2, 3, 3, 3})
|
||||
distinct := original.Distinct()
|
||||
|
||||
data1 := original.ToSlice()
|
||||
data2 := distinct.ToSlice()
|
||||
|
||||
fmt.Println(data1)
|
||||
fmt.Println(data2)
|
||||
|
||||
// Output:
|
||||
// [1 2 2 3 3 3]
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleStream_Filter() {
|
||||
original := FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
isEven := func(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
even := original.Filter(isEven)
|
||||
|
||||
fmt.Println(even.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
}
|
||||
|
||||
func ExampleStream_Map() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
addOne := func(n int) int {
|
||||
return n + 1
|
||||
}
|
||||
|
||||
increament := original.Map(addOne)
|
||||
|
||||
fmt.Println(increament.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
|
||||
func ExampleStream_Peek() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
data := []string{}
|
||||
peekStream := original.Peek(func(n int) {
|
||||
data = append(data, fmt.Sprint("value", n))
|
||||
})
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(peekStream.ToSlice())
|
||||
fmt.Println(data)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [1 2 3]
|
||||
// [value1 value2 value3]
|
||||
}
|
||||
|
||||
func ExampleStream_Skip() {
|
||||
original := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Skip(-1)
|
||||
s2 := original.Skip(0)
|
||||
s3 := original.Skip(1)
|
||||
s4 := original.Skip(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [1 2 3 4]
|
||||
// [2 3 4]
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleStream_Limit() {
|
||||
original := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := original.Limit(-1)
|
||||
s2 := original.Limit(0)
|
||||
s3 := original.Limit(1)
|
||||
s4 := original.Limit(5)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
|
||||
func ExampleStream_AllMatch() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AllMatch(func(item int) bool {
|
||||
return item > 0
|
||||
})
|
||||
|
||||
result2 := original.AllMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleStream_AnyMatch() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.AnyMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
result2 := original.AnyMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleStream_NoneMatch() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result1 := original.NoneMatch(func(item int) bool {
|
||||
return item > 3
|
||||
})
|
||||
|
||||
result2 := original.NoneMatch(func(item int) bool {
|
||||
return item > 1
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleStream_ForEach() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := 0
|
||||
original.ForEach(func(item int) {
|
||||
result += item
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleStream_Reduce() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result := original.Reduce(0, func(a, b int) int {
|
||||
return a + b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleStream_FindFirst() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
result, ok := original.FindFirst()
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleStream_Reverse() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
reverse := original.Reverse()
|
||||
|
||||
fmt.Println(reverse.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [3 2 1]
|
||||
}
|
||||
|
||||
func ExampleStream_Range() {
|
||||
original := FromSlice([]int{1, 2, 3})
|
||||
|
||||
s1 := original.Range(0, 0)
|
||||
s2 := original.Range(0, 1)
|
||||
s3 := original.Range(0, 3)
|
||||
s4 := original.Range(1, 2)
|
||||
|
||||
fmt.Println(s1.ToSlice())
|
||||
fmt.Println(s2.ToSlice())
|
||||
fmt.Println(s3.ToSlice())
|
||||
fmt.Println(s4.ToSlice())
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [1]
|
||||
// [1 2 3]
|
||||
// [2]
|
||||
}
|
||||
|
||||
func ExampleStream_Sorted() {
|
||||
original := FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
sorted := original.Sorted(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(original.ToSlice())
|
||||
fmt.Println(sorted.ToSlice())
|
||||
|
||||
// Output:
|
||||
// [4 2 1 3]
|
||||
// [1 2 3 4]
|
||||
}
|
||||
|
||||
func ExampleStream_Max() {
|
||||
original := FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
max, ok := original.Max(func(a, b int) bool { return a > b })
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleStream_Min() {
|
||||
original := FromSlice([]int{4, 2, 1, 3})
|
||||
|
||||
min, ok := original.Min(func(a, b int) bool { return a < b })
|
||||
|
||||
fmt.Println(min)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleStream_Count() {
|
||||
s1 := FromSlice([]int{1, 2, 3})
|
||||
s2 := FromSlice([]int{})
|
||||
|
||||
fmt.Println(s1.Count())
|
||||
fmt.Println(s2.Count())
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
@@ -147,13 +147,17 @@ func TestStream_Peek(t *testing.T) {
|
||||
func TestStream_Skip(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_Peek")
|
||||
|
||||
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
|
||||
stream := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
s1 := stream.Skip(-1)
|
||||
s2 := stream.Skip(0)
|
||||
s3 := stream.Skip(1)
|
||||
s4 := stream.Skip(2)
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s1.ToSlice())
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s2.ToSlice())
|
||||
assert.Equal([]int{1, 2, 3, 4}, s1.ToSlice())
|
||||
assert.Equal([]int{1, 2, 3, 4}, s2.ToSlice())
|
||||
assert.Equal([]int{2, 3, 4}, s3.ToSlice())
|
||||
assert.Equal([]int{3, 4}, s4.ToSlice())
|
||||
}
|
||||
|
||||
func TestStream_Limit(t *testing.T) {
|
||||
@@ -248,6 +252,16 @@ func TestStream_Reduce(t *testing.T) {
|
||||
assert.Equal(6, result)
|
||||
}
|
||||
|
||||
func TestStream_Count(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_Count")
|
||||
|
||||
s1 := FromSlice([]int{1, 2, 3})
|
||||
s2 := FromSlice([]int{})
|
||||
|
||||
assert.Equal(3, s1.Count())
|
||||
assert.Equal(0, s2.Count())
|
||||
}
|
||||
|
||||
func TestStream_FindFirst(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStream_FindFirst")
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package structs provide several high level functions to manipulate struct, tag, and field.
|
||||
package structs
|
||||
|
||||
import (
|
||||
|
||||
@@ -360,3 +360,16 @@ func WordCount(s string) int {
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// RemoveNonPrintable remove non-printable characters from a string.
|
||||
// Play: https://go.dev/play/p/og47F5x_jTZ
|
||||
func RemoveNonPrintable(str string) string {
|
||||
result := strings.Map(func(r rune) rune {
|
||||
if unicode.IsPrint(r) {
|
||||
return r
|
||||
}
|
||||
return -1
|
||||
}, str)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -438,3 +438,14 @@ func ExampleWordCount() {
|
||||
// 0
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleRemoveNonPrintable() {
|
||||
result1 := RemoveNonPrintable("hello\u00a0 \u200bworld\n")
|
||||
result2 := RemoveNonPrintable("你好😄")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// hello world
|
||||
// 你好😄
|
||||
}
|
||||
|
||||
@@ -342,3 +342,10 @@ func TestWordCount(t *testing.T) {
|
||||
assert.Equal(v, WordCount(k))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveNonPrintable(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRemoveNonPrintable")
|
||||
|
||||
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
|
||||
assert.Equal("你好😄", RemoveNonPrintable("你好😄"))
|
||||
}
|
||||
|
||||
12
system/os.go
12
system/os.go
@@ -15,6 +15,10 @@ import (
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
|
||||
// IsWindows check if current os is windows.
|
||||
// Play: https://go.dev/play/p/XzJULbzmf9m
|
||||
func IsWindows() bool {
|
||||
@@ -66,7 +70,7 @@ func CompareOsEnv(key, comparedEnv string) bool {
|
||||
// in linux, use /bin/bash -c to execute command
|
||||
// in windows, use powershell.exe to execute command
|
||||
// Play: https://go.dev/play/p/n-2fLyZef-4
|
||||
func ExecCommand(command string) (stdout, stderr string, err error) {
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error) {
|
||||
var out bytes.Buffer
|
||||
var errOut bytes.Buffer
|
||||
|
||||
@@ -74,6 +78,12 @@ func ExecCommand(command string) (stdout, stderr string, err error) {
|
||||
if IsWindows() {
|
||||
cmd = exec.Command("powershell.exe", command)
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(cmd)
|
||||
}
|
||||
}
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &errOut
|
||||
|
||||
|
||||
18
system/os_linux.go
Normal file
18
system/os_linux.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func WithForeground() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
if c.SysProcAttr == nil {
|
||||
c.SysProcAttr = &syscall.SysProcAttr{
|
||||
Foreground: true,
|
||||
}
|
||||
} else {
|
||||
c.SysProcAttr.Foreground = true
|
||||
}
|
||||
}
|
||||
}
|
||||
18
system/os_windows.go
Normal file
18
system/os_windows.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func WithWinHide() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
if c.SysProcAttr == nil {
|
||||
c.SysProcAttr = &syscall.SysProcAttr{
|
||||
HideWindow: true,
|
||||
}
|
||||
} else {
|
||||
c.SysProcAttr.HideWindow = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,31 @@ func IsAllLower(str string) bool {
|
||||
return str != ""
|
||||
}
|
||||
|
||||
// IsASCII checks if string is all ASCII char.
|
||||
// Play: https://go.dev/play/p/hfQNPLX0jNa
|
||||
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: https://go.dev/play/p/Pe1FE2gdtTP
|
||||
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 {
|
||||
@@ -87,7 +112,7 @@ func ContainLetter(str string) bool {
|
||||
}
|
||||
|
||||
// IsJSON checks if the string is valid JSON.
|
||||
// Play: https://go.dev/play/p/sRS6c4K8jGk
|
||||
// Play: https://go.dev/play/p/8Kip1Itjiil
|
||||
func IsJSON(str string) bool {
|
||||
var js json.RawMessage
|
||||
return json.Unmarshal([]byte(str), &js) == nil
|
||||
@@ -344,3 +369,29 @@ func IsGBK(data []byte) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsNumberStr check if the value is number(integer, float) or not.
|
||||
// Play: todo
|
||||
func IsNumber(v any) bool {
|
||||
return IsInt(v) || IsFloat(v)
|
||||
}
|
||||
|
||||
// IsFloat check if the value is float(float32, float34) or not.
|
||||
// Play: todo
|
||||
func IsFloat(v any) bool {
|
||||
switch v.(type) {
|
||||
case float32, float64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsInt check if the value is integer(int, unit) or not.
|
||||
// Play: todo
|
||||
func IsInt(v any) bool {
|
||||
switch v.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -285,8 +285,8 @@ func ExampleIsIntStr() {
|
||||
func ExampleIsJSON() {
|
||||
result1 := IsJSON("{}")
|
||||
result2 := IsJSON("{\"name\": \"test\"}")
|
||||
result3 := IsIntStr("")
|
||||
result4 := IsIntStr("abc")
|
||||
result3 := IsJSON("")
|
||||
result4 := IsJSON("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -407,3 +407,99 @@ 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
|
||||
}
|
||||
|
||||
func ExampleIsInt() {
|
||||
result1 := IsInt("")
|
||||
result2 := IsInt("3")
|
||||
result3 := IsInt(0.1)
|
||||
result4 := IsInt(0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsFloat() {
|
||||
result1 := IsFloat("")
|
||||
result2 := IsFloat("3")
|
||||
result3 := IsFloat(0)
|
||||
result4 := IsFloat(0.1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsNumber() {
|
||||
result1 := IsNumber("")
|
||||
result2 := IsNumber("3")
|
||||
result3 := IsNumber(0)
|
||||
result4 := IsNumber(0.1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -100,6 +100,34 @@ func TestIsJSON(t *testing.T) {
|
||||
assert.Equal(false, IsJSON("&@#$%^&*"))
|
||||
}
|
||||
|
||||
func TestIsNumber(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsNumber")
|
||||
|
||||
assert.Equal(false, IsNumber(""))
|
||||
assert.Equal(false, IsNumber("3"))
|
||||
assert.Equal(true, IsNumber(0))
|
||||
assert.Equal(true, IsNumber(0.1))
|
||||
}
|
||||
|
||||
func TestIsFloat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsFloat")
|
||||
|
||||
assert.Equal(false, IsFloat(""))
|
||||
assert.Equal(false, IsFloat("3"))
|
||||
assert.Equal(false, IsFloat(0))
|
||||
assert.Equal(true, IsFloat(0.1))
|
||||
}
|
||||
|
||||
func TestIsInt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsInt")
|
||||
|
||||
assert.Equal(false, IsInt(""))
|
||||
assert.Equal(false, IsInt("3"))
|
||||
assert.Equal(false, IsInt(0.1))
|
||||
assert.Equal(true, IsInt(0))
|
||||
assert.Equal(true, IsInt(-1))
|
||||
}
|
||||
|
||||
func TestIsNumberStr(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsNumberStr")
|
||||
|
||||
@@ -401,3 +429,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"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user