mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-05 05:12:26 +08:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99cb1b13a3 | ||
|
|
42ec189995 | ||
|
|
424c291813 | ||
|
|
4311b9ac66 | ||
|
|
581e338889 | ||
|
|
f399425c2a | ||
|
|
dcdb29334d | ||
|
|
4859f3ca23 | ||
|
|
9f2528842e | ||
|
|
6066d6669f | ||
|
|
e3804e9534 | ||
|
|
2f51397d2c | ||
|
|
11217a11c7 | ||
|
|
fa81ee143e | ||
|
|
62891f20f8 | ||
|
|
5e79eaa9dd | ||
|
|
aaf45012e4 | ||
|
|
48c17ea1ce | ||
|
|
e90283c3f9 | ||
|
|
f82c4a305d | ||
|
|
05997603a9 | ||
|
|
6d5ec807f7 | ||
|
|
f73c7e7e86 | ||
|
|
c137428b9e | ||
|
|
9f68620b37 | ||
|
|
2cdbba56a4 | ||
|
|
01a3b139c0 | ||
|
|
fcb3b97b45 | ||
|
|
52ea64bc33 | ||
|
|
14bc08c6d6 | ||
|
|
47bdd6718a | ||
|
|
18d27604e6 | ||
|
|
66bd339e3a | ||
|
|
04abb7a3ea | ||
|
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,4 +7,5 @@ fileutil/*.zip
|
||||
fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
cryptor/*.pem
|
||||
test
|
||||
271
README.md
271
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.
|
||||
|
||||
@@ -38,10 +38,10 @@ English | [简体中文](./README_zh-CN.md)
|
||||
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>
|
||||
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.8. </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
|
||||
@@ -118,7 +118,28 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)]
|
||||
[[play](https://go.dev/play/p/-EZjgOURufP)]
|
||||
|
||||
### 2. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
### 2. Compare package provides a lightweight comparison function on any type.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/compare"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>Equal</big>** : Checks if two values are equal or not. (check both type and value)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#Equal)]
|
||||
- **<big>EqualValue</big>** : Checks if two values are equal or not. (check value only)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#EqualValue)]
|
||||
- **<big>LessThan</big>** : Checks if value `left` less than value `right`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#LessThan)]
|
||||
- **<big>GreaterThan</big>** : Checks if value `left` greater than value `right`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#GreaterThan)]
|
||||
- **<big>LessOrEqual</big>** : Checks if value `left` less than or equal than value `right`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#LessOrEqual)]
|
||||
- **<big>GreaterOrEqual</big>** : Checks if value `left` less greater or equal than value `right`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#GreaterOrEqual)]
|
||||
|
||||
### 3. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
@@ -157,7 +178,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
|
||||
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
||||
|
||||
### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
|
||||
### 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/condition"
|
||||
@@ -190,7 +211,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
### 4. Convertor package contains some functions for data convertion.
|
||||
### 5. Convertor package contains some functions for data convertion.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -253,7 +274,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#CopyProperties)]
|
||||
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||
|
||||
### 5. Cryptor package is for data encryption and decryption.
|
||||
### 6. Cryptor package is for data encryption and decryption.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -357,7 +378,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
|
||||
### 6. Datetime package supports date and time format and compare.
|
||||
### 7. Datetime package supports date and time format and compare.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/datetime"
|
||||
@@ -456,7 +477,7 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
|
||||
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||
### 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
@@ -488,7 +509,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- **<big>Hashmap</big>** : hash map structure.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)]
|
||||
|
||||
### 8. Fileutil package implements some basic functions for file operations.
|
||||
### 9. Fileutil package implements some basic functions for file operations.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -541,8 +562,21 @@ 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)]
|
||||
[[play](https://go.dev/play/p/s74a9iBGcSw)]
|
||||
- **<big>IsZipFile</big>** : checks if file is zip file or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsZipFile)]
|
||||
- **<big>FileSize</big>** : return file size in bytes.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileSize)]
|
||||
- **<big>MTime</big>** : return file modified time(unix timestamp).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MTime)]
|
||||
- **<big>Sha</big>** : return file sha value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Sha)]
|
||||
- **<big>ReadCsvFile</big>** : read file content into slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadCsvFile)]
|
||||
|
||||
### 9. Formatter contains some functions for data formatting.
|
||||
### 10. Formatter contains some functions for data formatting.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -553,8 +587,26 @@ 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)]
|
||||
[[play](https://go.dev/play/p/YsciGj3FH2x)]
|
||||
- **<big>PrettyToWriter</big>** : pretty encode data to writer.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#PrettyToWriter)]
|
||||
[[play](https://go.dev/play/p/LPLZ3lDi5ma)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/FPXs1suwRcs)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/G9oHHMCAZxP)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/Am98ybWjvjj)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||
|
||||
### 10. Function package can control the flow of function execution and support part of functional programming
|
||||
### 11. Function package can control the flow of function execution and support part of functional programming
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -590,7 +642,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
### 11. Maputil package includes some functions to manipulate map.
|
||||
### 12. Maputil package includes some functions to manipulate map.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -598,6 +650,9 @@ 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)]
|
||||
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
|
||||
- **<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)]
|
||||
@@ -659,7 +714,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
### 12. Mathutil package implements some functions for math calculation.
|
||||
### 13. Mathutil package implements some functions for math calculation.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -705,10 +760,24 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[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.
|
||||
### 14. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -758,20 +827,28 @@ 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)]
|
||||
- **<big>DownloadFile</big>** : download the file exist in url to a local file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DownloadFile)]
|
||||
- **<big>UploadFile</big>** : upload the file to a server.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#UploadFile)]
|
||||
- **<big>IsPingConnected</big>** : checks if can ping the specified host or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPingConnected)]
|
||||
- **<big>IsTelnetConnected</big>** : checks if can if can telnet the specified host or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsTelnetConnected)]
|
||||
|
||||
### 14. Random package implements some basic functions to generate random int and string.
|
||||
### 15. Random package implements some basic functions to generate random int and string.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -804,7 +881,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
|
||||
### 15. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
### 16. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -828,7 +905,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
### 16. Slice contains some functions to manipulate slice.
|
||||
### 17. Slice contains some functions to manipulate slice.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -902,12 +979,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>FilterMap</big>** : returns a slice which apply both filtering and mapping to the given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FilterMap)]
|
||||
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
- **<big>Find<sup>deprecated</sup></big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</big>** : return the last item that passes a truth test on predicate function.
|
||||
- **<big>FindBy</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindBy)]
|
||||
- **<big>FindLast<sup>deprecated</sup></big>** : return the last item that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/FFDPV_j7URd)]
|
||||
- **<big>FindLastBy</big>** : iterates over elements of slice, returning the last one that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLastBy)]
|
||||
- **<big>Flatten</big>** : flattens slice one level.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Flatten)]
|
||||
[[play](https://go.dev/play/p/hYa3cBEevtm)]
|
||||
@@ -921,7 +1002,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[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#ForEach)]
|
||||
[[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)]
|
||||
@@ -955,9 +1037,15 @@ 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)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/YKDpLi7gtee)]
|
||||
- **<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/qT9dZC03A1K)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
@@ -1028,8 +1116,91 @@ 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)]
|
||||
|
||||
### 18. 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.
|
||||
|
||||
### 17. Structs package provides several high level functions to manipulate struct, tag, and field.
|
||||
```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)]
|
||||
|
||||
### 19. Structs package provides several high level functions to manipulate struct, tag, and field.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/structs"
|
||||
@@ -1062,7 +1233,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
- **<big>IsSlice</big>** : check if the field is a slice
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
|
||||
|
||||
### 18. Strutil package contains some functions to manipulate string.
|
||||
### 20. Strutil package contains some functions to manipulate string.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1138,8 +1309,23 @@ 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)]
|
||||
- **<big>StringToBytes</big>** : converts a string to byte slice without a memory allocation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#StringToBytes)]
|
||||
- **<big>BytesToString</big>** : converts a byte slice to string without a memory allocation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BytesToString)]
|
||||
- **<big>IsBlank</big>** : checks if a string is whitespace or empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsBlank)]
|
||||
- **<big>HasPrefixAny</big>** : checks if a string starts with any of an array of specified strings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#HasPrefixAny)]
|
||||
- **<big>HasSuffixAny</big>** : checks if a string ends with any of an array of specified strings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#HasSuffixAny)]
|
||||
- **<big>IndexOffset</big>** : returns the index of the first instance of substr in string after offsetting the string by `idxFrom`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IndexOffset)]
|
||||
|
||||
### 19. System package contain some functions about os, runtime, shell command.
|
||||
### 21. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1175,7 +1361,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)]
|
||||
|
||||
### 20. Validator package contains some functions for data validation.
|
||||
### 22. Validator package contains some functions for data validation.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1228,18 +1414,27 @@ 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)]
|
||||
[[play](https://go.dev/play/p/vsyG-sxr99_Z)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/mdJHOAvtsvF)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/eFoIHbgzl-z)]
|
||||
- **<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)]
|
||||
@@ -1267,8 +1462,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)]
|
||||
|
||||
### 21. xerror package implements helpers for errors.
|
||||
### 23. xerror package implements helpers for errors.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
277
README_zh-CN.md
277
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版本
|
||||
```
|
||||
|
||||
## 用法
|
||||
@@ -72,7 +72,7 @@ func main() {
|
||||
|
||||
## 文档
|
||||
|
||||
### 1. algorithm包实现一些基本查找和排序算法。
|
||||
### 1. algorithm 包实现一些基本查找和排序算法。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -117,7 +117,28 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)]
|
||||
[[play](https://go.dev/play/p/-EZjgOURufP)]
|
||||
|
||||
### 2. concurrency包含一些支持并发编程的功能。例如:goroutine, channel, async 等。
|
||||
### 2. compare 包提供几个轻量级的类型比较函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/compare"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>Equal</big>** : 检查两个值是否相等(检查类型和值)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#Equal)]
|
||||
- **<big>EqualValue</big>** : 检查两个值是否相等(只检查值)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#EqualValue)]
|
||||
- **<big>LessThan</big>** : 验证参数`left`的值是否小于参数`right`的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#LessThan)]
|
||||
- **<big>GreaterThan</big>** : 验证参数`left`的值是否大于参数`right`的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#GreaterThan)]
|
||||
- **<big>LessOrEqual</big>** : 验证参数`left`的值是否小于或等于参数`right`的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#LessOrEqual)]
|
||||
- **<big>GreaterOrEqual</big>** : 验证参数`left`的值是否大于或等于参数`right`的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#GreaterOrEqual)]
|
||||
|
||||
### 3. concurrency 包含一些支持并发编程的功能。例如:goroutine, channel, async 等。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
@@ -156,7 +177,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)]
|
||||
[[play](https://go.dev/play/p/3TQPKnCirrP)]
|
||||
|
||||
### 3. condition包含一些用于条件判断的函数。
|
||||
### 4. condition 包含一些用于条件判断的函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/condition"
|
||||
@@ -189,7 +210,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
### 4. convertor转换器包支持一些常见的数据类型转换。
|
||||
### 5. convertor 转换器包支持一些常见的数据类型转换。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -252,7 +273,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#CopyProperties)]
|
||||
[[play](https://go.dev/play/p/FOVY3XJL-6B)]
|
||||
|
||||
### 5. cryptor加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
### 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
@@ -356,7 +377,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
|
||||
### 6. datetime日期时间处理包,格式化日期,比较日期。
|
||||
### 7. datetime 日期时间处理包,格式化日期,比较日期。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/datetime"
|
||||
@@ -455,7 +476,7 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
|
||||
### 7. datastructure包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||
### 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
@@ -487,7 +508,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- **<big>Hashmap</big>** : 哈希映射。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
|
||||
|
||||
### 8. fileutil包含文件基本操作。
|
||||
### 9. fileutil 包含文件基本操作。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -540,8 +561,21 @@ 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)]
|
||||
[[play](https://go.dev/play/p/s74a9iBGcSw)]
|
||||
- **<big>IsZipFile</big>** : 判断文件是否是zip压缩文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsZipFile)]
|
||||
- **<big>FileSize</big>** : 返回文件字节大小。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileSize)]
|
||||
- **<big>MTime</big>** : 返回文件修改时间(unix timestamp)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MTime)]
|
||||
- **<big>Sha</big>** : 返回文件sha值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Sha)]
|
||||
- **<big>ReadCsvFile</big>** : 读取csv文件内容到切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadCsvFile)]
|
||||
|
||||
### 9. formatter格式化器包含一些数据格式化处理方法。
|
||||
### 10. formatter 格式化器包含一些数据格式化处理方法。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -552,8 +586,26 @@ 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)]
|
||||
[[play](https://go.dev/play/p/YsciGj3FH2x)]
|
||||
- **<big>PrettyToWriter</big>** : Pretty encode 数据到 writer。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#PrettyToWriter)]
|
||||
[[play](https://go.dev/play/p/LPLZ3lDi5ma)]
|
||||
- **<big>DecimalBytes</big>** : 返回十进制标准(以 1000 为基数)下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#DecimalBytes)]
|
||||
[[play](https://go.dev/play/p/FPXs1suwRcs)]
|
||||
- **<big>BinaryBytes</big>** : 返回 binary 标准(以 1024 为基数)下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#BinaryBytes)]
|
||||
[[play](https://go.dev/play/p/G9oHHMCAZxP)]
|
||||
- **<big>ParseDecimalBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1000 为基数)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseDecimalBytes)]
|
||||
[[play](https://go.dev/play/p/Am98ybWjvjj)]
|
||||
- **<big>ParseBinaryBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1024 为基数)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)]
|
||||
[[play](https://go.dev/play/p/69v1tTT62x8)]
|
||||
|
||||
### 10. function函数包控制函数执行流程,包含部分函数式编程。
|
||||
### 11. function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
@@ -589,7 +641,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
### 11. maputil包括一些操作 map 的函数.
|
||||
### 12. maputil 包括一些操作 map 的函数.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -597,6 +649,9 @@ 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)]
|
||||
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
|
||||
- **<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)]
|
||||
@@ -658,7 +713,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
### 12. mathutil包实现了一些数学计算的函数。
|
||||
### 13. mathutil 包实现了一些数学计算的函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -704,10 +759,24 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[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 请求。
|
||||
### 14. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
@@ -767,10 +836,18 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)]
|
||||
- **<big>HttpPatch<sup>deprecated</sup></big>** : 发送 http patch 请求(已弃用:SendRequest 代替)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)]
|
||||
- **<big>ParseHttpResponse</big>** : 解析 http 响应体到目标结构体。
|
||||
- **<big>ParseHttpResponse</big>** : 解析http响应体到目标结构体。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)]
|
||||
- **<big>DownloadFile</big>** : 从指定的server地址下载文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DownloadFile)]
|
||||
- **<big>UploadFile</big>** : 将文件上传指定的server地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#UploadFile)]
|
||||
- **<big>IsPingConnected</big>** : 检查能否ping通主机。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPingConnected)]
|
||||
- **<big>IsTelnetConnected</big>** : 检查能否telnet到主机。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsTelnetConnected)]
|
||||
|
||||
### 14. random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
### 15. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
@@ -803,7 +880,7 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
|
||||
### 15. retry重试执行函数直到函数运行成功或被 context cancel。
|
||||
### 16. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
@@ -827,7 +904,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
### 16. slice包含操作切片的方法集合。
|
||||
### 17. slice 包含操作切片的方法集合。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -901,12 +978,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>FilterMap</big>** : 返回一个将 filter 和 map 操作应用于给定切片的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FilterMap)]
|
||||
[[play](https://go.dev/play/p/J94SZ_9MiIe)]
|
||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||
- **<big>Find<sup>deprecated</sup></big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</big>** : 从头到尾遍历 slice 的元素,返回最后一个通过 predicate 函数真值测试的元素。
|
||||
- **<big>FindBy</big>** : 遍历切片的元素,返回第一个通过 predicate 函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindBy)]
|
||||
- **<big>FindLast<sup>deprecated</sup></big>** : 从头到尾遍历 slice 的元素,返回最后一个通过 predicate 函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/FFDPV_j7URd)]
|
||||
- **<big>FindLastBy</big>** : 从遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLastBy)]
|
||||
- **<big>Flatten</big>** : 将多维切片展平一层。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Flatten)]
|
||||
[[play](https://go.dev/play/p/hYa3cBEevtm)]
|
||||
@@ -919,8 +1000,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时,终止遍历。
|
||||
- **<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)]
|
||||
@@ -954,9 +1036,15 @@ 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)]
|
||||
[[play](https://go.dev/play/p/YKDpLi7gtee)]
|
||||
- **<big>ReduceRight</big>** : 类似 ReduceBy 操作,迭代切片元素顺序从右至左。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceRight)]
|
||||
[[play](https://go.dev/play/p/qT9dZC03A1K)]
|
||||
- **<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)]
|
||||
@@ -1027,7 +1115,91 @@ 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. structs提供操作struct, tag, field的相关函数。
|
||||
### 18. 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)]
|
||||
|
||||
### 19. structs 提供操作 struct, tag, field 的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/structs"
|
||||
@@ -1037,21 +1209,21 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
|
||||
- **<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。
|
||||
- **<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对象的属性列表。
|
||||
- **<big>Fields</big>** : 获取一个 struct 对象的属性列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||
- **<big>Field</big>** : 根据属性名获取一个struct对象的属性。
|
||||
- **<big>Field</big>** : 根据属性名获取一个 struct 对象的属性。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||
- **<big>IsStruct</big>** : 判断是否为一个合法的struct对象。
|
||||
- **<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。
|
||||
- **<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。
|
||||
- **<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)]
|
||||
@@ -1062,7 +1234,7 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
- **<big>IsSlice</big>** : 判断属性是否是切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
|
||||
|
||||
### 18. strutil包含字符串处理的相关函数。
|
||||
### 20. strutil 包含字符串处理的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -1139,9 +1311,23 @@ 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)]
|
||||
- **<big>StringToBytes</big>** : 在不分配内存的情况下将字符串转换为字节片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#StringToBytes)]
|
||||
- **<big>BytesToString</big>** : 在不分配内存的情况下将字节切片转换为字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BytesToString)]
|
||||
- **<big>IsBlank</big>** : 检查字符串是否为空格或空。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsBlank)]
|
||||
- **<big>HasPrefixAny</big>** : 检查字符串是否以指定字符串数组中的任何一个开头。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#HasPrefixAny)]
|
||||
- **<big>HasSuffixAny</big>** : 检查字符串是否以指定字符串数组中的任何一个结尾。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#HasSuffixAny)]
|
||||
- **<big>IndexOffset</big>** : 将字符串偏移idxFrom后,返回字符串中第一个 substr 实例的索引。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IndexOffset)]
|
||||
|
||||
|
||||
### 19. system包含 os, runtime, shell command 的相关函数。
|
||||
### 21. system 包含 os, runtime, shell command 的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -1177,7 +1363,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)]
|
||||
|
||||
### 20. validator验证器包,包含常用字符串格式验证函数。
|
||||
### 22. validator 验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
@@ -1230,18 +1416,27 @@ 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)]
|
||||
[[play](https://go.dev/play/p/vsyG-sxr99_Z)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/mdJHOAvtsvF)]
|
||||
- **<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)]
|
||||
[[play](https://go.dev/play/p/eFoIHbgzl-z)]
|
||||
- **<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)]
|
||||
@@ -1269,8 +1464,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)]
|
||||
|
||||
### 21. xerror包实现一些错误处理函数
|
||||
### 23. xerror 包实现一些错误处理函数
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
|
||||
@@ -200,7 +200,6 @@ func TestCountSort(t *testing.T) {
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
sortedPeopleByAge := CountSort(peoples, comparator)
|
||||
t.Log(sortedPeopleByAge)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", sortedPeopleByAge)
|
||||
|
||||
58
compare/compare.go
Normal file
58
compare/compare.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package compare provides a lightweight comparison function on any type.
|
||||
// reference: https://github.com/stretchr/testify
|
||||
package compare
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
// operator type
|
||||
const (
|
||||
equal = "eq"
|
||||
lessThan = "lt"
|
||||
greaterThan = "gt"
|
||||
lessOrEqual = "le"
|
||||
greaterOrEqual = "ge"
|
||||
)
|
||||
|
||||
var (
|
||||
timeType = reflect.TypeOf(time.Time{})
|
||||
bytesType = reflect.TypeOf([]byte{})
|
||||
)
|
||||
|
||||
// Equal checks if two values are equal or not. (check both type and value)
|
||||
func Equal(left, right any) bool {
|
||||
return compareValue(equal, left, right)
|
||||
}
|
||||
|
||||
// EqualValue checks if two values are equal or not. (check value only)
|
||||
func EqualValue(left, right any) bool {
|
||||
ls, rs := convertor.ToString(left), convertor.ToString(right)
|
||||
return ls == rs
|
||||
}
|
||||
|
||||
// LessThan checks if value `left` less than value `right`.
|
||||
func LessThan(left, right any) bool {
|
||||
return compareValue(lessThan, left, right)
|
||||
}
|
||||
|
||||
// GreaterThan checks if value `left` greater than value `right`.
|
||||
func GreaterThan(left, right any) bool {
|
||||
return compareValue(greaterThan, left, right)
|
||||
}
|
||||
|
||||
// LessOrEqual checks if value `left` less than or equal to value `right`.
|
||||
func LessOrEqual(left, right any) bool {
|
||||
return compareValue(lessOrEqual, left, right)
|
||||
}
|
||||
|
||||
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
|
||||
func GreaterOrEqual(left, right any) bool {
|
||||
return compareValue(greaterOrEqual, left, right)
|
||||
}
|
||||
170
compare/compare_example_test.go
Normal file
170
compare/compare_example_test.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleEqual() {
|
||||
result1 := Equal(1, 1)
|
||||
result2 := Equal("1", "1")
|
||||
result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := Equal(1, "1")
|
||||
result6 := Equal(1, int64(1))
|
||||
result7 := Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleEqualValue() {
|
||||
result1 := EqualValue(1, 1)
|
||||
result2 := EqualValue(int(1), int64(1))
|
||||
result3 := EqualValue(1, "1")
|
||||
result4 := EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLessThan() {
|
||||
result1 := LessThan(1, 2)
|
||||
result2 := LessThan(1.1, 2.2)
|
||||
result3 := LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := LessThan(time1, time2)
|
||||
|
||||
result5 := LessThan(2, 1)
|
||||
result6 := LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleGreaterThan() {
|
||||
result1 := GreaterThan(2, 1)
|
||||
result2 := GreaterThan(2.2, 1.1)
|
||||
result3 := GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := GreaterThan(time2, time1)
|
||||
|
||||
result5 := GreaterThan(1, 2)
|
||||
result6 := GreaterThan(int64(2), 1)
|
||||
result7 := GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLessOrEqual() {
|
||||
result1 := LessOrEqual(1, 1)
|
||||
result2 := LessOrEqual(1.1, 2.2)
|
||||
result3 := LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := LessOrEqual(time1, time2)
|
||||
|
||||
result5 := LessOrEqual(2, 1)
|
||||
result6 := LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleGreaterOrEqual() {
|
||||
result1 := GreaterOrEqual(1, 1)
|
||||
result2 := GreaterOrEqual(2.2, 1.1)
|
||||
result3 := GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := GreaterOrEqual(1, 2)
|
||||
result6 := GreaterOrEqual(int64(2), 1)
|
||||
result7 := GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
323
compare/compare_internal.go
Normal file
323
compare/compare_internal.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func compareValue(operator string, left, right any) bool {
|
||||
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
|
||||
|
||||
if leftType.Kind() != rightType.Kind() {
|
||||
return false
|
||||
}
|
||||
|
||||
switch leftType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
|
||||
return compareBasicValue(operator, left, right)
|
||||
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
return compareRefValue(operator, left, right, leftType.Kind())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind) bool {
|
||||
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
|
||||
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
|
||||
// compare time
|
||||
if leftVal.CanConvert(timeType) {
|
||||
timeObj1, ok := leftObj.(time.Time)
|
||||
if !ok {
|
||||
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
|
||||
}
|
||||
|
||||
timeObj2, ok := rightObj.(time.Time)
|
||||
if !ok {
|
||||
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
|
||||
}
|
||||
|
||||
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
|
||||
}
|
||||
|
||||
// for other struct type, only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return objectsAreEqualValues(leftObj, rightObj)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
// compare []byte
|
||||
if leftVal.CanConvert(bytesType) {
|
||||
bytesObj1, ok := leftObj.([]byte)
|
||||
if !ok {
|
||||
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
|
||||
}
|
||||
bytesObj2, ok := rightObj.([]byte)
|
||||
if !ok {
|
||||
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for other type slice, only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return reflect.DeepEqual(leftObj, rightObj)
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
// only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return reflect.DeepEqual(leftObj, rightObj)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// compareBasic compare basic value: integer, float, string, bool
|
||||
func compareBasicValue(operator string, leftValue, rightValue any) bool {
|
||||
if leftValue == nil && rightValue == nil && operator == equal {
|
||||
return true
|
||||
}
|
||||
|
||||
switch leftVal := leftValue.(type) {
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
left, err := convertor.ToFloat(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case string:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case string:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case bool:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case bool:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
134
compare/compare_test.go
Normal file
134
compare/compare_test.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqual")
|
||||
|
||||
assert.Equal(true, Equal(1, 1))
|
||||
assert.Equal(true, Equal(int64(1), int64(1)))
|
||||
assert.Equal(true, Equal("a", "a"))
|
||||
assert.Equal(true, Equal(true, true))
|
||||
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
|
||||
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
|
||||
|
||||
assert.Equal(false, Equal(1, 2))
|
||||
assert.Equal(false, Equal(1, int64(1)))
|
||||
assert.Equal(false, Equal("a", "b"))
|
||||
assert.Equal(false, Equal(true, false))
|
||||
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
|
||||
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
time3 := time1.Add(time.Second)
|
||||
|
||||
assert.Equal(false, Equal(time1, time2))
|
||||
assert.Equal(true, Equal(time2, time3))
|
||||
|
||||
st1 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
st2 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
st3 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a1",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
assert.Equal(true, Equal(st1, st2))
|
||||
assert.Equal(false, Equal(st1, st3))
|
||||
}
|
||||
|
||||
func TestEqualValue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqualValue")
|
||||
|
||||
assert.Equal(true, EqualValue(1, 1))
|
||||
assert.Equal(true, EqualValue(int(1), int64(1)))
|
||||
assert.Equal(true, EqualValue(1, "1"))
|
||||
|
||||
assert.Equal(false, EqualValue(1, "2"))
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLessThan")
|
||||
|
||||
assert.Equal(true, LessThan(1, 2))
|
||||
assert.Equal(true, LessThan(1.1, 2.2))
|
||||
assert.Equal(true, LessThan("a", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessThan(time1, time2))
|
||||
|
||||
assert.Equal(false, LessThan(1, 1))
|
||||
assert.Equal(false, LessThan(1, int64(1)))
|
||||
}
|
||||
|
||||
func TestGreaterThan(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterThan(2, 1))
|
||||
assert.Equal(true, GreaterThan(2.2, 1.1))
|
||||
assert.Equal(true, GreaterThan("b", "a"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterThan(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterThan(1, 2))
|
||||
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||
assert.Equal(false, GreaterThan("b", "c"))
|
||||
}
|
||||
|
||||
func TestLessOrEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLessOrEqual")
|
||||
|
||||
assert.Equal(true, LessOrEqual(1, 2))
|
||||
assert.Equal(true, LessOrEqual(1, 1))
|
||||
assert.Equal(true, LessOrEqual(1.1, 2.2))
|
||||
assert.Equal(true, LessOrEqual("a", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessOrEqual(time1, time2))
|
||||
|
||||
assert.Equal(false, LessOrEqual(2, 1))
|
||||
assert.Equal(false, LessOrEqual(1, int64(2)))
|
||||
}
|
||||
|
||||
func TestGreaterOrEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(2, 1))
|
||||
assert.Equal(true, GreaterOrEqual(1, 1))
|
||||
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
|
||||
assert.Equal(true, GreaterOrEqual("b", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterOrEqual(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterOrEqual(1, 2))
|
||||
assert.Equal(false, GreaterOrEqual(int64(2), 1))
|
||||
assert.Equal(false, GreaterOrEqual("b", "c"))
|
||||
}
|
||||
@@ -181,7 +181,6 @@ func TestBridge(t *testing.T) {
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
// t.Logf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
assert.Equal(index, val)
|
||||
index++
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
// ToBool convert string to boolean.
|
||||
@@ -319,43 +320,29 @@ func DeepClone[T any](src T) T {
|
||||
}
|
||||
|
||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
// Play: https://go.dev/play/p/FOVY3XJL-6B
|
||||
func CopyProperties[T, U any](dst T, src U) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}()
|
||||
|
||||
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
|
||||
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
|
||||
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||
// Play: todo
|
||||
func CopyProperties[T, U any](dst T, src U) error {
|
||||
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
|
||||
|
||||
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||
return errors.New("CopyProperties: param dst should be struct pointer")
|
||||
return errors.New("CopyProperties: parameter dst should be struct pointer")
|
||||
}
|
||||
|
||||
if srcType.Kind() == reflect.Ptr {
|
||||
srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
||||
srcType = srcType.Elem()
|
||||
}
|
||||
if srcType.Kind() != reflect.Struct {
|
||||
return errors.New("CopyProperties: param src should be a struct or struct pointer")
|
||||
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
|
||||
}
|
||||
|
||||
dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
||||
|
||||
propertyNums := dstType.NumField()
|
||||
|
||||
for i := 0; i < propertyNums; i++ {
|
||||
property := dstType.Field(i)
|
||||
propertyValue := srcValue.FieldByName(property.Name)
|
||||
|
||||
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
||||
continue
|
||||
}
|
||||
|
||||
if dstValue.Field(i).CanSet() {
|
||||
dstValue.Field(i).Set(propertyValue)
|
||||
}
|
||||
bytes, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
|
||||
}
|
||||
err = json.Unmarshal(bytes, dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -297,49 +297,55 @@ func ExampleDeepClone() {
|
||||
}
|
||||
|
||||
func ExampleCopyProperties() {
|
||||
type Address struct {
|
||||
Country string
|
||||
ZipCode string
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||
|
||||
employee1 := Employee{}
|
||||
err := CopyProperties(&employee1, &user)
|
||||
if err != nil {
|
||||
return
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
err = CopyProperties(&employee2, &user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
fmt.Println(employee1)
|
||||
fmt.Println(employee2)
|
||||
CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// {user001 10 Admin {CN 001} [a b] 0}
|
||||
// {user001 10 Admin {CN 001} [a b] 500}
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
|
||||
@@ -306,7 +306,6 @@ func TestDeepClone(t *testing.T) {
|
||||
for i, item := range cases {
|
||||
cloned := DeepClone(item)
|
||||
|
||||
t.Log(cloned)
|
||||
if &cloned == &item {
|
||||
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
|
||||
}
|
||||
@@ -320,49 +319,51 @@ func TestDeepClone(t *testing.T) {
|
||||
func TestCopyProperties(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||
|
||||
type Address struct {
|
||||
Country string
|
||||
ZipCode string
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
employee1 := Employee{}
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
err := CopyProperties(&employee1, &user)
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("user001", employee1.Name)
|
||||
assert.Equal("Admin", employee1.Role)
|
||||
assert.Equal("CN", employee1.Addr.Country)
|
||||
assert.Equal(0, employee1.salary)
|
||||
|
||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||
|
||||
err = CopyProperties(&employee2, &user)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("user001", employee2.Name)
|
||||
assert.Equal("Admin", employee2.Role)
|
||||
assert.Equal("CN", employee2.Addr.Country)
|
||||
assert.Equal(500, employee2.salary)
|
||||
assert.Equal("001", indicatorVO.Id)
|
||||
assert.Equal("127.0.0.1", indicatorVO.Ip)
|
||||
assert.Equal(3, len(indicatorVO.Disk))
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ func TestHashMap_KeysValues(t *testing.T) {
|
||||
|
||||
keys := hm.Keys()
|
||||
values := hm.Values()
|
||||
t.Log(keys, values)
|
||||
|
||||
assert.Equal(3, len(values))
|
||||
assert.Equal(3, len(keys))
|
||||
|
||||
@@ -175,7 +175,7 @@ func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
|
||||
// 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 {
|
||||
for _, v := range s.Values() {
|
||||
if !iteratee(v) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -194,20 +194,20 @@ func TestSet_Minus(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEachWithBreak(t *testing.T) {
|
||||
s := NewSet(1, 2, 3, 4, 5)
|
||||
// s := NewSet(1, 2, 3, 4, 5)
|
||||
|
||||
var sum int
|
||||
// var sum int
|
||||
|
||||
s.EachWithBreak(func(n int) bool {
|
||||
if n > 3 {
|
||||
return false
|
||||
}
|
||||
sum += n
|
||||
return true
|
||||
})
|
||||
// s.EachWithBreak(func(n int) bool {
|
||||
// if n > 3 {
|
||||
// return false
|
||||
// }
|
||||
// sum += n
|
||||
// return true
|
||||
// })
|
||||
|
||||
assert := internal.NewAssert(t, "TestEachWithBreak")
|
||||
assert.Equal(6, sum)
|
||||
// assert := internal.NewAssert(t, "TestEachWithBreak")
|
||||
// assert.Equal(6, sum)
|
||||
}
|
||||
|
||||
// func TestPop(t *testing.T) {
|
||||
|
||||
@@ -40,7 +40,6 @@ func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.PreOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 2, 4, 7}, acturl)
|
||||
}
|
||||
|
||||
@@ -55,7 +54,6 @@ func TestBSTree_PostOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.PostOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{5, 2, 4, 7, 6}, acturl)
|
||||
}
|
||||
|
||||
@@ -70,7 +68,6 @@ func TestBSTree_InOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.InOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{2, 4, 5, 6, 7}, acturl)
|
||||
}
|
||||
|
||||
@@ -85,7 +82,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(4)
|
||||
|
||||
acturl := bstree.LevelOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||
}
|
||||
|
||||
@@ -102,14 +98,12 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
bstree.Delete(4)
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
t.Log(acturl1)
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
|
||||
//todo
|
||||
// bstree.DeletetNode(6, comparator)
|
||||
// bstree.Print()
|
||||
// acturl2 := bstree.InOrderTraverse()
|
||||
// t.Log(acturl2)
|
||||
// assert.Equal([]int{2, 5, 7}, acturl2)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ func TestToFormat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToFormat")
|
||||
|
||||
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
t.Log("TestToFormat", tm.ToFormat())
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToFormat -> ", tm.ToFormat())
|
||||
}
|
||||
|
||||
func TestToFormatForTpl(t *testing.T) {
|
||||
@@ -32,9 +31,9 @@ func TestToFormatForTpl(t *testing.T) {
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
// assert.Equal("2022/03/18 17:04:05", tm.ToFormatForTpl("2006/01/02 15:04:05"))
|
||||
t.Log("TestToFormatForTpl", tm.ToFormatForTpl("2006/01/02 15:04:05"))
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
|
||||
}
|
||||
|
||||
func TestToIso8601(t *testing.T) {
|
||||
@@ -44,7 +43,7 @@ func TestToIso8601(t *testing.T) {
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
t.Log("TestToIso8601", tm.ToIso8601())
|
||||
// assert.Equal("2006-01-02T23:04:05+08:00", tm.ToIso8601())
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToIso8601 -> ", tm.ToIso8601())
|
||||
}
|
||||
|
||||
326
docs/compare.md
Normal file
326
docs/compare.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# Compare
|
||||
|
||||
Package compare provides a lightweight comparison function on any type.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/compare/compare.go](https://github.com/duke-git/lancet/blob/main/compare/compare.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [Equal](#Equal)
|
||||
- [EqualValue](#EqualValue)
|
||||
- [LessThan](#LessThan)
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
|
||||
<p>Checks if two values are equal or not. (check both type and value)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Equal(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.Equal(1, 1)
|
||||
result2 := compare.Equal("1", "1")
|
||||
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := compare.Equal(1, "1")
|
||||
result6 := compare.Equal(1, int64(1))
|
||||
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualValue">EqualValue</span>
|
||||
|
||||
<p>Checks if two values are equal or not. (check value only)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func EqualValue(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.EqualValue(1, 1)
|
||||
result2 := compare.EqualValue(int(1), int64(1))
|
||||
result3 := compare.EqualValue(1, "1")
|
||||
result4 := compare.EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessThan">LessThan</span>
|
||||
|
||||
<p>Checks if value `left` less than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LessThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessThan(1, 2)
|
||||
result2 := compare.LessThan(1.1, 2.2)
|
||||
result3 := compare.LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessThan(time1, time2)
|
||||
|
||||
result5 := compare.LessThan(2, 1)
|
||||
result6 := compare.LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterThan">GreaterThan</span>
|
||||
|
||||
<p>Checks if value `left` greater than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterThan(2, 1)
|
||||
result2 := compare.GreaterThan(2.2, 1.1)
|
||||
result3 := compare.GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterThan(time2, time1)
|
||||
|
||||
result5 := compare.GreaterThan(1, 2)
|
||||
result6 := compare.GreaterThan(int64(2), 1)
|
||||
result7 := compare.GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessOrEqual">LessOrEqual</span>
|
||||
|
||||
<p>Checks if value `left` less than or equal than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessOrEqual(1, 1)
|
||||
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||
result3 := compare.LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessOrEqual(time1, time2)
|
||||
|
||||
result5 := compare.LessOrEqual(2, 1)
|
||||
result6 := compare.LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||
|
||||
<p>Checks if value `left` less greater or equal than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterOrEqual(1, 1)
|
||||
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||
result3 := compare.GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := compare.GreaterOrEqual(1, 2)
|
||||
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||
result7 := compare.GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
326
docs/compare_zh-CN.md
Normal file
326
docs/compare_zh-CN.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# Compare
|
||||
|
||||
compare包提供几个轻量级的类型比较函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/compare/compare.go](https://github.com/duke-git/lancet/blob/main/compare/compare.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/main/compare/compare_internal.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Equal](#Equal)
|
||||
- [EqualValue](#EqualValue)
|
||||
- [LessThan](#LessThan)
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
|
||||
<p>检查两个值是否相等(检查类型和值)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Equal(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.Equal(1, 1)
|
||||
result2 := compare.Equal("1", "1")
|
||||
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := compare.Equal(1, "1")
|
||||
result6 := compare.Equal(1, int64(1))
|
||||
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualValue">EqualValue</span>
|
||||
|
||||
<p>检查两个值是否相等(只检查值)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func EqualValue(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.EqualValue(1, 1)
|
||||
result2 := compare.EqualValue(int(1), int64(1))
|
||||
result3 := compare.EqualValue(1, "1")
|
||||
result4 := compare.EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessThan">LessThan</span>
|
||||
|
||||
<p>验证参数`left`的值是否小于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LessThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessThan(1, 2)
|
||||
result2 := compare.LessThan(1.1, 2.2)
|
||||
result3 := compare.LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessThan(time1, time2)
|
||||
|
||||
result5 := compare.LessThan(2, 1)
|
||||
result6 := compare.LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterThan">GreaterThan</span>
|
||||
|
||||
<p>验证参数`left`的值是否大于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterThan(2, 1)
|
||||
result2 := compare.GreaterThan(2.2, 1.1)
|
||||
result3 := compare.GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterThan(time2, time1)
|
||||
|
||||
result5 := compare.GreaterThan(1, 2)
|
||||
result6 := compare.GreaterThan(int64(2), 1)
|
||||
result7 := compare.GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessOrEqual">LessOrEqual</span>
|
||||
|
||||
<p>验证参数`left`的值是否小于或等于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessOrEqual(1, 1)
|
||||
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||
result3 := compare.LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessOrEqual(time1, time2)
|
||||
|
||||
result5 := compare.LessOrEqual(2, 1)
|
||||
result6 := compare.LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||
|
||||
<p>验证参数`left`的值是否大于或参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterOrEqual(1, 1)
|
||||
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||
result3 := compare.GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := compare.GreaterOrEqual(1, 2)
|
||||
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||
result7 := compare.GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
@@ -697,7 +697,7 @@ func main() {
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<p>Copies each field from the source struct into the destination struct.</p>
|
||||
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -716,44 +716,56 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Address struct {
|
||||
Country string
|
||||
ZipCode string
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
employee1 := Employee{}
|
||||
CopyProperties(&employee1, &user)
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
CopyProperties(&employee2, &user)
|
||||
CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
fmt.Println(employee1)
|
||||
fmt.Println(employee2)
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// {user001 10 Admin {CN 001} [a b] 0}
|
||||
// {user001 10 Admin {CN 001} [a b] 500}
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -696,7 +696,7 @@ func main() {
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<p>拷贝不同结构体之间的同名字段。</p>
|
||||
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -715,44 +715,56 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Address struct {
|
||||
Country string
|
||||
ZipCode string
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Name string
|
||||
Age int
|
||||
Role string
|
||||
Addr Address
|
||||
Hobbys []string
|
||||
salary int
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
user := User{Name: "user001", Age: 10, Role: "Admin", Addr: Address{Country: "CN", ZipCode: "001"}, Hobbys: []string{"a", "b"}, salary: 1000}
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
employee1 := Employee{}
|
||||
CopyProperties(&employee1, &user)
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
employee2 := Employee{Name: "employee001", Age: 20, Role: "User",
|
||||
Addr: Address{Country: "UK", ZipCode: "002"}, salary: 500}
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
CopyProperties(&employee2, &user)
|
||||
CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
fmt.Println(employee1)
|
||||
fmt.Println(employee2)
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// {user001 10 Admin {CN 001} [a b] 0}
|
||||
// {user001 10 Admin {CN 001} [a b] 500}
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
195
docs/fileutil.md
195
docs/fileutil.md
@@ -26,6 +26,7 @@ import (
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
@@ -37,7 +38,11 @@ import (
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [UnZip](#UnZip)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
- [MTime](#MTime)
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -130,7 +135,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||
func CopyFile(srcPath string, dstPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -151,6 +156,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>
|
||||
@@ -469,3 +500,163 @@ func main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsZipFile">IsZipFile</span>
|
||||
|
||||
<p>Checks if file is zip file or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsZipFile(filepath string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isZip := IsZipFile("./zipfile.zip")
|
||||
fmt.Println(isZip)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FileSize">FileSize</span>
|
||||
|
||||
<p>Returns file size in bytes.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FileSize(path string) (int64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
size, err := fileutil.FileSize("./testdata/test.txt")
|
||||
|
||||
fmt.Println(size)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// 20
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MTime">MTime</span>
|
||||
|
||||
<p>Returns file modified time(unix timestamp).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MTime(filepath string) (int64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mtime, err := fileutil.MTime("./testdata/test.txt")
|
||||
|
||||
fmt.Println(mtime)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// 1682391110
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sha">Sha</span>
|
||||
|
||||
<p>returns file sha value, param `shaType` should be 1, 256 or 512.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sha(filepath string, shaType ...int) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
|
||||
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
|
||||
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
|
||||
|
||||
fmt.Println(sha1)
|
||||
fmt.Println(sha256)
|
||||
fmt.Println(sha512)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
|
||||
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
|
||||
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReadCsvFile">ReadCsvFile</span>
|
||||
|
||||
<p>Reads file content into slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ReadCsvFile(filepath string) ([][]string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
|
||||
|
||||
fmt.Println(content)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
@@ -37,6 +38,11 @@ import (
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
- [MTime](#MTime)
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -106,7 +112,7 @@ func main() {
|
||||
func CreateDir(absPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -129,7 +135,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||
func CopyFile(srcPath string, dstPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
@@ -150,6 +156,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>
|
||||
@@ -445,7 +477,7 @@ func main() {
|
||||
|
||||
<p>zip解压缩文件并保存在目录中</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func UnZip(zipFile string, destPath string) error
|
||||
@@ -468,3 +500,163 @@ func main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsZipFile">IsZipFile</span>
|
||||
|
||||
<p>判断文件是否是zip压缩文件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsZipFile(filepath string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isZip := IsZipFile("./zipfile.zip")
|
||||
fmt.Println(isZip)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FileSize">FileSize</span>
|
||||
|
||||
<p>返回文件字节大小。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FileSize(path string) (int64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
size, err := fileutil.FileSize("./testdata/test.txt")
|
||||
|
||||
fmt.Println(size)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// 20
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MTime">MTime</span>
|
||||
|
||||
<p>返回文件修改时间(unix timestamp).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MTime(filepath string) (int64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mtime, err := fileutil.MTime("./testdata/test.txt")
|
||||
|
||||
fmt.Println(mtime)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// 1682391110
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sha">Sha</span>
|
||||
|
||||
<p>返回文件sha值,参数`shaType` 应传值为: 1, 256,512.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sha(filepath string, shaType ...int) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
|
||||
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
|
||||
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
|
||||
|
||||
fmt.Println(sha1)
|
||||
fmt.Println(sha256)
|
||||
fmt.Println(sha512)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
|
||||
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
|
||||
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReadCsvFile">ReadCsvFile</span>
|
||||
|
||||
<p>读取csv文件内容到切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReadCsvFile(filepath string) ([][]string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
|
||||
|
||||
fmt.Println(content)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
}
|
||||
135
docs/netutil.md
135
docs/netutil.md
@@ -44,6 +44,10 @@ import (
|
||||
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
|
||||
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
|
||||
- [ParseHttpResponse](#ParseHttpResponse)
|
||||
- [DownloadFile](#DownloadFile)
|
||||
- [UploadFile](#UploadFile)
|
||||
- [IsPingConnected](#IsPingConnected)
|
||||
- [IsTelnetConnected](#IsTelnetConnected)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -110,8 +114,8 @@ func main() {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
fmt.Println(encodedUrl)
|
||||
|
||||
fmt.Println(encodedUrl)
|
||||
|
||||
// Output:
|
||||
// http://www.lancet.com?a=1&b=%5B2%5D
|
||||
}
|
||||
@@ -142,8 +146,8 @@ func main() {
|
||||
internalIp := netutil.GetInternalIp()
|
||||
ip := net.ParseIP(internalIp)
|
||||
|
||||
fmt.Println(ip)
|
||||
|
||||
fmt.Println(ip)
|
||||
|
||||
// Output:
|
||||
// 192.168.1.9
|
||||
}
|
||||
@@ -172,7 +176,7 @@ import (
|
||||
|
||||
func main() {
|
||||
ips := netutil.GetIps()
|
||||
fmt.Println(ips)
|
||||
fmt.Println(ips)
|
||||
|
||||
// Output:
|
||||
// [192.168.1.9]
|
||||
@@ -896,3 +900,124 @@ func main() {
|
||||
fmt.Println(toDoResp)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DownloadFile">DownloadFile</span>
|
||||
|
||||
<p>Download the file exist in url to a local file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DownloadFile(filepath string, url string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := DownloadFile("./lancet_logo.jpg", "https://picx.zhimg.com/v2-fc82a4199749de9cfb71e32e54f489d3_720w.jpg?source=172ae18b")
|
||||
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UploadFile">UploadFile</span>
|
||||
|
||||
<p>Upload the file to a server.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func UploadFile(filepath string, server string) (bool, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ok, err := netutil.UploadFile("./a.jpg", "http://www.xxx.com/bucket/test")
|
||||
|
||||
fmt.Println(ok)
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsPingConnected">IsPingConnected</span>
|
||||
|
||||
<p>checks if can ping the specified host or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsPingConnected(host string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := netutil.IsPingConnected("www.baidu.com")
|
||||
result2 := netutil.IsPingConnected("www.!@#&&&.com")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsTelnetConnected">IsTelnetConnected</span>
|
||||
|
||||
<p>Checks if can telnet the specified host or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsTelnetConnected(host string, port string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := netutil.IsTelnetConnected("www.baidu.com", "80")
|
||||
result2 := netutil.IsTelnetConnected("www.baidu.com", "123")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -44,6 +44,10 @@ import (
|
||||
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
|
||||
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
|
||||
- [ParseHttpResponse](#ParseHttpResponse)
|
||||
- [DownloadFile](#DownloadFile)
|
||||
- [UploadFile](#UploadFile)
|
||||
- [IsPingConnected](#IsPingConnected)
|
||||
- [IsTelnetConnected](#IsTelnetConnected)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -898,3 +902,124 @@ func main() {
|
||||
fmt.Println(toDoResp)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DownloadFile">DownloadFile</span>
|
||||
|
||||
<p>从指定的server地址下载文件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DownloadFile(filepath string, url string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := DownloadFile("./lancet_logo.jpg", "https://picx.zhimg.com/v2-fc82a4199749de9cfb71e32e54f489d3_720w.jpg?source=172ae18b")
|
||||
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UploadFile">UploadFile</span>
|
||||
|
||||
<p>将文件上传指定的server地址。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func UploadFile(filepath string, server string) (bool, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ok, err := netutil.UploadFile("./a.jpg", "http://www.xxx.com/bucket/test")
|
||||
|
||||
fmt.Println(ok)
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsPingConnected">IsPingConnected</span>
|
||||
|
||||
<p>检查能否ping通主机。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsPingConnected(host string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := netutil.IsPingConnected("www.baidu.com")
|
||||
result2 := netutil.IsPingConnected("www.!@#&&&.com")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsTelnetConnected">IsTelnetConnected</span>
|
||||
|
||||
<p>检查能否telnet到主机。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsTelnetConnected(host string, port string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/netutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := netutil.IsTelnetConnected("www.baidu.com", "80")
|
||||
result2 := netutil.IsTelnetConnected("www.baidu.com", "123")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
154
docs/slice.md
154
docs/slice.md
@@ -43,8 +43,10 @@ import (
|
||||
- [EqualWith](#EqualWith)
|
||||
- [Every](#Every)
|
||||
- [Filter](#Filter)
|
||||
- [Find](#Find)
|
||||
- [FindLast](#FindLast)
|
||||
- [Find<sup>deprecated</sup>](#Find)
|
||||
- [FindBy](#FindBy)
|
||||
- [FindLast<sup>deprecated</sup>](#FindLast)
|
||||
- [FindLastBy](#FindLastBy)
|
||||
- [Flatten](#Flatten)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](#ForEach)
|
||||
@@ -62,7 +64,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)
|
||||
@@ -835,7 +839,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Find">Find</span>
|
||||
### <span id="Find">Find(deprecated: use FindBy)</span>
|
||||
|
||||
<p>Iterates over elements of slice, returning the first one that passes a truth test on function.</p>
|
||||
|
||||
@@ -871,7 +875,43 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLast">FindLast</span>
|
||||
### <span id="FindBy">FindBy</span>
|
||||
|
||||
<p>Iterates over elements of slice, returning the first one that passes a truth test on predicate function.If return T is nil or zero value then no items matched the predicate func. In contrast to Find or FindLast, its return value no longer requires dereferencing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLast">FindLast(deprecated: use FindLastBy)</span>
|
||||
|
||||
<p>iterates over elements of slice from end to begin, returning the last one that passes a truth test on function.</p>
|
||||
|
||||
@@ -907,6 +947,42 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLastBy">FindLastBy</span>
|
||||
|
||||
<p>FindLastBy iterates over elements of slice, returning the last one that passes a truth test on predicate function. If return T is nil or zero value then no items matched the predicate func. In contrast to Find or FindLast, its return value no longer requires dereferencing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Flatten">Flatten</span>
|
||||
|
||||
<p>Flatten slice with one level.</p>
|
||||
@@ -1472,7 +1548,7 @@ func main() {
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>Reduce slice.</p>
|
||||
<p>Reduce slice.(Deprecated: use ReduceBy)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -1504,6 +1580,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>
|
||||
|
||||
@@ -43,8 +43,10 @@ import (
|
||||
- [Equal](#Equal)
|
||||
- [EqualWith](#EqualWith)
|
||||
- [Filter](#Filter)
|
||||
- [Find](#Find)
|
||||
- [FindLast](#FindLast)
|
||||
- [Find<sup>deprecated</sup>](#Find)
|
||||
- [FindBy](#FindBy)
|
||||
- [FindLast<sup>deprecated</sup>](#FindLast)
|
||||
- [FindLastBy](#FindLastBy)
|
||||
- [Flatten](#Flatten)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](#ForEach)
|
||||
@@ -62,7 +64,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)
|
||||
@@ -836,9 +840,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Find">Find</span>
|
||||
### <span id="Find">Find (废弃:使用 FindBy)</span>
|
||||
|
||||
<p>遍历切片的元素,返回第一个通过predicate函数真值测试的元素</p>
|
||||
<p>遍历slice的元素,返回第一个通过predicate函数真值测试的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -872,9 +876,45 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLast">FindLast</span>
|
||||
### <span id="FindBy">FindBy</span>
|
||||
|
||||
<p>从头到尾遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。</p>
|
||||
<p>遍历slice的元素,返回第一个通过predicate函数真值测试的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLast">FindLast(废弃:使用 FindLastBy)</span>
|
||||
|
||||
<p>遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -908,6 +948,42 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FindLastBy">FindLastBy</span>
|
||||
|
||||
<p>从遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Flatten">Flatten</span>
|
||||
|
||||
<p>将切片压平一层</p>
|
||||
@@ -1473,7 +1549,7 @@ func main() {
|
||||
|
||||
### <span id="Reduce">Reduce</span>
|
||||
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果</p>
|
||||
<p>将切片中的元素依次运行iteratee函数,返回运行结果(废弃:建议使用ReduceBy)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1505,6 +1581,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>
|
||||
|
||||
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]
|
||||
}
|
||||
```
|
||||
233
docs/strutil.md
233
docs/strutil.md
@@ -45,6 +45,13 @@ import (
|
||||
- [Unwrap](#Unwrap)
|
||||
- [SplitWords](#SplitWords)
|
||||
- [WordCount](#WordCount)
|
||||
- [RemoveNonPrintable](#RemoveNonPrintable)
|
||||
- [StringToBytes](#StringToBytes)
|
||||
- [BytesToString](#BytesToString)
|
||||
- [IsBlank](#IsBlank)
|
||||
- [HasPrefixAny](#HasPrefixAny)
|
||||
- [HasSuffixAny](#HasSuffixAny)
|
||||
- [IndexOffset](#IndexOffset)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -851,7 +858,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitWords">SplitWords</span>
|
||||
|
||||
<p>Splits a string into words, word only contains alphabetic characters.</p>
|
||||
@@ -895,7 +901,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="WordCount">WordCount</span>
|
||||
|
||||
<p>Return the number of meaningful word, word only contains alphabetic characters.</p>
|
||||
@@ -937,4 +942,226 @@ 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
|
||||
// 你好😄
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StringToBytes">StringToBytes</span>
|
||||
|
||||
<p>Converts a string to byte slice without a memory allocation.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func StringToBytes(str string) (b []byte)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.StringToBytes("abc")
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BytesToString">BytesToString</span>
|
||||
|
||||
<p>Converts a byte slice to string without a memory allocation.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BytesToString(bytes []byte) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
result := strutil.BytesToString(bytes)
|
||||
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsBlank">IsBlank</span>
|
||||
|
||||
<p>Checks if a string is whitespace or empty.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.IsBlank("")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HasPrefixAny">HasPrefixAny</span>
|
||||
|
||||
<p>Checks if a string starts with any of an array of specified strings.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HasPrefixAny(str string, prefixes []string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HasSuffixAny">HasSuffixAny</span>
|
||||
|
||||
<p>Checks if a string ends with any of an array of specified strings.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HasSuffixAny(str string, suffixes []string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOffset">IndexOffset</span>
|
||||
|
||||
<p>Returns the index of the first instance of substr in string after offsetting the string by `idxFrom`, or -1 if substr is not present in string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IndexOffset(str string, substr string, idxFrom int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "foo bar hello world"
|
||||
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -45,6 +45,13 @@ import (
|
||||
- [Unwrap](#Unwrap)
|
||||
- [SplitWords](#SplitWords)
|
||||
- [WordCount](#WordCount)
|
||||
- [RemoveNonPrintable](#RemoveNonPrintable)
|
||||
- [StringToBytes](#StringToBytes)
|
||||
- [BytesToString](#BytesToString)
|
||||
- [IsBlank](#IsBlank)
|
||||
- [HasPrefixAny](#HasPrefixAny)
|
||||
- [HasSuffixAny](#HasSuffixAny)
|
||||
- [IndexOffset](#IndexOffset)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -894,7 +901,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="WordCount">WordCount</span>
|
||||
|
||||
<p>返回有意义单词的数量,只支持字母字符单词。</p>
|
||||
@@ -936,4 +942,226 @@ 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
|
||||
// 你好😄
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StringToBytes">StringToBytes</span>
|
||||
|
||||
<p>在不分配内存的情况下将字符串转换为字节片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StringToBytes(str string) (b []byte)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.StringToBytes("abc")
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BytesToString">BytesToString</span>
|
||||
|
||||
<p>在不分配内存的情况下将字节切片转换为字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BytesToString(bytes []byte) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
result := strutil.BytesToString(bytes)
|
||||
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsBlank">IsBlank</span>
|
||||
|
||||
<p>检查字符串是否为空格或空。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.IsBlank("")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HasPrefixAny">HasPrefixAny</span>
|
||||
|
||||
<p>检查字符串是否以指定字符串数组中的任何一个开头。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HasPrefixAny(str string, prefixes []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HasSuffixAny">HasSuffixAny</span>
|
||||
|
||||
<p>检查字符串是否以指定字符串数组中的任何一个结尾。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HasSuffixAny(str string, suffixes []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOffset">IndexOffset</span>
|
||||
|
||||
<p>将字符串偏移idxFrom后,返回字符串中第一个 substr 实例的索引,如果字符串中不存在 substr,则返回 -1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IndexOffset(str string, substr string, idxFrom int) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "foo bar hello world"
|
||||
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -239,14 +239,17 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
|
||||
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -246,7 +246,10 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
114
fileutil/file.go
114
fileutil/file.go
@@ -7,6 +7,11 @@ package fileutil
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -15,6 +20,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -67,14 +73,14 @@ func RemoveFile(path string) error {
|
||||
|
||||
// CopyFile copy src file to dest file.
|
||||
// Play: https://go.dev/play/p/Jg9AMJMLrJi
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
srcFile, err := os.Open(srcFilePath)
|
||||
func CopyFile(srcPath string, dstPath string) error {
|
||||
srcFile, err := os.Open(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
distFile, err := os.Create(dstFilePath)
|
||||
distFile, err := os.Create(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -173,6 +179,23 @@ func ListFileNames(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IsZipFile checks if file is zip or not.
|
||||
// Play: todo
|
||||
func IsZipFile(filepath string) bool {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := make([]byte, 4)
|
||||
if n, err := f.Read(buf); err != nil || n < 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.Equal(buf, []byte("PK\x03\x04"))
|
||||
}
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory.
|
||||
// Play: https://go.dev/play/p/j-3sWBp8ik_P
|
||||
func Zip(fpath string, destPath string) error {
|
||||
@@ -275,6 +298,7 @@ func UnZip(zipFile string, destPath string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -345,3 +369,87 @@ func MiMeType(file any) string {
|
||||
}
|
||||
return mediatype
|
||||
}
|
||||
|
||||
// CurrentPath return current absolute path.
|
||||
// Play: https://go.dev/play/p/s74a9iBGcSw
|
||||
func CurrentPath() string {
|
||||
var absPath string
|
||||
_, filename, _, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
absPath = path.Dir(filename)
|
||||
}
|
||||
|
||||
return absPath
|
||||
}
|
||||
|
||||
// FileSize returns file size in bytes.
|
||||
// Play: todo
|
||||
func FileSize(path string) (int64, error) {
|
||||
f, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.Size(), nil
|
||||
}
|
||||
|
||||
// MTime returns file modified time.
|
||||
// Play: todo
|
||||
func MTime(filepath string) (int64, error) {
|
||||
f, err := os.Stat(filepath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.ModTime().Unix(), nil
|
||||
}
|
||||
|
||||
// MTime returns file sha value, param `shaType` should be 1, 256 or 512.
|
||||
// Play: todo
|
||||
func Sha(filepath string, shaType ...int) (string, error) {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
h := sha1.New()
|
||||
if len(shaType) > 0 {
|
||||
if shaType[0] == 1 {
|
||||
h = sha1.New()
|
||||
} else if shaType[0] == 256 {
|
||||
h = sha256.New()
|
||||
} else if shaType[0] == 512 {
|
||||
h = sha512.New()
|
||||
} else {
|
||||
return "", errors.New("param `shaType` should be 1, 256 or 512.")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = io.Copy(h, file)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sha := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
return sha, nil
|
||||
|
||||
}
|
||||
|
||||
// ReadCsvFile read file content into slice.
|
||||
// Play: todo
|
||||
func ReadCsvFile(filepath string) ([][]string, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
csvReader := csv.NewReader(f)
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
@@ -223,3 +223,65 @@ func ExampleUnZip() {
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
|
||||
func ExampleIsZipFile() {
|
||||
result1 := IsZipFile("./file.go")
|
||||
result2 := IsZipFile("./testdata/file.go.zip")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFileSize() {
|
||||
size, err := FileSize("./testdata/test.txt")
|
||||
|
||||
fmt.Println(size)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// 20
|
||||
// <nil>
|
||||
}
|
||||
|
||||
// func ExampleMTime() {
|
||||
// mtime, err := MTime("./testdata/test.txt")
|
||||
|
||||
// fmt.Println(mtime) // 1682478195 (unix timestamp)
|
||||
// fmt.Println(err)
|
||||
|
||||
// // Output:
|
||||
// // 1682478195
|
||||
// // <nil>
|
||||
// }
|
||||
|
||||
func ExampleSha() {
|
||||
sha1, err := Sha("./testdata/test.txt", 1)
|
||||
sha256, _ := Sha("./testdata/test.txt", 256)
|
||||
sha512, _ := Sha("./testdata/test.txt", 512)
|
||||
|
||||
fmt.Println(sha1)
|
||||
fmt.Println(sha256)
|
||||
fmt.Println(sha512)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
|
||||
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
|
||||
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleReadCsvFile() {
|
||||
content, err := ReadCsvFile("./testdata/test.csv")
|
||||
|
||||
fmt.Println(content)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestReadFileToString(t *testing.T) {
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(path)
|
||||
@@ -127,7 +127,7 @@ func TestClearFile(t *testing.T) {
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = ClearFile(path)
|
||||
@@ -151,7 +151,7 @@ func TestReadFileByLine(t *testing.T) {
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expected := []string{"hello", "world"}
|
||||
@@ -198,9 +198,9 @@ func TestFileMode(t *testing.T) {
|
||||
CreateFile(srcFile)
|
||||
|
||||
mode, err := FileMode(srcFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log(mode)
|
||||
assert.IsNotNil(mode)
|
||||
assert.IsNil(err)
|
||||
|
||||
os.Remove(srcFile)
|
||||
}
|
||||
@@ -235,9 +235,64 @@ 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)
|
||||
}
|
||||
|
||||
func TestIsZipFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsZipFile")
|
||||
|
||||
assert.Equal(false, IsZipFile("./file.go"))
|
||||
assert.Equal(true, IsZipFile("./testdata/file.go.zip"))
|
||||
}
|
||||
|
||||
func TestFileSize(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileSize")
|
||||
|
||||
size, err := FileSize("./testdata/test.txt")
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(int64(20), size)
|
||||
}
|
||||
|
||||
func TestMTime(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMTime")
|
||||
|
||||
mtime, err := MTime("./testdata/test.txt")
|
||||
t.Log("TestMTime", mtime)
|
||||
assert.IsNil(err)
|
||||
// assert.Equal(int64(1682478195), mtime)
|
||||
}
|
||||
|
||||
func TestSha(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSha")
|
||||
|
||||
sha1, err := Sha("./testdata/test.txt", 1)
|
||||
sha256, err := Sha("./testdata/test.txt", 256)
|
||||
sha512, err := Sha("./testdata/test.txt", 512)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
|
||||
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
|
||||
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
|
||||
}
|
||||
|
||||
func TestReadCsvFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReadCsvFile")
|
||||
|
||||
content, err := ReadCsvFile("./testdata/test.csv")
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, len(content))
|
||||
assert.Equal(3, len(content[0]))
|
||||
assert.Equal("Bob", content[0][0])
|
||||
}
|
||||
|
||||
BIN
fileutil/testdata/file.go.zip
vendored
Normal file
BIN
fileutil/testdata/file.go.zip
vendored
Normal file
Binary file not shown.
3
fileutil/testdata/test.csv
vendored
Normal file
3
fileutil/testdata/test.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Bob, 12, male
|
||||
Duke, 14, male
|
||||
Lucy, 16, female
|
||||
|
1
fileutil/testdata/test.txt
vendored
Normal file
1
fileutil/testdata/test.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
this is a test file.
|
||||
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: https://go.dev/play/p/FPXs1suwRcs
|
||||
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: https://go.dev/play/p/G9oHHMCAZxP
|
||||
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: https://go.dev/play/p/Am98ybWjvjj
|
||||
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: https://go.dev/play/p/69v1tTT62x8
|
||||
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: https://go.dev/play/p/YsciGj3FH2x
|
||||
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: https://go.dev/play/p/LPLZ3lDi5ma
|
||||
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,62 @@ 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)
|
||||
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())
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -4,5 +4,5 @@ go 1.18
|
||||
|
||||
require (
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
|
||||
golang.org/x/text v0.5.0
|
||||
golang.org/x/text v0.9.0
|
||||
)
|
||||
|
||||
2
go.sum
2
go.sum
@@ -2,3 +2,5 @@ golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLU
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
|
||||
@@ -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 {
|
||||
@@ -164,7 +211,7 @@ func compare(x, y any) int {
|
||||
|
||||
}
|
||||
|
||||
// logFailedInfo make test failed and log error info
|
||||
// makeTestFailed make test failed and log error info
|
||||
func makeTestFailed(t *testing.T, caseName string, expected, actual any) {
|
||||
_, file, line, _ := runtime.Caller(2)
|
||||
errInfo := fmt.Sprintf("Case %v failed. file: %v, line: %v, expected: %v, actual: %v.", caseName, file, line, expected, actual)
|
||||
|
||||
@@ -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}}
|
||||
}
|
||||
|
||||
181
maputil/typemap.go
Normal file
181
maputil/typemap.go
Normal file
@@ -0,0 +1,181 @@
|
||||
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)
|
||||
|
||||
*/
|
||||
// Play: https://go.dev/play/p/4K7KBEPgS5M
|
||||
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"
|
||||
@@ -77,7 +78,6 @@ func TestAverage(t *testing.T) {
|
||||
assert.Equal(Average(0, 0), 0)
|
||||
assert.Equal(Average(1, 1), 1)
|
||||
avg := Average(1.2, 1.4)
|
||||
t.Log(avg)
|
||||
assert.Equal(1.3, RoundToFloat(avg, 1))
|
||||
}
|
||||
|
||||
@@ -139,7 +139,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 +155,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 +167,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))
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestHttpClient_Get(t *testing.T) {
|
||||
var todo Todo
|
||||
err = httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Equal(1, todo.Id)
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
// GetInternalIp return internal ipv4.
|
||||
@@ -178,3 +186,90 @@ func EncodeUrl(urlStr string) (string, error) {
|
||||
|
||||
return URL.String(), nil
|
||||
}
|
||||
|
||||
// DownloadFile will upload the file to a server.
|
||||
func UploadFile(filepath string, server string) (bool, error) {
|
||||
if !fileutil.IsExist(filepath) {
|
||||
return false, errors.New("file not exist")
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(filepath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
bodyBuffer := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(bodyBuffer)
|
||||
|
||||
formFile, err := writer.CreateFormFile("uploadfile", fileInfo.Name())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
srcFile, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
_, err = io.Copy(formFile, srcFile)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
contentType := writer.FormDataContentType()
|
||||
writer.Close()
|
||||
|
||||
_, err = http.Post(server, contentType, bodyBuffer)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DownloadFile will download the file exist in url to a local file.
|
||||
// Play: todo
|
||||
func DownloadFile(filepath string, url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// IsPingConnected checks if can ping specified host or not.
|
||||
// Play: todo
|
||||
func IsPingConnected(host string) bool {
|
||||
cmd := exec.Command("ping", host, "-c", "1", "-W", "6")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsTelnetConnected checks if can telnet specified host or not.
|
||||
// Play: todo
|
||||
func IsTelnetConnected(host string, port string) bool {
|
||||
adder := host + ":" + port
|
||||
conn, err := net.DialTimeout("tcp", adder, 5*time.Second)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ func ExampleGetInternalIp() {
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGetPublicIpInfo() {
|
||||
ipInfo, err := GetPublicIpInfo()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// func ExampleGetPublicIpInfo() {
|
||||
// ipInfo, err := GetPublicIpInfo()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
result := IsPublicIP(net.ParseIP(ipInfo.Ip))
|
||||
fmt.Println(result)
|
||||
// result := IsPublicIP(net.ParseIP(ipInfo.Ip))
|
||||
// fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
// // Output:
|
||||
// // true
|
||||
// }
|
||||
|
||||
func ExampleGetRequestPublicIp() {
|
||||
ip := "36.112.24.10"
|
||||
@@ -178,3 +178,26 @@ func ExampleConvertMapToQueryString() {
|
||||
// Output:
|
||||
// a=1&b=2&c=3
|
||||
}
|
||||
|
||||
func ExampleIsPingConnected() {
|
||||
// result1 := IsPingConnected("bing.com")
|
||||
result2 := IsPingConnected("www.!@#&&&.com")
|
||||
|
||||
// fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIsTelnetConnected() {
|
||||
result1 := IsTelnetConnected("bing.com", "80")
|
||||
result2 := IsTelnetConnected("www.baidu.com", "123")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
@@ -40,14 +40,14 @@ func TestGetRequestPublicIp(t *testing.T) {
|
||||
assert.Equal(publicIp, ip)
|
||||
}
|
||||
|
||||
func TestGetPublicIpInfo(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
|
||||
// func TestGetPublicIpInfo(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestGetPublicIpInfo")
|
||||
|
||||
publicIpInfo, err := GetPublicIpInfo()
|
||||
assert.IsNil(err)
|
||||
// publicIpInfo, err := GetPublicIpInfo()
|
||||
// assert.IsNil(err)
|
||||
|
||||
t.Logf("public ip info is: %+v \n", *publicIpInfo)
|
||||
}
|
||||
// t.Logf("public ip info is: %+v \n", *publicIpInfo)
|
||||
// }
|
||||
|
||||
func TestIsPublicIP(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsPublicIP")
|
||||
@@ -98,14 +98,42 @@ func TestGetMacAddrs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEncodeUrl(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsInternalIP")
|
||||
assert := internal.NewAssert(t, "TestEncodeUrl")
|
||||
|
||||
urlAddr := "http://www.lancet.com?a=1&b=[2]"
|
||||
encodedUrl, err := EncodeUrl(urlAddr)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
expected := "http://www.lancet.com?a=1&b=%5B2%5D"
|
||||
assert.Equal(expected, encodedUrl)
|
||||
}
|
||||
|
||||
// func TestDownloadFile(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestDownloadFile")
|
||||
|
||||
// err := DownloadFile("./lancet_logo.jpg", "https://picx.zhimg.com/v2-fc82a4199749de9cfb71e32e54f489d3_720w.jpg?source=172ae18b")
|
||||
// assert.IsNil(err)
|
||||
// }
|
||||
|
||||
func TestIsPingConnected(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsPingConnected")
|
||||
|
||||
// in github action env, this will fail
|
||||
// result1 := IsPingConnected("bing.com")
|
||||
// assert.Equal(true, result1)
|
||||
|
||||
result2 := IsPingConnected("www.!@#&&&.com")
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
func TestTelnetConnected(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTelnetConnected")
|
||||
|
||||
result1 := IsTelnetConnected("bing.com", "80")
|
||||
assert.Equal(true, result1)
|
||||
|
||||
result2 := IsTelnetConnected("www.baidu.com", "123")
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package async contain some featurese to support async programming. eg, promise, asycn/await, eventbus.
|
||||
package async
|
||||
// Package promise contains some functions to support async programming.
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
package async
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
package async
|
||||
package promise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -57,7 +57,6 @@ func TestRandNumeralOrLetter(t *testing.T) {
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
randStr := RandNumeralOrLetter(10)
|
||||
t.Log(randStr)
|
||||
|
||||
assert := internal.NewAssert(t, "TestRandNumeralOrLetter")
|
||||
assert.Equal(10, len(randStr))
|
||||
@@ -68,7 +67,6 @@ func TestRandInt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRandInt")
|
||||
|
||||
r1 := RandInt(1, 10)
|
||||
t.Log(r1)
|
||||
assert.GreaterOrEqual(r1, 1)
|
||||
assert.Less(r1, 10)
|
||||
|
||||
@@ -99,7 +97,6 @@ func TestUUIdV4(t *testing.T) {
|
||||
|
||||
uuid, err := UUIdV4()
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
|
||||
@@ -319,7 +319,27 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]
|
||||
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/CBKeBoHVLgq
|
||||
// Deprecated
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
v, ok := FindBy(slice, predicate)
|
||||
return &v, ok
|
||||
}
|
||||
|
||||
// FindLast iterates over elements of slice from end to begin,
|
||||
// return the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/FFDPV_j7URd
|
||||
// Deprecated
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
v, ok := FindLastBy(slice, predicate)
|
||||
return &v, ok
|
||||
}
|
||||
|
||||
// FindBy iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil or zero value then no items matched the predicate func.
|
||||
// In contrast to Find or FindLast, its return value no longer requires dereferencing
|
||||
// Play: todo
|
||||
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool) {
|
||||
index := -1
|
||||
|
||||
for i, v := range slice {
|
||||
@@ -330,17 +350,17 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return nil, false
|
||||
return v, false
|
||||
}
|
||||
|
||||
return &slice[index], true
|
||||
return slice[index], true
|
||||
}
|
||||
|
||||
// FindLast iterates over elements of slice from end to begin,
|
||||
// return the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/FFDPV_j7URd
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
// FindLastBy iterates over elements of slice, returning the last one that passes a truth test on predicate function.
|
||||
// If return T is nil or zero value then no items matched the predicate func.
|
||||
// In contrast to Find or FindLast, its return value no longer requires dereferencing
|
||||
// Play: todo
|
||||
func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool) {
|
||||
index := -1
|
||||
|
||||
for i := len(slice) - 1; i >= 0; i-- {
|
||||
@@ -351,10 +371,10 @@ func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, boo
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return nil, false
|
||||
return v, false
|
||||
}
|
||||
|
||||
return &slice[index], true
|
||||
return slice[index], true
|
||||
}
|
||||
|
||||
// Flatten flattens slice with one level.
|
||||
@@ -423,6 +443,7 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
|
||||
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||
// when iteratee return false, will break the for each loop.
|
||||
// Play: https://go.dev/play/p/qScs39f3D9W
|
||||
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
||||
for i, v := range slice {
|
||||
if !iteratee(i, v) {
|
||||
@@ -491,6 +512,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: https://go.dev/play/p/YKDpLi7gtee
|
||||
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: https://go.dev/play/p/qT9dZC03A1K
|
||||
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 {
|
||||
@@ -1093,7 +1138,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
|
||||
}
|
||||
|
||||
@@ -341,6 +341,40 @@ func ExampleFindLast() {
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFindBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := FindBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFindLastBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := FindLastBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFlatten() {
|
||||
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
|
||||
@@ -460,6 +494,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"}
|
||||
|
||||
|
||||
@@ -249,6 +249,44 @@ func TestFind(t *testing.T) {
|
||||
assert.Equal(2, *res)
|
||||
}
|
||||
|
||||
func TestFindBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFindBy")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := FindBy(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
assert.Equal(2, res)
|
||||
|
||||
res, ok = FindBy(nums, func(_ int, v int) bool {
|
||||
return v == 6
|
||||
})
|
||||
assert.Equal(res == 0 && ok == false, true)
|
||||
}
|
||||
|
||||
func TestFindLastBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFindBy")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := FindLastBy(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
assert.Equal(4, res)
|
||||
|
||||
res, ok = FindLastBy(nums, func(_ int, v int) bool {
|
||||
return v == 6
|
||||
})
|
||||
assert.Equal(res == 0 && ok == false, true)
|
||||
}
|
||||
|
||||
func TestFindLast(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
@@ -405,6 +443,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)
|
||||
@@ -530,7 +594,6 @@ func TestInsertAt(t *testing.T) {
|
||||
assert.Equal([]string{"a", "b", "c", "1"}, InsertAt(strs, 3, "1"))
|
||||
assert.Equal([]string{"1", "2", "3", "a", "b", "c"}, InsertAt(strs, 0, []string{"1", "2", "3"}))
|
||||
assert.Equal([]string{"a", "b", "c", "1", "2", "3"}, InsertAt(strs, 3, []string{"1", "2", "3"}))
|
||||
t.Log(strs)
|
||||
}
|
||||
|
||||
func TestUpdateAt(t *testing.T) {
|
||||
@@ -665,8 +728,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
|
||||
}
|
||||
@@ -757,10 +820,9 @@ func TestSortBy(t *testing.T) {
|
||||
return a.Age < b.Age
|
||||
})
|
||||
|
||||
t.Logf("sort users by age: %v", users)
|
||||
|
||||
// output
|
||||
// [{b 15} {a 21} {c 100}]
|
||||
assert.EqualValues(15, users[0].Age)
|
||||
assert.EqualValues(21, users[1].Age)
|
||||
assert.EqualValues(100, users[2].Age)
|
||||
}
|
||||
|
||||
func TestSortByFielDesc(t *testing.T) {
|
||||
@@ -826,7 +888,6 @@ func TestShuffle(t *testing.T) {
|
||||
|
||||
s := []int{1, 2, 3, 4, 5}
|
||||
res := Shuffle(s)
|
||||
t.Log("Shuffle result: ", res)
|
||||
|
||||
assert.Equal(5, len(res))
|
||||
}
|
||||
@@ -873,8 +934,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")
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// CamelCase coverts string to camelCase string. Non letters and numbers will be ignored.
|
||||
@@ -360,3 +362,86 @@ 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
|
||||
}
|
||||
|
||||
// StringToBytes converts a string to byte slice without a memory allocation.
|
||||
// Play: todo
|
||||
func StringToBytes(str string) (b []byte) {
|
||||
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
|
||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
|
||||
return b
|
||||
}
|
||||
|
||||
// BytesToString converts a byte slice to string without a memory allocation.
|
||||
// Play: todo
|
||||
func BytesToString(bytes []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&bytes))
|
||||
}
|
||||
|
||||
// IsBlank checks if a string is whitespace, empty.
|
||||
// Play: todo
|
||||
func IsBlank(str string) bool {
|
||||
if len(str) == 0 {
|
||||
return true
|
||||
}
|
||||
// memory copies will occur here, but UTF8 will be compatible
|
||||
runes := []rune(str)
|
||||
for _, r := range runes {
|
||||
if !unicode.IsSpace(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasPrefixAny check if a string starts with any of an array of specified strings.
|
||||
// Play: todo
|
||||
func HasPrefixAny(str string, prefixes []string) bool {
|
||||
if len(str) == 0 || len(prefixes) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(str, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasSuffixAny check if a string ends with any of an array of specified strings.
|
||||
// Play: todo
|
||||
func HasSuffixAny(str string, suffixes []string) bool {
|
||||
if len(str) == 0 || len(suffixes) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, suffix := range suffixes {
|
||||
if strings.HasSuffix(str, suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IndexOffset returns the index of the first instance of substr in string after offsetting the string by `idxFrom`,
|
||||
// or -1 if substr is not present in string.
|
||||
// Play: todo
|
||||
func IndexOffset(str string, substr string, idxFrom int) int {
|
||||
if idxFrom > len(str)-1 || idxFrom < 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
return strings.Index(str[idxFrom:], substr) + idxFrom
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package strutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func ExampleAfter() {
|
||||
@@ -438,3 +439,92 @@ func ExampleWordCount() {
|
||||
// 0
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleRemoveNonPrintable() {
|
||||
result1 := RemoveNonPrintable("hello\u00a0 \u200bworld\n")
|
||||
result2 := RemoveNonPrintable("你好😄")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// hello world
|
||||
// 你好😄
|
||||
}
|
||||
|
||||
func ExampleStringToBytes() {
|
||||
result1 := StringToBytes("abc")
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleBytesToString() {
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
result := BytesToString(bytes)
|
||||
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
|
||||
func ExampleIsBlank() {
|
||||
result1 := IsBlank("")
|
||||
result2 := IsBlank("\t\v\f\n")
|
||||
result3 := IsBlank(" 中文")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleHasPrefixAny() {
|
||||
result1 := HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
|
||||
result2 := HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleHasSuffixAny() {
|
||||
result1 := HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
|
||||
result2 := HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIndexOffset() {
|
||||
str := "foo bar hello world"
|
||||
|
||||
result1 := IndexOffset(str, "o", 5)
|
||||
result2 := IndexOffset(str, "o", 0)
|
||||
result3 := IndexOffset(str, "d", len(str)-1)
|
||||
result4 := IndexOffset(str, "d", len(str))
|
||||
result5 := IndexOffset(str, "f", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -342,3 +343,59 @@ 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("你好😄"))
|
||||
}
|
||||
|
||||
func TestStringToBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStringToBytes")
|
||||
str := "abc"
|
||||
bytes := StringToBytes(str)
|
||||
assert.Equal(reflect.DeepEqual(bytes, []byte{'a', 'b', 'c'}), true)
|
||||
}
|
||||
|
||||
func TestBytesToString(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBytesToString")
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
str := BytesToString(bytes)
|
||||
assert.Equal(str == "abc", true)
|
||||
}
|
||||
|
||||
func TestIsBlank(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsBlank")
|
||||
assert.Equal(IsBlank(""), true)
|
||||
assert.Equal(IsBlank("\t\v\f\n"), true)
|
||||
assert.Equal(IsBlank(" 中文"), false)
|
||||
}
|
||||
|
||||
func TestHasPrefixAny(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestHasPrefixAny")
|
||||
str := "foo bar"
|
||||
prefixes := []string{"fo", "xyz", "hello"}
|
||||
notMatches := []string{"oom", "world"}
|
||||
assert.Equal(HasPrefixAny(str, prefixes), true)
|
||||
assert.Equal(HasPrefixAny(str, notMatches), false)
|
||||
}
|
||||
|
||||
func TestHasSuffixAny(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestHasSuffixAny")
|
||||
str := "foo bar"
|
||||
suffixes := []string{"bar", "xyz", "hello"}
|
||||
notMatches := []string{"oom", "world"}
|
||||
assert.Equal(HasSuffixAny(str, suffixes), true)
|
||||
assert.Equal(HasSuffixAny(str, notMatches), false)
|
||||
}
|
||||
|
||||
func TestIndexOffset(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIndexOffset")
|
||||
str := "foo bar hello world"
|
||||
assert.Equal(IndexOffset(str, "o", 5), 12)
|
||||
assert.Equal(IndexOffset(str, "o", 0), 1)
|
||||
assert.Equal(IndexOffset(str, "d", len(str)-1), len(str)-1)
|
||||
assert.Equal(IndexOffset(str, "d", len(str)), -1)
|
||||
assert.Equal(IndexOffset(str, "f", -1), -1)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
19
system/os_darwin.go
Normal file
19
system/os_darwin.go
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build darwin
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func WithForeground() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func WithWinHide() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
|
||||
}
|
||||
}
|
||||
26
system/os_linux.go
Normal file
26
system/os_linux.go
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build linux
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithWinHide() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,16 @@ func TestExecCommand(t *testing.T) {
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
// func TestExecCommandWithOption(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestExecCommandWithOption")
|
||||
|
||||
// stdout, stderr, err := ExecCommand("ls", WithForeground())
|
||||
// t.Log("std out: ", stdout)
|
||||
// t.Log("std err: ", stderr)
|
||||
// assert.Equal("", stderr)
|
||||
// assert.IsNil(err)
|
||||
// }
|
||||
|
||||
func TestGetOsBits(t *testing.T) {
|
||||
osBits := GetOsBits()
|
||||
switch osBits {
|
||||
|
||||
26
system/os_windows.go
Normal file
26
system/os_windows.go
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build windows
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithForeground() Option {
|
||||
return func(c *exec.Cmd) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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: https://go.dev/play/p/mdJHOAvtsvF
|
||||
func IsNumber(v any) bool {
|
||||
return IsInt(v) || IsFloat(v)
|
||||
}
|
||||
|
||||
// IsFloat check if the value is float(float32, float34) or not.
|
||||
// Play: https://go.dev/play/p/vsyG-sxr99_Z
|
||||
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: https://go.dev/play/p/eFoIHbgzl-z
|
||||
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