mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-15 02:02:27 +08:00
Compare commits
114 Commits
v2.1.9
...
ca2a51b37e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca2a51b37e | ||
|
|
be444f521d | ||
|
|
e21dd07d46 | ||
|
|
4044deac70 | ||
|
|
d9c6294775 | ||
|
|
d8505d1a5f | ||
|
|
6498c7d68a | ||
|
|
5f0211f0c4 | ||
|
|
1de2e2cedd | ||
|
|
c8f8b1b7d9 | ||
|
|
3062eb7789 | ||
|
|
64d5486cc6 | ||
|
|
6d57891f66 | ||
|
|
927245e47f | ||
|
|
31fdbee0b5 | ||
|
|
3712819994 | ||
|
|
6d7dec1cea | ||
|
|
9b6a004dbc | ||
|
|
3ad6f4bd9e | ||
|
|
b8c6746f31 | ||
|
|
0bf8bbf4cb | ||
|
|
a6ba1028c5 | ||
|
|
cc54dd7ec9 | ||
|
|
54834dba4c | ||
|
|
e996d4c945 | ||
|
|
ae92ae7666 | ||
|
|
526e568d0e | ||
|
|
1dc5e8ac23 | ||
|
|
b5f7b0e670 | ||
|
|
39c576248c | ||
|
|
eb164d1536 | ||
|
|
68e170080c | ||
|
|
652b09135c | ||
|
|
bff24c89bc | ||
|
|
49a460eef8 | ||
|
|
a58e52e53c | ||
|
|
b07356423f | ||
|
|
005dd9d2ab | ||
|
|
65315dafb1 | ||
|
|
b06fb6736d | ||
|
|
b9f0854950 | ||
|
|
6a2dd328ad | ||
|
|
dd1147f6d0 | ||
|
|
6da7ce64af | ||
|
|
b7e5d946f1 | ||
|
|
687db4ce79 | ||
|
|
a9a4bb8841 | ||
|
|
bc6cb5f61b | ||
|
|
2c57266f8e | ||
|
|
57e49c9520 | ||
|
|
985c9a5d9a | ||
|
|
5cfb11f036 | ||
|
|
5b3d48a1e7 | ||
|
|
d0576e028f | ||
|
|
76bdec2b54 | ||
|
|
fa20aba3a7 | ||
|
|
7a4a429e23 | ||
|
|
a70ec6ad1e | ||
|
|
e435fa271b | ||
|
|
1533d00891 | ||
|
|
8b99641de0 | ||
|
|
251f899f18 | ||
|
|
00407e5182 | ||
|
|
4e457ad672 | ||
|
|
7d8d9c3543 | ||
|
|
1197e8d1b6 | ||
|
|
13bbe19ab2 | ||
|
|
2725575d2f | ||
|
|
037d2729ce | ||
|
|
09d98745b0 | ||
|
|
af5cfe6da1 | ||
|
|
d59259bbe0 | ||
|
|
3189628d54 | ||
|
|
62c5e251a5 | ||
|
|
6e6444c8c0 | ||
|
|
dd613e98b2 | ||
|
|
2d905ab03e | ||
|
|
205fedb197 | ||
|
|
4c864da62d | ||
|
|
263ab7e316 | ||
|
|
809b7a53df | ||
|
|
61c43daabb | ||
|
|
18914ee2cd | ||
|
|
0a8058956f | ||
|
|
a044da7d2f | ||
|
|
f8b785c4cb | ||
|
|
82c8a04c35 | ||
|
|
280ecb5cef | ||
|
|
ec27ad4c40 | ||
|
|
d66f92cd68 | ||
|
|
d8ed692651 | ||
|
|
a16de97d1d | ||
|
|
6f458e4367 | ||
|
|
37c7508ad0 | ||
|
|
acb5844b15 | ||
|
|
76f4eeea16 | ||
|
|
5466a23019 | ||
|
|
5692982dd1 | ||
|
|
c39c8914fb | ||
|
|
29bdca1bd2 | ||
|
|
eb66d038ac | ||
|
|
a99ada5ee1 | ||
|
|
a87faf5453 | ||
|
|
ab6fec2f69 | ||
|
|
7b290989f5 | ||
|
|
5722c724e6 | ||
|
|
f84584ca04 | ||
|
|
80cbbdc787 | ||
|
|
be148e07ba | ||
|
|
d36ab5cc3a | ||
|
|
2b17329094 | ||
|
|
f869a0a670 | ||
|
|
be000a4bd6 | ||
|
|
81efa800ea |
833
README.md
833
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)
|
||||
@@ -32,16 +32,16 @@ English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
### Note:
|
||||
|
||||
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause v2.x.x rewrite all functions with generics of go1.18.</b>
|
||||
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause in v2.x.x all functions was rewriten with generics of go1.18.</b>
|
||||
|
||||
```go
|
||||
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. now latest v1 is v1.3.3. </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.5. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.3.3 // below go1.18, install latest version of v1.x.x
|
||||
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -71,9 +71,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
## [lancet API doc](https://uvdream.github.io/lancet-docs/) Thanks [@UvDream](https://github.com/UvDream) for contributing.
|
||||
## Documentation
|
||||
|
||||
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
|
||||
|
||||
@@ -83,18 +81,41 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BubbleSort)
|
||||
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#CountSort)
|
||||
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#HeapSort)
|
||||
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#InsertionSort)
|
||||
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#MergeSort)
|
||||
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#QuickSort)
|
||||
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#SelectionSort)
|
||||
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#ShellSort)
|
||||
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinarySearch)
|
||||
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinaryIterativeSearch)
|
||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)
|
||||
- **<big>BubbleSort</big>** : sorts slice with bubble sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BubbleSort)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>CountSort</big>** : sorts slice with bubble sort algorithm, don't change original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#CountSort)]
|
||||
[[play](https://go.dev/play/p/tB-Umgm0DrP)]
|
||||
- **<big>HeapSort</big>** : sorts slice with heap sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#HeapSort)]
|
||||
[[play](https://go.dev/play/p/u6Iwa1VZS_f)]
|
||||
- **<big>InsertionSort</big>** : sorts slice with insertion sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#InsertionSort)]
|
||||
[[play](https://go.dev/play/p/G5LJiWgJJW6)]
|
||||
- **<big>MergeSort</big>** : sorts slice with merge sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#MergeSort)]
|
||||
[[play](https://go.dev/play/p/ydinn9YzUJn)]
|
||||
- **<big>QuickSort</big>** : sorts slice with quick sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#QuickSort)]
|
||||
[[play](https://go.dev/play/p/7Y7c1Elk3ax)]
|
||||
- **<big>SelectionSort</big>** : sorts slice with selection sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#SelectionSort)]
|
||||
[[play](https://go.dev/play/p/oXovbkekayS)]
|
||||
- **<big>ShellSort</big>** : sorts slice with shell sort algorithm, will change the original slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#ShellSort)]
|
||||
[[play](https://go.dev/play/p/3ibkszpJEu3)]
|
||||
- **<big>BinarySearch</big>** : returns the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinarySearch)]
|
||||
[[play](https://go.dev/play/p/t6MeGiUSN47)]
|
||||
- **<big>BinaryIterativeSearch</big>** : returns the index of target within a sorted slice, use binary search (no recursive).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinaryIterativeSearch)]
|
||||
[[play](https://go.dev/play/p/Anozfr8ZLH3)]
|
||||
- **<big>LinearSearch</big>** : returns the index of target in slice base on equal function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)]
|
||||
- **<big>LRUCache</big>** : implements memory cache with lru 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.
|
||||
|
||||
@@ -104,16 +125,26 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)
|
||||
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Bridge)
|
||||
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)
|
||||
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)
|
||||
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)
|
||||
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)
|
||||
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)
|
||||
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)
|
||||
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)
|
||||
- **<big>NewChannel</big>** : create a Channel pointer instance.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)]
|
||||
- **<big>Bridge</big>** : link multiply channels into one channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)]
|
||||
- **<big>FanIn</big>** : merge multiple channels into one channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)]
|
||||
- **<big>Generate</big>** : creates a channel, then put values into the channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)]
|
||||
- **<big>Or</big>** : read one or more channels into one channel, will close when any readin channel is closed.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)]
|
||||
- **<big>OrDone</big>** : read a channel into another channel, will close until cancel context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)]
|
||||
- **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)]
|
||||
- **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)]
|
||||
- **<big>Take</big>** : create a channel whose values are taken from another channel with limit number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)]
|
||||
- **<big>Tee</big>** : split one chanel into two channels, until cancel the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
|
||||
|
||||
### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
|
||||
|
||||
@@ -123,13 +154,30 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Bool](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Bool)
|
||||
- [And](https://github.com/duke-git/lancet/blob/main/docs/condition.md#And)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)
|
||||
- [Xor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)
|
||||
- [Nor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nor)
|
||||
- [Nand](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nand)
|
||||
- [TernaryOperator](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)
|
||||
- **<big>Bool</big>** : returns the truthy value of anything.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Bool)]
|
||||
[[play](https://go.dev/play/p/ETzeDJRSvhm)]
|
||||
- **<big>And</big>** : returns true if both a and b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#And)]
|
||||
[[play](https://go.dev/play/p/W1SSUmt6pvr)]
|
||||
- **<big>Or</big>** : returns false if neither a nor b is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)]
|
||||
[[play](https://go.dev/play/p/UlQTxHaeEkq)]
|
||||
- **<big>Xor</big>** : returns true if a or b but not both is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)]
|
||||
[[play](https://go.dev/play/p/gObZrW7ZbG8)]
|
||||
- **<big>Nor</big>** : returns true if neither a nor b is truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nor)]
|
||||
[[play](https://go.dev/play/p/g2j08F_zZky)
|
||||
- **<big>Xnor</big>** : returns true if both a and b or neither a nor b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xnor)]
|
||||
[[play](https://go.dev/play/p/OuDB9g51643)]
|
||||
- **<big>Nand</big>** : returns false if both a and b are truthy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nand)]
|
||||
[[play](https://go.dev/play/p/vSRMLxLIbq8)]
|
||||
- **<big>TernaryOperator</big>** : ternary operator.
|
||||
[[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.
|
||||
|
||||
@@ -139,22 +187,54 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)
|
||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)
|
||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
|
||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
|
||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
|
||||
- [ToChannel](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChannel)
|
||||
- [ToFloat](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToFloat)
|
||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
|
||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
|
||||
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToMap)
|
||||
- [ToPointer](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToPointer)
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
|
||||
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)
|
||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#EncodeByte)
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)
|
||||
- **<big>ColorHexToRGB</big>** : convert color hex to color rgb.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)]
|
||||
[[play](https://go.dev/play/p/o7_ft-JCJBV)]
|
||||
- **<big>ColorRGBToHex</big>** : convert rgb color to hex color.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)]
|
||||
[[play](https://go.dev/play/p/nzKS2Ro87J1)]
|
||||
- **<big>ToBool</big>** : convert string to bool.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)]
|
||||
[[play](https://go.dev/play/p/ARht2WnGdIN)]
|
||||
- **<big>ToBytes</big>** : convert value to byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)]
|
||||
[[play](https://go.dev/play/p/fAMXYFDvOvr)]
|
||||
- **<big>ToChar</big>** : convert string to char slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)]
|
||||
[[play](https://go.dev/play/p/JJ1SvbFkVdM)]
|
||||
- **<big>ToChannel</big>** : convert a collection of elements to a read-only channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChannel)]
|
||||
[[play](https://go.dev/play/p/hOx_oYZbAnL)]
|
||||
- **<big>ToFloat</big>** : convert value to float64, if param is a invalid floatable, will return 0.0 and error.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToFloat)]
|
||||
[[play](https://go.dev/play/p/4YTmPCibqHJ)]
|
||||
- **<big>ToInt</big>** : convert value to int64 value, if input is not numerical, return 0 and error.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)]
|
||||
[[play](https://go.dev/play/p/9_h9vIt-QZ_b)]
|
||||
- **<big>ToJson</big>** : convert value to a json string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)]
|
||||
[[play](https://go.dev/play/p/2rLIkMmXWvR)]
|
||||
- **<big>ToMap</big>** : convert a slice of structs to a map based on iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToMap)]
|
||||
[[play](https://go.dev/play/p/tVFy7E-t24l)]
|
||||
- **<big>ToPointer</big>** : return a pointer of passed value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToPointer)]
|
||||
[[play](https://go.dev/play/p/ASf_etHNlw1)]
|
||||
- **<big>ToString</big>** : convert value to string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)]
|
||||
[[play](https://go.dev/play/p/nF1zOOslpQq)]
|
||||
- **<big>StructToMap</big>** : convert struct to map, only convert exported struct field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)]
|
||||
[[play](https://go.dev/play/p/KYGYJqNUBOI)]
|
||||
- **<big>MapToSlice</big>** : convert map to slice based on iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)]
|
||||
[[play](https://go.dev/play/p/dmX4Ix5V6Wl)]
|
||||
- **<big>EncodeByte</big>** : encode data to byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#EncodeByte)]
|
||||
[[play](https://go.dev/play/p/DVmM1G5JfuP)]
|
||||
- **<big>DecodeByte</big>** : decode byte slice data to target object.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)]
|
||||
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
|
||||
|
||||
### 5. Cryptor package is for data encryption and decryption.
|
||||
|
||||
@@ -268,21 +348,51 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)
|
||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)
|
||||
- [CreateDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateDir)
|
||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)
|
||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)
|
||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)
|
||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)
|
||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)
|
||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)
|
||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)
|
||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)
|
||||
- **<big>ClearFile</big>** : write empty string to target file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)]
|
||||
[[play](https://go.dev/play/p/NRZ0ZT-G94H)]
|
||||
- **<big>CreateFile</big>** : create file in path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)]
|
||||
[[play](https://go.dev/play/p/lDt8PEsTNKI)]
|
||||
- **<big>CreateDir</big>** : create directory in absolute path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateDir)]
|
||||
[[play](https://go.dev/play/p/qUuCe1OGQnM)]
|
||||
- **<big>CopyFile</big>** :copy src file to dest file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)]
|
||||
[[play](https://go.dev/play/p/Jg9AMJMLrJi)]
|
||||
- **<big>FileMode</big>** : return file's mode and permission.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)]
|
||||
[[play](https://go.dev/play/p/2l2hI42fA3p)]
|
||||
- **<big>MiMeType</big>** : return file mime type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)]
|
||||
[[play](https://go.dev/play/p/bd5sevSUZNu)]
|
||||
- **<big>IsExist</big>** : checks if a file or directory exists.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)]
|
||||
[[play](https://go.dev/play/p/nKKXt8ZQbmh)]
|
||||
- **<big>IsLink</big>** : checks if a file is symbol link or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)]
|
||||
[[play](https://go.dev/play/p/TL-b-Kzvf44)]
|
||||
- **<big>IsDir</big>** : checks if the path is directory or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)]
|
||||
[[play](https://go.dev/play/p/WkVwEKqtOWk)]
|
||||
- **<big>ListFileNames</big>** : return all file names in the path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)]
|
||||
[[play](https://go.dev/play/p/Tjd7Y07rejl)]
|
||||
- **<big>RemoveFile</big>** : remove file, param should be file path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)]
|
||||
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
||||
- **<big>ReadFileToString</big>** : return string of file content.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)]
|
||||
[[play](https://go.dev/play/p/cmfwp_5SQTp)]
|
||||
- **<big>ReadFileByLine</big>** : read file line by line, return string slice of file content.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)]
|
||||
[[play](https://go.dev/play/p/svJP_7ZrBrD)]
|
||||
- **<big>Zip</big>** : create zip file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)]
|
||||
[[play](https://go.dev/play/p/j-3sWBp8ik_P)]
|
||||
- **<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)]
|
||||
|
||||
### 9. Formatter contains some functions for data formatting.
|
||||
|
||||
@@ -292,7 +402,9 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
|
||||
- **<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)]
|
||||
|
||||
### 10. Function package can control the flow of function execution and support part of functional programming
|
||||
|
||||
@@ -302,14 +414,32 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)
|
||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function.md#Curry)
|
||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)
|
||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)
|
||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)
|
||||
- [Pipeline](https://github.com/duke-git/lancet/blob/main/docs/function.md#Pipeline)
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
|
||||
- **<big>After</big>** : return a function that invokes passed funcation once the returned function is called more than n times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Before</big>** : return a function that invokes passed funcation once the returned function is called less than n times
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)]
|
||||
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
|
||||
- **<big>CurryFn</big>** : make a curry function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#CurryFn)]
|
||||
- **<big>Compose</big>** : compose the functions from right to left.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)]
|
||||
- **<big>Delay</big>** : call the function after delayed time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)]
|
||||
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
|
||||
- **<big>Debounced</big>** : creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)]
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Schedule</big>** : invoke function every duration time, util close the returned bool channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
- **<big>Pipeline</big>** : takes a list of functions and returns a function whose param will be passed into the functions one by one.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Pipeline)]
|
||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
||||
- **<big>Watcher</big>** : Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
|
||||
|
||||
|
||||
|
||||
### 11. Maputil package includes some functions to manipulate map.
|
||||
|
||||
@@ -319,14 +449,30 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)
|
||||
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)
|
||||
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)
|
||||
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)
|
||||
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)
|
||||
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)
|
||||
- **<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)]
|
||||
- **<big>Filter</big>** : iterates over map, return a new map contains all key and value pairs pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)]
|
||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)]
|
||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||
- **<big>Keys</big>** : returns a slice of the map's keys.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)]
|
||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||
- **<big>Merge</big>** : merge maps, next key will overwrite previous key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)]
|
||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||
- **<big>Minus</big>** : creates a map of whose key in mapA but not in mapB.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)]
|
||||
[[play](https://go.dev/play/p/3u5U9K7YZ9m)]
|
||||
- **<big>Values</big>** : returns a slice of the map's values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)]
|
||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
### 12. Mathutil package implements some functions for math calculation.
|
||||
|
||||
@@ -336,18 +482,41 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)
|
||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)
|
||||
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)
|
||||
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MaxBy)
|
||||
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)
|
||||
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MinBy)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)
|
||||
- **<big>Average</big>** :return average value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)]
|
||||
[[play](https://go.dev/play/p/Vv7LBwER-pz)]
|
||||
- **<big>Exponent</big>** : calculate x^n for int64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)]
|
||||
[[play](https://go.dev/play/p/uF3HGNPk8wr)]
|
||||
- **<big>Fibonacci</big>** :calculate fibonacci number before n for int.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)]
|
||||
[[play](https://go.dev/play/p/IscseUNMuUc)]
|
||||
- **<big>Factorial</big>** : calculate x! for uint.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)]
|
||||
[[play](https://go.dev/play/p/tt6LdOK67Nx)]
|
||||
- **<big>Max</big>** : return maximum value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)]
|
||||
[[play](https://go.dev/play/p/cN8DHI0rTkH)]
|
||||
- **<big>MaxBy</big>** : return the maximum value of a slice using the given comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MaxBy)]
|
||||
[[play](https://go.dev/play/p/pbe2MT-7DV2)]
|
||||
- **<big>Min</big>** : return minimum value of numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)]
|
||||
[[play](https://go.dev/play/p/21BER_mlGUj)]
|
||||
- **<big>MinBy</big>** : return the minimum value of a slice using the given comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MinBy)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>Percent</big>** : calculate the percentage of value to total.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)]
|
||||
- **<big>RoundToFloat</big>** : round up to n decimal places for float64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)]
|
||||
[[play](https://go.dev/play/p/ghyb528JRJL)]
|
||||
- **<big>RoundToString</big>** : round up to n decimal places for float64, return string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)]
|
||||
[[play](https://go.dev/play/p/kZwpBRAcllO)]
|
||||
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||
|
||||
### 13. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
@@ -371,12 +540,11 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)
|
||||
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)
|
||||
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)
|
||||
|
||||
- [HttpGet<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
||||
- [HttpDelete<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
||||
- [HttpPost<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
||||
- [HttpPut<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
|
||||
- [HttpPatch<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
|
||||
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
|
||||
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
|
||||
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
|
||||
- [HttpPut<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
|
||||
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
|
||||
|
||||
### 14. Random package implements some basic functions to generate random int and string.
|
||||
@@ -387,14 +555,30 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
|
||||
- [RandUpper](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUpper)
|
||||
- [RandLower](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
- **<big>RandBytes</big>** : generate random byte slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)]
|
||||
[[play](https://go.dev/play/p/EkiLESeXf8d)]
|
||||
- **<big>RandInt</big>** : generate random int number between min and max.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)]
|
||||
[[play](https://go.dev/play/p/pXyyAAI5YxD)]
|
||||
- **<big>RandString</big>** : generate random string of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)]
|
||||
[[play](https://go.dev/play/p/W2xvRUXA7Mi)]
|
||||
- **<big>RandUpper</big>** : generate a random upper case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUpper)]
|
||||
[[play](https://go.dev/play/p/29QfOh0DVuh)]
|
||||
- **<big>RandLower</big>** : generate a random lower case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandLower)]
|
||||
[[play](https://go.dev/play/p/XJtZ471cmtI)]
|
||||
- **<big>RandNumeral</big>** : generate a random numeral string of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeral)]
|
||||
[[play](https://go.dev/play/p/g4JWVpHsJcf)]
|
||||
- **<big>RandNumeralOrLetter</big>** : generate a random numeral or letter string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandNumeralOrLetter)]
|
||||
[[play](https://go.dev/play/p/19CEQvpx2jD)]
|
||||
- **<big>UUIdV4</big>** : generate a random UUID of version 4 according to RFC 4122.
|
||||
[[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.
|
||||
|
||||
@@ -418,54 +602,165 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)
|
||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
|
||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
|
||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
|
||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)
|
||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)
|
||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)
|
||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)
|
||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)
|
||||
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
|
||||
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)
|
||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)
|
||||
- [Equal](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)
|
||||
- [EqualWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#EqualWith)
|
||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)
|
||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)
|
||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)
|
||||
- [Flatten](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Flatten)
|
||||
- [FlattenDeep](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)
|
||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)
|
||||
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)
|
||||
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)
|
||||
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)
|
||||
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IndexOf)
|
||||
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#LastIndexOf)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)
|
||||
- [Replace](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)
|
||||
- [ReplaceAll](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReplaceAll)
|
||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)
|
||||
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)
|
||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)
|
||||
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)
|
||||
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SymmetricDifference)
|
||||
- [ToSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlice)
|
||||
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlicePointer)
|
||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)
|
||||
- [UniqueBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UniqueBy)
|
||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)
|
||||
- [UnionBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UnionBy)
|
||||
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)
|
||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
|
||||
- [KeyBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)
|
||||
- **<big>AppendIfAbsent</big>** : if the item is absent,append it to the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>Contain</big>** : check if the value is in the slice or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)]
|
||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||
- **<big>ContainSubSlice</big>** : check if the slice contain a given subslice or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)]
|
||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||
- **<big>Chunk</big>** : creates a slice of elements split into groups the length of size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)]
|
||||
[[play](https://go.dev/play/p/b4Pou5j2L_C)]
|
||||
- **<big>Compact</big>** : creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)]
|
||||
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
|
||||
- **<big>Concat</big>** : creates a new slice concatenating slice with any additional slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)]
|
||||
[[play](https://go.dev/play/p/gPt-q7zr5mk)]
|
||||
- **<big>Count</big>** : returns the number of occurrences of the given item in the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)]
|
||||
[[play](https://go.dev/play/p/Mj4oiEnQvRJ)]
|
||||
- **<big>CountBy</big>** : iterates over elements of slice with predicate function, returns the number of all matched elements.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#CountBy)]
|
||||
[[play](https://go.dev/play/p/tHOccTMDZCC)]
|
||||
- **<big>Difference</big>** : creates an slice of whose element in slice but not in compared slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)]
|
||||
[[play](https://go.dev/play/p/VXvadzLzhDa)]
|
||||
- **<big>DifferenceBy</big>** : accepts iteratee which is invoked for each element of slice and values to generate the criterion by which they're compared.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)]
|
||||
[[play](https://go.dev/play/p/DiivgwM5OnC)]
|
||||
- **<big>DifferenceWith</big>** : accepts comparator which is invoked to compare elements of slice to values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)]
|
||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
||||
- **<big>DeleteAt</big>** : delete the element of slice from specific start index to end index - 1.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Drop</big>** : creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Equal</big>** : checks if two slices are equal: the same length and all elements' order and value are equal.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Equal)]
|
||||
[[play](https://go.dev/play/p/WcRQJ37ifPa)]
|
||||
- **<big>EqualWith</big>** : checks if two slices are equal with comparator func.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>Every</big>** : return true if all of the values in the slice pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
- **<big>Filter</big>** : iterates over elements of slice, returning an slice of all elements pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)]
|
||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||
- **<big>Find</big>** : iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</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>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)]
|
||||
- **<big>FlattenDeep</big>** : flattens slice recursive to one level.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FlattenDeep)]
|
||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>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)]
|
||||
- **<big>GroupWith</big>** : return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)]
|
||||
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : convert param to int slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : convert param to interface slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>Intersection</big>** : creates a slice of unique elements that included by all slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)]
|
||||
[[play](https://go.dev/play/p/anJXfB5wq_t)]
|
||||
- **<big>InsertAt</big>** : insert the value or other slice into slice at index.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)]
|
||||
[[play](https://go.dev/play/p/hMLNxPEGJVE)]
|
||||
- **<big>IndexOf</big>** : returns the index at which the first occurrence of an item is found in a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/MRN1f0FpABb)]
|
||||
- **<big>LastIndexOf</big>** : returns the index at which the last occurrence of the item is found in a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/DokM4cf1IKH)]
|
||||
- **<big>Map</big>** : creates an slice of values by running each element of slice thru iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)]
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>Merge</big>** : merge all given slices into one slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
- **<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.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
- **<big>ReplaceAll</big>** : returns a copy of the slice with all non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReplaceAll)]
|
||||
[[play](https://go.dev/play/p/CzqXMsuYUrx)]
|
||||
- **<big>Repeat</big>** : creates a slice with length n whose elements are passed item.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Repeat)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>Shuffle</big>** : shuffle the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)]
|
||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||
- **<big>Sort</big>** : sorts a slice of any ordered type(number or string).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Sort)]
|
||||
[[play](https://go.dev/play/p/V9AVjzf_4Fk)]
|
||||
- **<big>SortBy</big>** : sorts the slice in ascending order as determined by the less function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortBy)]
|
||||
[[play](https://go.dev/play/p/DAhLQSZEumm)]
|
||||
- **<big>SortByField<sup>deprecated</sup></big>** : return sorted slice by specific field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)]
|
||||
[[play](https://go.dev/play/p/fU1prOBP9p1)]
|
||||
- **<big>Some</big>** : return true if any of the values in the list pass the predicate function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)]
|
||||
[[play](https://go.dev/play/p/4pO9Xf9NDGS)]
|
||||
- **<big>StringSlice<sup>deprecated</sup></big>** : convert param to slice of string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)]
|
||||
[[play](https://go.dev/play/p/W0TZDWCPFcI)]
|
||||
- **<big>SymmetricDifference</big>** : the symmetric difference of two slice, also known as the disjunctive union.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#h42nJX5xMln)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>ToSlice</big>** : returns a slices of a variable parameter transformation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/YzbzVq5kscN)]
|
||||
- **<big>ToSlicePointer</big>** : returns a pointer to the slices of a variable parameter transformation.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ToSlicePointer)]
|
||||
[[play](https://go.dev/play/p/gx4tr6_VXSF)]
|
||||
- **<big>Unique</big>** : remove duplicate elements in slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)]
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : call iteratee func with every item of slice, then remove duplicated.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
- **<big>UnionBy</big>** : accepts iteratee which is invoked for each element of each slice, then union slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UnionBy)]
|
||||
[[play](https://go.dev/play/p/HGKHfxKQsFi)]
|
||||
- **<big>UpdateAt</big>** : update the slice element at index.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)]
|
||||
[[play](https://go.dev/play/p/f3mh2KloWVm)]
|
||||
- **<big>Without</big>** : creates a slice excluding all given items.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)]
|
||||
[[play](https://go.dev/play/p/bwhEXEypThg)]
|
||||
- **<big>KeyBy</big>** : converts a slice to a map based on a callback function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
|
||||
### 17. Strutil package contains some functions to manipulate string.
|
||||
|
||||
@@ -475,23 +770,64 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)
|
||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)
|
||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)
|
||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)
|
||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
|
||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
|
||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
|
||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
|
||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
|
||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
|
||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
|
||||
- **<big>After</big>** : returns the substring after the first occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)]
|
||||
[[play](https://go.dev/play/p/RbCOQqCDA7m)]
|
||||
- **<big>AfterLast</big>** : returns the substring after the last occurrence of a specified string in the source string. [[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)]
|
||||
[[play](https://go.dev/play/p/1TegARrb8Yn)]
|
||||
- **<big>Before</big>** : returns the substring before the first occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)]
|
||||
[[play](https://go.dev/play/p/JAWTZDS4F5w)]
|
||||
- **<big>BeforeLast</big>** : returns the substring before the last occurrence of a specified string in the source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)]
|
||||
[[play](https://go.dev/play/p/pJfXXAoG_Te)]
|
||||
- **<big>CamelCase</big>** : coverts source string to its camelCase string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)]
|
||||
[[play](https://go.dev/play/p/9eXP3tn2tUy)]
|
||||
- **<big>Capitalize</big>** : converts the first character of source string to upper case and the remaining to lower case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)]
|
||||
[[play](https://go.dev/play/p/2OAjgbmAqHZ)]
|
||||
- **<big>IsString</big>** : checks if the parameter value data type is string or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)]
|
||||
[[play](https://go.dev/play/p/IOgq7oF9ERm)]
|
||||
- **<big>KebabCase</big>** : coverts string to kebab-case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)]
|
||||
[[play](https://go.dev/play/p/dcZM9Oahw-Y)]
|
||||
- **<big>UpperKebabCase</big>** : coverts string to upper KEBAB-CASE string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperKebabCase)]
|
||||
[[play](https://go.dev/play/p/zDyKNneyQXk)]
|
||||
- **<big>LowerFirst</big>** : converts the first character of string to lower case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)]
|
||||
[[play](https://go.dev/play/p/CbzAyZmtJwL)]
|
||||
- **<big>UpperFirst</big>** : converts the first character of string to upper case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)]
|
||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||
- **<big>PadEnd</big>** : pads string with given characters on the right side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)]
|
||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||
- **<big>PadStart</big>** : pads string with given characters on the left side if it's shorter than limit size. Padding characters are truncated if they exceed size.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)]
|
||||
[[play](https://go.dev/play/p/xpTfzArDfvT)]
|
||||
- **<big>Reverse</big>** : returns string whose char order is reversed to the given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/adfwalJiecD)]
|
||||
- **<big>SnakeCase</big>** : coverts string to snake_case string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)]
|
||||
[[play](https://go.dev/play/p/tgzQG11qBuN)]
|
||||
- **<big>UpperSnakeCase</big>** : coverts string to upper SNAKE_CASE string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperSnakeCase)]
|
||||
[[play](https://go.dev/play/p/4COPHpnLx38)]
|
||||
- **<big>SplitEx</big>** : split a given string which can control the result slice contains empty string or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)]
|
||||
[[play](https://go.dev/play/p/Us-ySSbWh-3)]
|
||||
- **<big>Substring</big>** : returns a substring of the specified length starting at the specified offset position.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)]
|
||||
- **<big>Wrap</big>** : wrap a string with given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)]
|
||||
[[play](https://go.dev/play/p/KoZOlZDDt9y)]
|
||||
- **<big>Unwrap</big>** : unwrap a given string from anther string. will change source string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)]
|
||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||
|
||||
### 19. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
@@ -501,15 +837,33 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)
|
||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)
|
||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)
|
||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)
|
||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)
|
||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)
|
||||
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)
|
||||
- **<big>IsWindows</big>** : check if current os is windows.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)]
|
||||
[[play](https://go.dev/play/p/XzJULbzmf9m)]
|
||||
- **<big>IsLinux</big>** : check if current os is linux.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)]
|
||||
[[play](https://go.dev/play/p/zIflQgZNuxD)]
|
||||
- **<big>IsMac</big>** : check if current os is macos.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)]
|
||||
[[play](https://go.dev/play/p/Mg4Hjtyq7Zc)]
|
||||
- **<big>GetOsEnv</big>** : get the value of the environment variable named by the key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>SetOsEnv</big>** : set the value of the environment variable named by the key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>RemoveOsEnv</big>** : remove a single environment variable.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)]
|
||||
[[play](https://go.dev/play/p/fqyq4b3xUFQ)]
|
||||
- **<big>CompareOsEnv</big>** : get env named by the key and compare it with passed env.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)]
|
||||
[[play](https://go.dev/play/p/BciHrKYOHbp)]
|
||||
- **<big>ExecCommand</big>** : execute command, return the stdout and stderr string of command, and error if error occurs.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)]
|
||||
[[play](https://go.dev/play/p/n-2fLyZef-4)]
|
||||
- **<big>GetOsBits</big>** : return current os bits (32 or 64).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
|
||||
### 19. Validator package contains some functions for data validation.
|
||||
|
||||
@@ -519,33 +873,90 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)
|
||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)
|
||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)
|
||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)
|
||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)
|
||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)
|
||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)
|
||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)
|
||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)
|
||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)
|
||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)
|
||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)
|
||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)
|
||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)
|
||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)
|
||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)
|
||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)
|
||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)
|
||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)
|
||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)
|
||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)
|
||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)
|
||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)
|
||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
|
||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
|
||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)
|
||||
- **<big>ContainChinese</big>** : check if the string contain mandarin chinese.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)]
|
||||
[[play](https://go.dev/play/p/7DpU0uElYeM)]
|
||||
- **<big>ContainLetter</big>** : check if the string contain at least one letter.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)]
|
||||
[[play](https://go.dev/play/p/lqFD04Yyewp)]
|
||||
- **<big>ContainLower</big>** : check if the string contain at least one lower case letter a-z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)]
|
||||
[[play](https://go.dev/play/p/Srqi1ItvnAA)]
|
||||
- **<big>ContainUpper</big>** : check if the string contain at least one upper case letter A-Z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)]
|
||||
[[play](https://go.dev/play/p/CmWeBEk27-z)]
|
||||
- **<big>IsAlpha</big>** : checks if the string contains only letters (a-zA-Z).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)]
|
||||
[[play](https://go.dev/play/p/7Q5sGOz2izQ)]
|
||||
- **<big>IsAllUpper</big>** : check if the string is all upper case letters A-Z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)]
|
||||
[[play](https://go.dev/play/p/ZHctgeK1n4Z)]
|
||||
- **<big>IsAllLower</big>** : check if the string is all lower case letters a-z.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)]
|
||||
[[play](https://go.dev/play/p/GjqCnOfV6cM)]
|
||||
- **<big>IsBase64</big>** : check if the string is base64 string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)]
|
||||
[[play](https://go.dev/play/p/sWHEySAt6hl)]
|
||||
- **<big>IsChineseMobile</big>** : check if the string is chinese mobile number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)]
|
||||
[[play](https://go.dev/play/p/GPYUlGTOqe3)]
|
||||
- **<big>IsChineseIdNum</big>** : check if the string is chinese id card.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)]
|
||||
[[play](https://go.dev/play/p/d8EWhl2UGDF)]
|
||||
- **<big>IsChinesePhone</big>** : check if the string is chinese phone number.(xxx-xxxxxxxx or xxxx-xxxxxxx.)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)]
|
||||
[[play](https://go.dev/play/p/RUD_-7YZJ3I)]
|
||||
- **<big>IsCreditCard</big>** : check if the string is credit card.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : check if the string is dns.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : check if the string is a email address.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)]
|
||||
[[play](https://go.dev/play/p/Os9VaFlT33G)]
|
||||
- **<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>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)]
|
||||
[[play](https://go.dev/play/p/LOYwS_Oyl7U)]
|
||||
- **<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)]
|
||||
- **<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>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)]
|
||||
- **<big>IsIp</big>** : check if the string is ip.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : check if the string is ipv4.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : check if the string is ipv6.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsStrongPassword</big>** : check if the string is strong password.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
- **<big>IsUrl</big>** : check if the string is url.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)]
|
||||
[[play](https://go.dev/play/p/pbJGa7F98Ka)]
|
||||
- **<big>IsWeakPassword</big>** : check if the string is weak password.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)]
|
||||
[[play](https://go.dev/play/p/wqakscZH5gH)]
|
||||
- **<big>IsZeroValue</big>** : check if value is a zero value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<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)]
|
||||
|
||||
### 20. xerror package implements helpers for errors.
|
||||
|
||||
|
||||
852
README_zh-CN.md
852
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)
|
||||
@@ -31,16 +31,16 @@
|
||||
|
||||
### Note:
|
||||
|
||||
1. <b>对于使用 go1.18 及以上的用户,建议安装 v2.x.x。 因为 v2.x.x 用 go1.18 的泛型重写了大部分函数。</b>
|
||||
1. <b>使用 go1.18 及以上版本的用户,建议安装 v2.x.x。 因为 v2.x.x 应用 go1.18 的泛型重写了大部分函数。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.3。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.5。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.3.3 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
go get github.com/duke-git/lancet@v1.3.5 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
```
|
||||
|
||||
## 用法
|
||||
@@ -70,11 +70,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## API 文档
|
||||
## 文档
|
||||
|
||||
## [lancet API doc](https://uvdream.github.io/lancet-docs/) 感谢[@UvDream](https://github.com/UvDream)整理
|
||||
|
||||
### 1. algorithm 算法包实现一些基本算法。eg. sort, search.
|
||||
### 1. algorithm 包实现一些基本查找和排序算法。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -82,20 +80,43 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BubbleSort)
|
||||
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#CountSort)
|
||||
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#HeapSort)
|
||||
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#InsertionSort)
|
||||
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#MergeSort)
|
||||
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#QuickSort)
|
||||
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#SelectionSort)
|
||||
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#ShellSort)
|
||||
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinarySearch)
|
||||
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinaryIterativeSearch)
|
||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
|
||||
- **<big>BubbleSort</big>** : 使用冒泡排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BubbleSort)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>CountSort</big>** : 使用计数排序算法对切片进行排序。不改变原数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#CountSort)]
|
||||
[[play](https://go.dev/play/p/tB-Umgm0DrP)]
|
||||
- **<big>HeapSort</big>** : 使用堆排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#HeapSort)]
|
||||
[[play](https://go.dev/play/p/u6Iwa1VZS_f)]
|
||||
- **<big>InsertionSort</big>** : 使用插入排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#InsertionSort)]
|
||||
[[play](https://go.dev/play/p/G5LJiWgJJW6)]
|
||||
- **<big>MergeSort</big>** : 使用合并排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#MergeSort)]
|
||||
[[play](https://go.dev/play/p/ydinn9YzUJn)]
|
||||
- **<big>QuickSort</big>** : 使用快速排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#QuickSort)]
|
||||
[[play](https://go.dev/play/p/7Y7c1Elk3ax)]
|
||||
- **<big>SelectionSort</big>** : 使用选择排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#SelectionSort)]
|
||||
[[play](https://go.dev/play/p/oXovbkekayS)]
|
||||
- **<big>ShellSort</big>** : 使用希尔排序算法对切片进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#ShellSort)]
|
||||
[[play](https://go.dev/play/p/3ibkszpJEu3)]
|
||||
- **<big>BinarySearch</big>** : 返回排序切片中目标值的索引,使用二分搜索(递归调用)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinarySearch)]
|
||||
[[play](https://go.dev/play/p/t6MeGiUSN47)]
|
||||
- **<big>BinaryIterativeSearch</big>** :返回排序切片中目标值的索引,使用二分搜索(非递归)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinaryIterativeSearch)]
|
||||
[[play](https://go.dev/play/p/Anozfr8ZLH3)]
|
||||
- **<big>LinearSearch</big>** : 基于传入的相等函数返回切片中目标值的索引。(线性查找)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)]
|
||||
- **<big>LRUCache</big>** : 应用 lru 算法实现内存缓存.
|
||||
[[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. concurrency 包含一些支持并发编程的功能。例如:goroutine, channel, async 等。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/concurrency"
|
||||
@@ -103,18 +124,28 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)
|
||||
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Bridge)
|
||||
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)
|
||||
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)
|
||||
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)
|
||||
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)
|
||||
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)
|
||||
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
|
||||
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
|
||||
- **<big>NewChannel</big>** : 返回一个 Channel 指针实例。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)]
|
||||
- **<big>Bridge</big>** : 将多个 channel 链接到一个 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/Bridge.md#NewChannel)]
|
||||
- **<big>FanIn</big>** : 将多个 channel 合并为一个 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)]
|
||||
- **<big>Generate</big>** : 根据传入的值,生成 channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)]
|
||||
- **<big>Or</big>** : 将一个或多个 channel 读取到一个 channel 中,当任何读取 channel 关闭时将结束读取。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)]
|
||||
- **<big>OrDone</big>** : 将一个 channel 读入另一个 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)]
|
||||
- **<big>Repeat</big>** : 返回一个 channel,将参数`values`重复放入 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)]
|
||||
- **<big>RepeatFn</big>** : 返回一个 channel,重复执行函数 fn,并将结果放入返回的 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)]
|
||||
- **<big>Take</big>** : 返回一个 channel,其值从另一个 channel 获取,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)]
|
||||
- **<big>Tee</big>** : 将一个 channel 分成两个 channel,直到取消上下文。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)]
|
||||
|
||||
### 3. condition 条件包含一些用于条件判断的函数。eg. And, Or, TernaryOperator...
|
||||
### 3. condition 包含一些用于条件判断的函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/condition"
|
||||
@@ -122,13 +153,30 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Bool](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Bool)
|
||||
- [And](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#And)
|
||||
- [Or](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Or)
|
||||
- [Xor](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xor)
|
||||
- [Nor](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nor)
|
||||
- [Nand](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nand)
|
||||
- [TernaryOperator](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)
|
||||
- **<big>Bool</big>** : 返回传入参数的 bool 值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Bool)]
|
||||
[[play](https://go.dev/play/p/ETzeDJRSvhm)]
|
||||
- **<big>And</big>** : 逻辑且操作,当切仅当 a 和 b 都为 true 时返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#And)]
|
||||
[[play](https://go.dev/play/p/W1SSUmt6pvr)]
|
||||
- **<big>Or</big>** : 逻辑或操作,当切仅当 a 和 b 都为 false 时返回 false。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Or)]
|
||||
[[play](https://go.dev/play/p/UlQTxHaeEkq)]
|
||||
- **<big>Xor</big>** : 逻辑异或操作,a 和 b 相同返回 false,a 和 b 不相同返回 true
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xor)]
|
||||
[[play](https://go.dev/play/p/gObZrW7ZbG8)]
|
||||
- **<big>Nor</big>** : 异或的取反操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nor)]
|
||||
[[play](https://go.dev/play/p/g2j08F_zZky)
|
||||
- **<big>Xnor</big>** : 如果 a 和 b 都是真的或 a 和 b 均是假的,则返回 true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xnor)]
|
||||
[[play](https://go.dev/play/p/OuDB9g51643)]
|
||||
- **<big>Nand</big>** : 如果 a 和 b 都为真,返回 false,否则返回 true
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nand)]
|
||||
[[play](https://go.dev/play/p/vSRMLxLIbq8)]
|
||||
- **<big>TernaryOperator</big>** : 三元运算符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
### 4. convertor 转换器包支持一些常见的数据类型转换。
|
||||
|
||||
@@ -138,22 +186,54 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)
|
||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)
|
||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
|
||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
|
||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
|
||||
- [ToChannel](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChannel)
|
||||
- [ToFloat](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToFloat)
|
||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
|
||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
|
||||
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToMap)
|
||||
- [ToPointer](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToPointer)
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
|
||||
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#MapToSlice)
|
||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#EncodeByte)
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)
|
||||
- **<big>ColorHexToRGB</big>** : 颜色值十六进制转 rgb。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)]
|
||||
[[play](https://go.dev/play/p/o7_ft-JCJBV)]
|
||||
- **<big>ColorRGBToHex</big>** : 颜色值 rgb 转十六进制。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)]
|
||||
[[play](https://go.dev/play/p/nzKS2Ro87J1)]
|
||||
- **<big>ToBool</big>** : 字符串转布尔类型,使用 strconv.ParseBool。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)]
|
||||
[[play](https://go.dev/play/p/ARht2WnGdIN)]
|
||||
- **<big>ToBytes</big>** : interface 转字节切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)]
|
||||
[[play](https://go.dev/play/p/fAMXYFDvOvr)]
|
||||
- **<big>ToChar</big>** : 字符串转字符切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)]
|
||||
[[play](https://go.dev/play/p/JJ1SvbFkVdM)]
|
||||
- **<big>ToChannel</big>** : 将切片转为只读 channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChannel)]
|
||||
[[play](https://go.dev/play/p/hOx_oYZbAnL)]
|
||||
- **<big>ToFloat</big>** : 将 interface 转成 float64 类型,如果参数无法转换,会返回 0.0 和 error。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToFloat)]
|
||||
[[play](https://go.dev/play/p/4YTmPCibqHJ)]
|
||||
- **<big>ToInt</big>** : 将 interface 转成 int64 类型,如果参数无法转换,会返回 0 和 error。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)]
|
||||
[[play](https://go.dev/play/p/9_h9vIt-QZ_b)]
|
||||
- **<big>ToJson</big>** : 将 interface 转成 json 字符串,如果参数无法转换,会返回""和 error。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)]
|
||||
[[play](https://go.dev/play/p/2rLIkMmXWvR)]
|
||||
- **<big>ToMap</big>** : 将切片转为 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToMap)]
|
||||
[[play](https://go.dev/play/p/tVFy7E-t24l)]
|
||||
- **<big>ToPointer</big>** : 返回传入值的指针。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToPointer)]
|
||||
[[play](https://go.dev/play/p/ASf_etHNlw1)]
|
||||
- **<big>ToString</big>** : 将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)]
|
||||
[[play](https://go.dev/play/p/nF1zOOslpQq)]
|
||||
- **<big>StructToMap</big>** : 将 struct 转成 map,只会转换 struct 中可导出的字段。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)]
|
||||
[[play](https://go.dev/play/p/KYGYJqNUBOI)]
|
||||
- **<big>MapToSlice</big>** : map 中 key 和 value 执行函数 iteratee 后,转为切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#MapToSlice)]
|
||||
[[play](https://go.dev/play/p/dmX4Ix5V6Wl)]
|
||||
- **<big>EncodeByte</big>** : 将传入的 data 编码成字节切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#EncodeByte)]
|
||||
[[play](https://go.dev/play/p/DVmM1G5JfuP)]
|
||||
- **<big>DecodeByte</big>** : 解码字节切片到目标对象,目标对象需要传入一个指针实例。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)]
|
||||
[[play](https://go.dev/play/p/zI6xsmuQRbn)]
|
||||
|
||||
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
@@ -259,7 +339,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
- [Heap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap.md)
|
||||
- [HashMap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)
|
||||
|
||||
### 8. fileutil 包支持文件基本操作。
|
||||
### 8. fileutil 包含文件基本操作。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -267,21 +347,51 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ClearFile)
|
||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateFile)
|
||||
- [CreateDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateDir)
|
||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CopyFile)
|
||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileMode)
|
||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MiMeType)
|
||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsExist)
|
||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsLink)
|
||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsDir)
|
||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ListFileNames)
|
||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#RemoveFile)
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
|
||||
- **<big>ClearFile</big>** : 清空文件内容。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ClearFile)]
|
||||
[[play](https://go.dev/play/p/NRZ0ZT-G94H)]
|
||||
- **<big>CreateFile</big>** : 创建文件,创建成功返回 true, 否则返回 false。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateFile)]
|
||||
[[play](https://go.dev/play/p/lDt8PEsTNKI)]
|
||||
- **<big>CreateDir</big>** : 创建嵌套目录,例如/a/, /a/b/。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateDir)]
|
||||
[[play](https://go.dev/play/p/qUuCe1OGQnM)]
|
||||
- **<big>CopyFile</big>** :拷贝文件,会覆盖原有的文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CopyFile)]
|
||||
[[play](https://go.dev/play/p/Jg9AMJMLrJi)]
|
||||
- **<big>FileMode</big>** : 获取文件 mode 信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileMode)]
|
||||
[[play](https://go.dev/play/p/2l2hI42fA3p)]
|
||||
- **<big>MiMeType</big>** : 获取文件 mime 类型, 参数的类型必须是 string 或者\*os.File。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MiMeType)]
|
||||
[[play](https://go.dev/play/p/bd5sevSUZNu)]
|
||||
- **<big>IsExist</big>** : 判断文件或目录是否存在。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsExist)]
|
||||
[[play](https://go.dev/play/p/nKKXt8ZQbmh)]
|
||||
- **<big>IsLink</big>** : 判断文件是否是符号链接。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsLink)]
|
||||
[[play](https://go.dev/play/p/TL-b-Kzvf44)]
|
||||
- **<big>IsDir</big>** : 判断参数是否是目录。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsDir)]
|
||||
[[play](https://go.dev/play/p/WkVwEKqtOWk)]
|
||||
- **<big>ListFileNames</big>** : 返回目录下所有文件名。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ListFileNames)]
|
||||
[[play](https://go.dev/play/p/Tjd7Y07rejl)]
|
||||
- **<big>RemoveFile</big>** : 删除文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#RemoveFile)]
|
||||
[[play](https://go.dev/play/p/P2y0XW8a1SH)]
|
||||
- **<big>ReadFileToString</big>** : 读取文件内容并返回字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileToString)]
|
||||
[[play](https://go.dev/play/p/cmfwp_5SQTp)]
|
||||
- **<big>ReadFileByLine</big>** : 按行读取文件内容,返回字符串切片包含每一行。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileByLine)]
|
||||
[[play](https://go.dev/play/p/svJP_7ZrBrD)]
|
||||
- **<big>Zip</big>** : zip 压缩文件, 参数可以是文件或目录。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)]
|
||||
[[play](https://go.dev/play/p/j-3sWBp8ik_P)]
|
||||
- **<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)]
|
||||
|
||||
### 9. formatter 格式化器包含一些数据格式化处理方法。
|
||||
|
||||
@@ -291,7 +401,9 @@ import "github.com/duke-git/lancet/v2/formatter"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
|
||||
- **<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)]
|
||||
|
||||
### 10. function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
@@ -301,16 +413,33 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)
|
||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Curry)
|
||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)
|
||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)
|
||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)
|
||||
- [Pipeline](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
||||
- **<big>After</big>** : 创建一个函数,当该函数被调用n或更多次之后将执行传入的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)]
|
||||
[[play](https://go.dev/play/p/eRD5k2vzUVX)]
|
||||
- **<big>Before</big>** : 创建一个函数,当该函数被调用不超过n次时,将执行执行传入的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)]
|
||||
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
|
||||
- **<big>CurryFn</big>** : 创建柯里化函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#CurryFn)]
|
||||
- **<big>Compose</big>** : 从右至左组合函数列表fnList,返回组合后的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)]
|
||||
- **<big>Delay</big>** : 延迟delay时间后调用函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)]
|
||||
[[play](https://go.dev/play/p/Ivtc2ZE-Tye)]
|
||||
- **<big>Debounced</big>** : 创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)]
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
- **<big>Pipeline</big>** : 从右至左执行函数列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)]
|
||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
||||
- **<big>Watcher</big>** : Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
|
||||
|
||||
### 11. maputil 包包括一些操作 map 的函数.
|
||||
|
||||
### 11. maputil 包括一些操作 map 的函数.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -318,14 +447,30 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)
|
||||
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)
|
||||
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)
|
||||
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)
|
||||
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
|
||||
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)
|
||||
- **<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)]
|
||||
- **<big>Filter</big>** : 迭代 map 中的每对 key 和 value,返回 map,其中的 key 和 value 符合 predicate 函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)]
|
||||
[[play](https://go.dev/play/p/fSvF3wxuNG7)]
|
||||
- **<big>Intersect</big>** : 多个 map 的交集操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)]
|
||||
[[play](https://go.dev/play/p/Zld0oj3sjcC)]
|
||||
- **<big>Keys</big>** : 返回 map 中所有 key 组成的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)]
|
||||
[[play](https://go.dev/play/p/xNB5bTb97Wd)]
|
||||
- **<big>Merge</big>** : 合并多个 map, 相同的 key 会被之后的 key 覆盖。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)]
|
||||
[[play](https://go.dev/play/p/H95LENF1uB-)]
|
||||
- **<big>Minus</big>** : 返回一个 map,其中的 key 存在于 mapA,不存在于 mapB。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)]
|
||||
[[play](https://go.dev/play/p/3u5U9K7YZ9m)]
|
||||
- **<big>Values</big>** : 返回 map 中所有 values 组成的切片
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)]
|
||||
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
|
||||
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
|
||||
### 12. mathutil 包实现了一些数学计算的函数。
|
||||
|
||||
@@ -335,18 +480,41 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)
|
||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
|
||||
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)
|
||||
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MaxBy)
|
||||
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)
|
||||
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MinBy)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
||||
- **<big>Average</big>** :计算平均数,可能需要对结果调用 RoundToFloat 方法四舍五入。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)]
|
||||
[[play](https://go.dev/play/p/Vv7LBwER-pz)]
|
||||
- **<big>Exponent</big>** : 指数计算(x 的 n 次方)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)]
|
||||
[[play](https://go.dev/play/p/uF3HGNPk8wr)]
|
||||
- **<big>Fibonacci</big>** :计算斐波那契数列的第 n 个数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)]
|
||||
[[play](https://go.dev/play/p/IscseUNMuUc)]
|
||||
- **<big>Factorial</big>** : 计算阶乘。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)]
|
||||
[[play](https://go.dev/play/p/tt6LdOK67Nx)]
|
||||
- **<big>Max</big>** : 返回参数中的最大数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)]
|
||||
[[play](https://go.dev/play/p/cN8DHI0rTkH)]
|
||||
- **<big>MaxBy</big>** : 使用给定的比较器函数返回切片的最大值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MaxBy)]
|
||||
[[play](https://go.dev/play/p/pbe2MT-7DV2)]
|
||||
- **<big>Min</big>** : 返回参数中的最小数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)]
|
||||
[[play](https://go.dev/play/p/21BER_mlGUj)]
|
||||
- **<big>MinBy</big>** : 使用给定的比较器函数返回切片的最小值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MinBy)]
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>Percent</big>** : 计算百分比,可以指定保留 n 位小数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)]
|
||||
- **<big>RoundToFloat</big>** : 四舍五入,保留 n 位小数,返回 float64。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)]
|
||||
[[play](https://go.dev/play/p/ghyb528JRJL)]
|
||||
- **<big>RoundToString</big>** : 四舍五入,保留 n 位小数,返回 string。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)]
|
||||
[[play](https://go.dev/play/p/kZwpBRAcllO)]
|
||||
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
|
||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||
|
||||
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
|
||||
@@ -370,12 +538,11 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)
|
||||
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)
|
||||
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)
|
||||
|
||||
- [HttpGet<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
||||
- [HttpDelete<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
||||
- [HttpPost<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
||||
- [HttpPut<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
|
||||
- [HttpPatch<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
||||
- [HttpGet<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
||||
- [HttpDelete<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
||||
- [HttpPost<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
||||
- [HttpPut<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
|
||||
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||
|
||||
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
@@ -386,14 +553,32 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
|
||||
- [RandUpper](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUpper)
|
||||
- [RandLower](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandLower)
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
- **<big>RandBytes</big>** : 生成随机字节切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)]
|
||||
[[play](https://go.dev/play/p/EkiLESeXf8d)]
|
||||
- **<big>RandInt</big>** : 生成随机int, 范围[min, max)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)]
|
||||
[[play](https://go.dev/play/p/pXyyAAI5YxD)]
|
||||
- **<big>RandString</big>** : 生成给定长度的随机字符串,只包含字母(a-zA-Z)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)]
|
||||
[[play](https://go.dev/play/p/W2xvRUXA7Mi)]
|
||||
- **<big>RandUpper</big>** : 生成给定长度的随机大写字母字符串(A-Z)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUpper)]
|
||||
[[play](https://go.dev/play/p/29QfOh0DVuh)]
|
||||
- **<big>RandLower</big>** : 生成给定长度的随机小写字母字符串(a-z)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandLower)]
|
||||
[[play](https://go.dev/play/p/XJtZ471cmtI)]
|
||||
- **<big>RandNumeral</big>** : 生成给定长度的随机数字字符串(0-9)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeral)]
|
||||
[[play](https://go.dev/play/p/g4JWVpHsJcf)]
|
||||
- **<big>RandNumeralOrLetter</big>** : 生成给定长度的随机字符串(数字+字母)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)]
|
||||
[[play](https://go.dev/play/p/19CEQvpx2jD)]
|
||||
- **<big>UUIdV4</big>** : 生成UUID v4字符串。
|
||||
[[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。
|
||||
|
||||
@@ -409,62 +594,175 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
|
||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
||||
|
||||
### 16. slice 包包含操作切片的方法集合。
|
||||
### 16. slice 包含操作切片的方法集合。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- **<big>AppendIfAbsent</big>** : 当前切片中不包含值时,将该值追加到切片中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)]
|
||||
[[play](https://go.dev/play/p/GNdv7Jg2Taj)]
|
||||
- **<big>Contain</big>** : 判断slice是否包含value。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)]
|
||||
[[play](https://go.dev/play/p/_454yEHcNjf)]
|
||||
- **<big>ContainSubSlice</big>** : 判断slice是否包含subslice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)]
|
||||
[[play](https://go.dev/play/p/bcuQ3UT6Sev)]
|
||||
- **<big>Chunk</big>** : 按照size参数均分slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)]
|
||||
[[play](https://go.dev/play/p/b4Pou5j2L_C)]
|
||||
- **<big>Compact</big>** : 去除slice中的假值(false values are false, nil, 0, "")。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)]
|
||||
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
|
||||
- **<big>Concat</big>** : 合并多个slices到一个slice中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)]
|
||||
[[play](https://go.dev/play/p/gPt-q7zr5mk)]
|
||||
- **<big>Count</big>** : 返回切片中指定元素的个数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)]
|
||||
[[play](https://go.dev/play/p/Mj4oiEnQvRJ)]
|
||||
- **<big>CountBy</big>** : 遍历切片,对每个元素执行函数predicate. 返回符合函数返回值为true的元素的个数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#CountBy)]
|
||||
[[play](https://go.dev/play/p/tHOccTMDZCC)]
|
||||
- **<big>Difference</big>** : 创建一个切片,其元素不包含在另一个给定切片中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)]
|
||||
[[play](https://go.dev/play/p/VXvadzLzhDa)]
|
||||
- **<big>DifferenceBy</big>** : 将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)]
|
||||
[[play](https://go.dev/play/p/DiivgwM5OnC)]
|
||||
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceWith)]
|
||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
||||
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Drop</big>** : 创建一个切片,当n > 0时从开头删除n个元素,或者当n < 0时从结尾删除n个元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>Equal</big>** : 检查两个切片是否相等,相等条件:切片长度相同,元素顺序和值都相同。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Equal)]
|
||||
[[play](https://go.dev/play/p/WcRQJ37ifPa)]
|
||||
- **<big>EqualWith</big>** : 检查两个切片是否相等,相等条件:对两个切片的元素调用比较函数comparator,返回true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#EqualWith)]
|
||||
[[play](https://go.dev/play/p/b9iygtgsHI1)]
|
||||
- **<big>Every</big>** : 如果切片中的所有值都通过谓词函数,则返回true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)]
|
||||
[[play](https://go.dev/play/p/R8U6Sl-j8cD)]
|
||||
- **<big>Filter</big>** : 返回切片中通过predicate函数真值测试的所有元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)]
|
||||
[[play](https://go.dev/play/p/SdPna-7qK4T)]
|
||||
- **<big>Find</big>** : 遍历切片的元素,返回第一个通过predicate函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)]
|
||||
[[play](https://go.dev/play/p/CBKeBoHVLgq)]
|
||||
- **<big>FindLast</big>** : 从头到尾遍历slice的元素,返回最后一个通过predicate函数真值测试的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/FFDPV_j7URd)]
|
||||
- **<big>Flatten</big>** : 将多维切片展平一层。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Flatten)]
|
||||
[[play](https://go.dev/play/p/hYa3cBEevtm)]
|
||||
- **<big>FlattenDeep</big>** : 将多维切片递归展平到一层。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlattenDeep)]
|
||||
[[play](https://go.dev/play/p/yjYNHPyCFaF)]
|
||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用iteratee函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||
- **<big>GroupWith</big>** : 创建一个map,key是iteratee遍历slice中的每个元素返回的结果。值是切片元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)]
|
||||
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : 将接口切片转换为int切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>InterfaceSlice<sup>deprecated</sup></big>** : 将值转换为interface切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)]
|
||||
[[play](https://go.dev/play/p/FdQXF0Vvqs-)]
|
||||
- **<big>Intersection</big>** : 返回多个切片的交集。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)]
|
||||
[[play](https://go.dev/play/p/anJXfB5wq_t)]
|
||||
- **<big>InsertAt</big>** : 将元素插入到索引处的切片中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)]
|
||||
[[play](https://go.dev/play/p/hMLNxPEGJVE)]
|
||||
- **<big>IndexOf</big>** : 返回在切片中找到值的第一个匹配项的索引,如果找不到值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IndexOf)]
|
||||
[[play](https://go.dev/play/p/MRN1f0FpABb)]
|
||||
- **<big>LastIndexOf</big>** : 返回在切片中找到最后一个值的索引,如果找不到该值,则返回-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)]
|
||||
[[play](https://go.dev/play/p/DokM4cf1IKH)]
|
||||
- **<big>Map</big>** : 对slice中的每个元素执行map函数以创建一个新切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)]
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>Merge</big>** : 合并多个切片(不会消除重复元素)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
- **<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函数,返回运行结果。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
|
||||
- **<big>Replace</big>** : 返回切片的副本,其中前n个不重叠的old替换为new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
- **<big>ReplaceAll</big>** : 返回切片的副本,将其中old全部替换为new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReplaceAll)]
|
||||
[[play](https://go.dev/play/p/CzqXMsuYUrx)]
|
||||
- **<big>Repeat</big>** : 创建一个切片,包含n个传入的item。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Repeat)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>Shuffle</big>** : 随机打乱切片中的元素顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)]
|
||||
[[play](https://go.dev/play/p/YHvhnWGU3Ge)]
|
||||
- **<big>Sort</big>** : 对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Sort)]
|
||||
[[play](https://go.dev/play/p/V9AVjzf_4Fk)]
|
||||
- **<big>SortBy</big>** : 按照less函数确定的升序规则对切片进行排序。排序不保证稳定性。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortBy)]
|
||||
[[play](https://go.dev/play/p/DAhLQSZEumm)]
|
||||
- **<big>SortByField<sup>deprecated</sup></big>** : 按字段对结构切片进行排序。slice元素应为struct,字段类型应为int、uint、string或bool。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)]
|
||||
[[play](https://go.dev/play/p/fU1prOBP9p1)]
|
||||
- **<big>Some</big>** : 如果列表中的任何值通过谓词函数,则返回true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)]
|
||||
[[play](https://go.dev/play/p/4pO9Xf9NDGS)]
|
||||
- **<big>StringSlice<sup>deprecated</sup></big>** : 将接口切片转换为字符串切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)]
|
||||
[[play](https://go.dev/play/p/W0TZDWCPFcI)]
|
||||
- **<big>SymmetricDifference</big>** : 返回一个切片,其中的元素存在于参数切片中,但不同时存储在于参数切片中(交集取反)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#h42nJX5xMln)]
|
||||
[[play](https://go.dev/play/p/1CbOmtgILUU)]
|
||||
- **<big>ToSlice</big>** : 将可变参数转为切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ToSlice)]
|
||||
[[play](https://go.dev/play/p/YzbzVq5kscN)]
|
||||
- **<big>ToSlicePointer</big>** : 将可变参数转为指针切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ToSlicePointer)]
|
||||
[[play](https://go.dev/play/p/gx4tr6_VXSF)]
|
||||
- **<big>Unique</big>** : 删除切片中的重复元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)]
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : 对切片的每个元素调用iteratee函数,然后删除重复元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
- **<big>Union</big>** : 合并多个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
- **<big>UnionBy</big>** : 对切片的每个元素调用函数后,合并多个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UnionBy)]
|
||||
[[play](https://go.dev/play/p/HGKHfxKQsFi)]
|
||||
- **<big>UpdateAt</big>** : 更新索引处的切片元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateAt)]
|
||||
[[play](https://go.dev/play/p/f3mh2KloWVm)]
|
||||
- **<big>Without</big>** : 创建一个不包括所有给定值的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)]
|
||||
[[play](https://go.dev/play/p/bwhEXEypThg)]
|
||||
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
|
||||
|
||||
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)
|
||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
|
||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
|
||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
|
||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)
|
||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)
|
||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)
|
||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)
|
||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)
|
||||
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
|
||||
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)
|
||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)
|
||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)
|
||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)
|
||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)
|
||||
- [Flatten](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Flatten)
|
||||
- [FlattenDeep](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FlattenDeep)
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)
|
||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)
|
||||
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)
|
||||
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
|
||||
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)
|
||||
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IndexOf)
|
||||
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
|
||||
- [Replace](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)
|
||||
- [ReplaceAll](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReplaceAll)
|
||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)
|
||||
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)
|
||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)
|
||||
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)
|
||||
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SymmetricDifference)
|
||||
- [ToSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ToSlice)
|
||||
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ToSlicePointer)
|
||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)
|
||||
- [UniqueBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UniqueBy)
|
||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)
|
||||
- [UniqueBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UniqueBy)
|
||||
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateAt)
|
||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
||||
- [KeyBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)
|
||||
|
||||
### 17. strutil 包含处理字符串的相关函数。
|
||||
### 17. strutil 包含字符串处理的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
@@ -472,25 +770,67 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)
|
||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)
|
||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)
|
||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)
|
||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
|
||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
|
||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
|
||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
|
||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
|
||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Reverse)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
||||
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
||||
- **<big>After</big>** : 返回源字符串中指定字符串首次出现时的位置之后的子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)]
|
||||
[[play](https://go.dev/play/p/RbCOQqCDA7m)]
|
||||
- **<big>AfterLast</big>** : 返回源字符串中指定字符串最后一次出现时的位置之后的子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)]
|
||||
[[play](https://go.dev/play/p/1TegARrb8Yn)]
|
||||
- **<big>Before</big>** : 返回源字符串中指定字符串第一次出现时的位置之前的子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)]
|
||||
[[play](https://go.dev/play/p/JAWTZDS4F5w)]
|
||||
- **<big>BeforeLast</big>** : 返回源字符串中指定字符串最后一次出现时的位置之前的子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)]
|
||||
[[play](https://go.dev/play/p/pJfXXAoG_Te)]
|
||||
- **<big>CamelCase</big>** : 将字符串转换为 CamelCase 驼峰式字符串, 非字母和数字会被忽略。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)]
|
||||
[[play](https://go.dev/play/p/9eXP3tn2tUy)]
|
||||
- **<big>Capitalize</big>** : 将字符串的第一个字符转换为大写。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)]
|
||||
[[play](https://go.dev/play/p/2OAjgbmAqHZ)]
|
||||
- **<big>IsString</big>** : 判断传入参数的数据类型是否为字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)]
|
||||
[[play](https://go.dev/play/p/IOgq7oF9ERm)]
|
||||
- **<big>KebabCase</big>** : 将字符串转换为 kebab-case 形式字符串, 非字母和数字会被忽略。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)]
|
||||
[[play](https://go.dev/play/p/dcZM9Oahw-Y)]
|
||||
- **<big>UpperKebabCase</big>** : 将字符串转换为大写 KEBAB-CASE 形式字符串, 非字母和数字会被忽略。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperKebabCase)]
|
||||
[[play](https://go.dev/play/p/zDyKNneyQXk)]
|
||||
- **<big>LowerFirst</big>** : 将字符串的第一个字符转换为小写形式。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)]
|
||||
[[play](https://go.dev/play/p/CbzAyZmtJwL)]
|
||||
- **<big>UpperFirst</big>** : 将字符串的第一个字符转换为大写形式。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)]
|
||||
[[play](https://go.dev/play/p/sBbBxRbs8MM)]
|
||||
- **<big>PadEnd</big>** : 如果字符串短于限制大小,则在右侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)]
|
||||
[[play](https://go.dev/play/p/9xP8rN0vz--)]
|
||||
- **<big>PadStart</big>** : 如果字符串短于限制大小,则在左侧用给定字符填充字符串。 如果填充字符超出大小,它们将被截断。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)]
|
||||
[[play](https://go.dev/play/p/xpTfzArDfvT)]
|
||||
- **<big>Reverse</big>** : 返回字符顺序与给定字符串相反的字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Reverse)]
|
||||
[[play](https://go.dev/play/p/adfwalJiecD)]
|
||||
- **<big>SnakeCase</big>** : 将字符串转换为 snake_case 形式, 非字母和数字会被忽略。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)]
|
||||
[[play](https://go.dev/play/p/tgzQG11qBuN)]
|
||||
- **<big>UpperSnakeCase</big>** : 将字符串转换为大写 SNAKE_CASE 形式, 非字母和数字会被忽略。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperSnakeCase)]
|
||||
[[play](https://go.dev/play/p/4COPHpnLx38)]
|
||||
- **<big>SplitEx</big>** : 拆分给定的字符串可以控制结果切片是否包含空字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)]
|
||||
[[play](https://go.dev/play/p/Us-ySSbWh-3)]
|
||||
- **<big>Substring</big>** : 根据指定的位置和长度截取子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Substring)]
|
||||
- **<big>Wrap</big>** : 用给定字符包裹传入的字符串
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)]
|
||||
[[play](https://go.dev/play/p/KoZOlZDDt9y)]
|
||||
- **<big>Unwrap</big>** : 从另一个字符串中解开一个给定的字符串。 将更改源字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)]
|
||||
[[play](https://go.dev/play/p/Ec2q4BzCpG-)]
|
||||
|
||||
### 18. system 包含 os, runtime, shell command 相关函数。
|
||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
@@ -498,15 +838,33 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsWindows)
|
||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsLinux)
|
||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsMac)
|
||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsEnv)
|
||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#SetOsEnv)
|
||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#RemoveOsEnv)
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
||||
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsBits)
|
||||
- **<big>IsWindows</big>** : 检查当前操作系统是否是 windows。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#IsWindows)]
|
||||
[[play](https://go.dev/play/p/XzJULbzmf9m)]
|
||||
- **<big>IsLinux</big>** : 检查当前操作系统是否是 linux。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#IsLinux)]
|
||||
[[play](https://go.dev/play/p/zIflQgZNuxD)]
|
||||
- **<big>IsMac</big>** : 检查当前操作系统是否是 macos。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#IsMac)]
|
||||
[[play](https://go.dev/play/p/Mg4Hjtyq7Zc)]
|
||||
- **<big>GetOsEnv</big>** : 根据 key 获取对应的环境变量值
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>SetOsEnv</big>** : 设置环境变量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#SetOsEnv)]
|
||||
[[play](https://go.dev/play/p/D88OYVCyjO-)]
|
||||
- **<big>RemoveOsEnv</big>** : 删除环境变量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#RemoveOsEnv)]
|
||||
[[play](https://go.dev/play/p/fqyq4b3xUFQ)]
|
||||
- **<big>CompareOsEnv</big>** : 换取环境变量并与传入值进行比较。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#CompareOsEnv)]
|
||||
[[play](https://go.dev/play/p/BciHrKYOHbp)]
|
||||
- **<big>ExecCommand</big>** : 执行 shell 命令。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#ExecCommand)]
|
||||
[[play](https://go.dev/play/p/n-2fLyZef-4)]
|
||||
- **<big>GetOsBits</big>** : 获取当前操作系统位数(32/64)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
|
||||
### 19. validator 验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
@@ -516,33 +874,91 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainChinese)
|
||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLetter)
|
||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLower)
|
||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainUpper)
|
||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAlpha)
|
||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllUpper)
|
||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)
|
||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)
|
||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseMobile)
|
||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseIdNum)
|
||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChinesePhone)
|
||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)
|
||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)
|
||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmail)
|
||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmptyString)
|
||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)
|
||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)
|
||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)
|
||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsRegexMatch)
|
||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)
|
||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)
|
||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)
|
||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)
|
||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)
|
||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
|
||||
- **<big>ContainChinese</big>** : 验证字符串是否包含中文字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainChinese)]
|
||||
[[play](https://go.dev/play/p/7DpU0uElYeM)]
|
||||
- **<big>ContainLetter</big>** : 验证字符串是否包含至少一个英文字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLetter)]
|
||||
[[play](https://go.dev/play/p/lqFD04Yyewp)]
|
||||
- **<big>ContainLower</big>** : 验证字符串是否包含至少一个英文小写字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLower)]
|
||||
[[play](https://go.dev/play/p/Srqi1ItvnAA)]
|
||||
- **<big>ContainUpper</big>** : 验证字符串是否包含至少一个英文大写字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainUpper)]
|
||||
[[play](https://go.dev/play/p/CmWeBEk27-z)]
|
||||
- **<big>IsAlpha</big>** : 验证字符串是否只包含英文字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAlpha)]
|
||||
[[play](https://go.dev/play/p/7Q5sGOz2izQ)]
|
||||
- **<big>IsAllUpper</big>** : 验证字符串是否全是大写英文字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllUpper)]
|
||||
[[play](https://go.dev/play/p/ZHctgeK1n4Z)]
|
||||
- **<big>IsAllLower</big>** : 验证字符串是否全是小写英文字母。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)]
|
||||
[[play](https://go.dev/play/p/GjqCnOfV6cM)]
|
||||
- **<big>IsBase64</big>** : 验证字符串是否是base64编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)]
|
||||
[[play](https://go.dev/play/p/sWHEySAt6hl)]
|
||||
- **<big>IsChineseMobile</big>** : 验证字符串是否是中国手机号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseMobile)]
|
||||
[[play](https://go.dev/play/p/GPYUlGTOqe3)]
|
||||
- **<big>IsChineseIdNum</big>** : 验证字符串是否是中国身份证号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseIdNum)]
|
||||
[[play](https://go.dev/play/p/d8EWhl2UGDF)]
|
||||
- **<big>IsChinesePhone</big>** : 验证字符串是否是中国电话座机号码(xxx-xxxxxxxx or xxxx-xxxxxxx.)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChinesePhone)]
|
||||
[[play](https://go.dev/play/p/RUD_-7YZJ3I)]
|
||||
- **<big>IsCreditCard</big>** : 验证字符串是否是信用卡号码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)]
|
||||
[[play](https://go.dev/play/p/sNwwL6B0-v4)]
|
||||
- **<big>IsDns</big>** : 验证字符串是否是有效dns。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)]
|
||||
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
|
||||
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmail)]
|
||||
[[play](https://go.dev/play/p/Os9VaFlT33G)]
|
||||
- **<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>IsFloatStr</big>** : 验证字符串是否是可以转换为浮点数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#LOYwS_Oyl7U)]
|
||||
[[play](https://go.dev/play/p/LOYwS_Oyl7U)]
|
||||
- **<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)]
|
||||
- **<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>IsIntStr</big>** : 验证字符串是否是可以转换为整数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)]
|
||||
[[play](https://go.dev/play/p/jQRtFv-a0Rk)]
|
||||
- **<big>IsIp</big>** : 验证字符串是否是ip地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)]
|
||||
[[play](https://go.dev/play/p/FgcplDvmxoD)]
|
||||
- **<big>IsIpV4</big>** : 验证字符串是否是ipv4地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)]
|
||||
[[play](https://go.dev/play/p/zBGT99EjaIu)]
|
||||
- **<big>IsIpV6</big>** : 验证字符串是否是ipv6地址。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)]
|
||||
[[play](https://go.dev/play/p/AHA0r0AzIdC)]
|
||||
- **<big>IsStrongPassword</big>** : 验证字符串是否是强密码:(字母+数字+特殊字符)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)]
|
||||
[[play](https://go.dev/play/p/QHdVcSQ3uDg)]
|
||||
- **<big>IsUrl</big>** : 验证字符串是否是url。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)]
|
||||
[[play](https://go.dev/play/p/pbJGa7F98Ka)]
|
||||
- **<big>IsWeakPassword</big>** : 验证字符串是否是弱密码(只包含字母+数字)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)]
|
||||
[[play](https://go.dev/play/p/wqakscZH5gH)]
|
||||
- **<big>IsZeroValue</big>** : 判断传入的参数值是否为零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)]
|
||||
[[play](https://go.dev/play/p/UMrwaDCi_t4)]
|
||||
- **<big>IsGBK</big>** : 检查数据编码是否为gbk(汉字内部代码扩展规范)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||
|
||||
|
||||
### 20. xerror 包实现一些错误处理函数
|
||||
|
||||
|
||||
15
SECURITY.md
Normal file
15
SECURITY.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
Here is the lancet version and compatibility with go language version.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------|
|
||||
| 2.x.x | +go v1.18 |
|
||||
| 1.x.x | +go v1.12 |
|
||||
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
For now, there is no public website to report a vulnerability, If you find security issue in lancet, you can send it to me via my email `lanliddd.2007@163.com`.
|
||||
we can discuss it. I am appreciate if someone can create a public page for reporting vulnerability.
|
||||
@@ -26,7 +26,7 @@ type LRUCache[K comparable, V any] struct {
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLRUCache return a LRUCache pointer
|
||||
// NewLRUCache creates a LRUCache pointer instance.
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
return &LRUCache[K, V]{
|
||||
cache: make(map[K]*lruNode[K, V], capacity),
|
||||
@@ -37,7 +37,8 @@ func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
}
|
||||
}
|
||||
|
||||
// Get value of key from lru cache
|
||||
// Get value of key from lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
var value V
|
||||
|
||||
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
return value, false
|
||||
}
|
||||
|
||||
// Put value of key into lru cache
|
||||
// Put value of key into lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
node, ok := l.cache[key]
|
||||
if !ok {
|
||||
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
|
||||
// Delete item from lru cache.
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
key := l.deleteNode(node)
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (l *LRUCache[K, V]) Len() int {
|
||||
return l.length
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
|
||||
if l.tail != nil {
|
||||
l.tail.next = node
|
||||
79
algorithm/lrucache_example_test.go
Normal file
79
algorithm/lrucache_example_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLRUCache_Put() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Get() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Delete() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
|
||||
ok2 := cache.Delete(2)
|
||||
|
||||
_, ok3 := cache.Get(2)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(ok2)
|
||||
fmt.Println(ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Len() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result := cache.Len()
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
func TestLRUCache(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](2)
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
@@ -25,12 +25,9 @@ func TestLRUCache(t *testing.T) {
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
|
||||
cache.Put(3, 3)
|
||||
v, ok = cache.Get(1)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.NotEqual(1, v)
|
||||
|
||||
v, ok = cache.Get(3)
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(3, v)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
}
|
||||
@@ -1,26 +1,27 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
|
||||
// LinearSearch return the index of target in slice base on equal function.
|
||||
// If not found return -1
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||
for i, v := range slice {
|
||||
if comparator.Compare(v, target) == 0 {
|
||||
if equal(v, target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// BinarySearch search for target within a sorted slice, recursive call itself.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/t6MeGiUSN47
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
@@ -39,8 +40,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
||||
return midIndex
|
||||
}
|
||||
|
||||
// BinaryIterativeSearch search for target within a sorted slice.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/Anozfr8ZLH3
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
51
algorithm/search_example_test.go
Normal file
51
algorithm/search_example_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLinearSearch() {
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
result1 := LinearSearch(numbers, 3, equalFunc)
|
||||
result2 := LinearSearch(numbers, 6, equalFunc)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinarySearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinaryIterativeSearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
@@ -6,20 +6,24 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
|
||||
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
@@ -27,7 +31,9 @@ func TestBinarySearch(t *testing.T) {
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// BubbleSort use bubble to sort slice.
|
||||
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/GNdv7Jg2Taj
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := 0; j < len(slice)-1-i; j++ {
|
||||
@@ -18,7 +18,8 @@ func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// InsertionSort use insertion to sort slice.
|
||||
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/G5LJiWgJJW6
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
@@ -32,7 +33,8 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionSort use selection to sort slice.
|
||||
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/oXovbkekayS
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
@@ -45,7 +47,8 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// ShellSort shell sort slice.
|
||||
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/3ibkszpJEu3
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -64,7 +67,8 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
|
||||
// Play: https://go.dev/play/p/7Y7c1Elk3ax
|
||||
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
quickSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -93,7 +97,8 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
return i
|
||||
}
|
||||
|
||||
// HeapSort use heap to sort slice
|
||||
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/u6Iwa1VZS_f
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -126,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
||||
slice[i] = temp
|
||||
}
|
||||
|
||||
// MergeSort merge sorting for slice
|
||||
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/ydinn9YzUJn
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -167,7 +173,8 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
|
||||
}
|
||||
}
|
||||
|
||||
// CountSort use count sorting for slice
|
||||
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
|
||||
// Play: https://go.dev/play/p/tB-Umgm0DrP
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
93
algorithm/sort_example_test.go
Normal file
93
algorithm/sort_example_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBubbleSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleCountSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
sortedNumber := CountSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
fmt.Println(sortedNumber)
|
||||
// Output:
|
||||
// [2 1 5 3 6 4]
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleHeapSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
HeapSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleMergeSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
MergeSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleInsertionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
InsertionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleSelectionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
SelectionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleShellSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
ShellSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleQuickSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
QuickSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
@@ -66,6 +66,7 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
@@ -11,17 +11,18 @@ import (
|
||||
|
||||
// Channel is a logic object which can generate or manipulate go channel
|
||||
// all methods of Channel are in the book tilted《Concurrency in Go》
|
||||
type Channel struct {
|
||||
type Channel[T any] struct {
|
||||
}
|
||||
|
||||
// NewChannel return a Channel instance
|
||||
func NewChannel() *Channel {
|
||||
return &Channel{}
|
||||
func NewChannel[T any]() *Channel[T] {
|
||||
return &Channel[T]{}
|
||||
}
|
||||
|
||||
// Generate a data of type any chan, put param `values` into the chan
|
||||
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// Generate creates channel, then put values into the channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// Repeat create channel, put values into the channel repeatly until cancel the context.
|
||||
// Play:
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
|
||||
// until close the `done` channel
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
|
||||
// until close context.
|
||||
// Play:
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Take return a chan whose values are tahken from another chan
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
|
||||
takeStream := make(chan any)
|
||||
// Take create a channel whose values are taken from another channel with limit number.
|
||||
// Play:
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
|
||||
takeStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(takeStream)
|
||||
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
|
||||
return takeStream
|
||||
}
|
||||
|
||||
// FanIn merge multiple channels into one channel
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
|
||||
out := make(chan any)
|
||||
// FanIn merge multiple channels into one channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
|
||||
out := make(chan T)
|
||||
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(channels))
|
||||
|
||||
for _, c := range channels {
|
||||
go func(c <-chan any) {
|
||||
go func(c <-chan T) {
|
||||
defer wg.Done()
|
||||
for v := range c {
|
||||
select {
|
||||
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
return out
|
||||
}
|
||||
|
||||
// Tee split one chanel into two channels
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
|
||||
out1 := make(chan any)
|
||||
out2 := make(chan any)
|
||||
// Tee split one chanel into two channels, until cancel the context.
|
||||
// Play:
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
|
||||
out1 := make(chan T)
|
||||
out2 := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(out1)
|
||||
@@ -147,18 +153,19 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
|
||||
return out1, out2
|
||||
}
|
||||
|
||||
// Bridge link multiply channels into one channel
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
// Bridge link multiply channels into one channel.
|
||||
// Play:
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
for {
|
||||
var stream <-chan any
|
||||
var stream <-chan T
|
||||
select {
|
||||
case maybeStream, ok := <-chanStream:
|
||||
if ok == false {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
stream = maybeStream
|
||||
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
|
||||
return valStream
|
||||
}
|
||||
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed.
|
||||
// Play:
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
|
||||
switch len(channels) {
|
||||
case 0:
|
||||
return nil
|
||||
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
return channels[0]
|
||||
}
|
||||
|
||||
orDone := make(chan any)
|
||||
orDone := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(orDone)
|
||||
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
case <-channels[1]:
|
||||
}
|
||||
default:
|
||||
m := len(channels) / 2
|
||||
select {
|
||||
case <-c.Or(channels[:m]...):
|
||||
case <-c.Or(channels[m:]...):
|
||||
case <-channels[0]:
|
||||
case <-channels[1]:
|
||||
case <-channels[2]:
|
||||
case <-c.Or(append(channels[3:], orDone)...):
|
||||
}
|
||||
// select {
|
||||
// case <-channels[0]:
|
||||
// case <-channels[1]:
|
||||
// case <-channels[2]:
|
||||
// case <-c.Or(append(channels[3:], orDone)...):
|
||||
// }
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -217,8 +220,9 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
}
|
||||
|
||||
// OrDone read a channel into another channel, will close until cancel context.
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
// Play:
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
196
concurrency/channel_example_test.go
Normal file
196
concurrency/channel_example_test.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package concurrency
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleChannel_Generate() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_Repeat() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleChannel_RepeatFn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleChannel_Take() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_FanIn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ExampleChannel_Or() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
)
|
||||
|
||||
if time.Since(start).Seconds() < 2 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleChannel_OrDone() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Tee() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Bridge() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
@@ -14,12 +14,9 @@ func TestGenerate(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 3
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(3, <-intStream)
|
||||
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 1, 2, 1
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(1, <-intStream)
|
||||
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
fn := func() string {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := NewChannel()
|
||||
c := NewChannel[string]()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
// for v := range dataStream {
|
||||
// t.Log(v) //a, a, a
|
||||
// }
|
||||
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
@@ -72,7 +62,7 @@ func TestTake(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -80,7 +70,7 @@ func TestTake(t *testing.T) {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
assert.Equal(1, <-intStream)
|
||||
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
@@ -124,7 +114,7 @@ func TestOr(t *testing.T) {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
@@ -133,9 +123,7 @@ func TestOr(t *testing.T) {
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
t.Logf("done after %v", time.Since(start))
|
||||
|
||||
assert.Equal(1, 1)
|
||||
assert.Equal(true, time.Since(start).Seconds() < 2)
|
||||
}
|
||||
|
||||
func TestOrDone(t *testing.T) {
|
||||
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
var res any
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
t.Logf("%v", val)
|
||||
res = val
|
||||
assert.Equal(1, val)
|
||||
}
|
||||
|
||||
assert.Equal(1, res)
|
||||
}
|
||||
|
||||
func TestTee(t *testing.T) {
|
||||
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
val1 := val
|
||||
val2 := <-out2
|
||||
// t.Log("val1 is", val1)
|
||||
// t.Log("val2 is", val2)
|
||||
assert.Equal(1, val1)
|
||||
assert.Equal(1, val2)
|
||||
}
|
||||
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
chanStream := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
|
||||
@@ -13,6 +13,7 @@ import "reflect"
|
||||
// If the type has an IsZero() bool method, the opposite value is returned.
|
||||
// Slices and maps are truthy if they have a length greater than zero.
|
||||
// All other types are truthy if they are not their zero value.
|
||||
// Play: https://go.dev/play/p/ETzeDJRSvhm
|
||||
func Bool[T any](value T) bool {
|
||||
switch m := any(value).(type) {
|
||||
case interface{ Bool() bool }:
|
||||
@@ -34,40 +35,47 @@ func reflectValue(vp any) bool {
|
||||
}
|
||||
|
||||
// And returns true if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/W1SSUmt6pvr
|
||||
func And[T, U any](a T, b U) bool {
|
||||
return Bool(a) && Bool(b)
|
||||
}
|
||||
|
||||
// Or returns false iff neither a nor b is truthy.
|
||||
// Or returns false if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/UlQTxHaeEkq
|
||||
func Or[T, U any](a T, b U) bool {
|
||||
return Bool(a) || Bool(b)
|
||||
}
|
||||
|
||||
// Xor returns true iff a or b but not both is truthy.
|
||||
// Xor returns true if a or b but not both is truthy.
|
||||
// Play: https://go.dev/play/p/gObZrW7ZbG8
|
||||
func Xor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA || valB) && valA != valB
|
||||
}
|
||||
|
||||
// Nor returns true iff neither a nor b is truthy.
|
||||
// Nor returns true if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/g2j08F_zZky
|
||||
func Nor[T, U any](a T, b U) bool {
|
||||
return !(Bool(a) || Bool(b))
|
||||
}
|
||||
|
||||
// Xnor returns true iff both a and b or neither a nor b are truthy.
|
||||
// Xnor returns true if both a and b or neither a nor b are truthy.
|
||||
// Play: https://go.dev/play/p/OuDB9g51643
|
||||
func Xnor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA && valB) || (!valA && !valB)
|
||||
}
|
||||
|
||||
// Nand returns false iff both a and b are truthy.
|
||||
// Nand returns false if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/vSRMLxLIbq8
|
||||
func Nand[T, U any](a T, b U) bool {
|
||||
return !Bool(a) || !Bool(b)
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
|
||||
163
condition/condition_example_test.go
Normal file
163
condition/condition_example_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package condition
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBool() {
|
||||
// bool
|
||||
result1 := Bool(false)
|
||||
result2 := Bool(true)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// integer
|
||||
result3 := Bool(0)
|
||||
result4 := Bool(1)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// string
|
||||
result5 := Bool("")
|
||||
result6 := Bool(" ")
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// slice
|
||||
var nums = []int{}
|
||||
result7 := Bool(nums)
|
||||
nums = append(nums, 1, 2)
|
||||
result8 := Bool(nums)
|
||||
fmt.Println(result7)
|
||||
fmt.Println(result8)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleAnd() {
|
||||
result1 := And(0, 1)
|
||||
result2 := And(0, "")
|
||||
result3 := And(0, "0")
|
||||
result4 := And(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleOr() {
|
||||
result1 := Or(0, "")
|
||||
result2 := Or(0, 1)
|
||||
result3 := Or(0, "0")
|
||||
result4 := Or(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleXor() {
|
||||
result1 := Xor(0, 0)
|
||||
result2 := Xor(1, 1)
|
||||
result3 := Xor(0, 1)
|
||||
result4 := Xor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleNor() {
|
||||
result1 := Nor(0, 0)
|
||||
result2 := Nor(1, 1)
|
||||
result3 := Nor(0, 1)
|
||||
result4 := Nor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleXnor() {
|
||||
result1 := Xnor(0, 0)
|
||||
result2 := Xnor(1, 1)
|
||||
result3 := Xnor(0, 1)
|
||||
result4 := Xnor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleNand() {
|
||||
result1 := Nand(0, 0)
|
||||
result2 := Nand(1, 0)
|
||||
result3 := Nand(0, 1)
|
||||
result4 := Nand(1, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
@@ -17,12 +17,14 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToBool convert string to a boolean
|
||||
// ToBool convert string to boolean.
|
||||
// Play: https://go.dev/play/p/ARht2WnGdIN
|
||||
func ToBool(s string) (bool, error) {
|
||||
return strconv.ParseBool(s)
|
||||
}
|
||||
|
||||
// ToBytes convert interface to bytes
|
||||
// ToBytes convert value to byte slice.
|
||||
// Play: https://go.dev/play/p/fAMXYFDvOvr
|
||||
func ToBytes(value any) ([]byte, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -63,7 +65,8 @@ func ToBytes(value any) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToChar convert string to char slice
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
if len(s) == 0 {
|
||||
@@ -75,7 +78,8 @@ func ToChar(s string) []string {
|
||||
return c
|
||||
}
|
||||
|
||||
// ToChannel convert a array of elements to a read-only channels
|
||||
// ToChannel convert a slice of elements to a read-only channel.
|
||||
// Play: https://go.dev/play/p/hOx_oYZbAnL
|
||||
func ToChannel[T any](array []T) <-chan T {
|
||||
ch := make(chan T)
|
||||
|
||||
@@ -90,38 +94,59 @@ func ToChannel[T any](array []T) <-chan T {
|
||||
}
|
||||
|
||||
// ToString convert value to string
|
||||
// for number, string, []byte, will convert to string
|
||||
// for other type (slice, map, array, struct) will call json.Marshal.
|
||||
// Play: https://go.dev/play/p/nF1zOOslpQq
|
||||
func ToString(value any) string {
|
||||
result := ""
|
||||
if value == nil {
|
||||
return result
|
||||
return ""
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
switch value.(type) {
|
||||
case float32, float64:
|
||||
result = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
return result
|
||||
case int, int8, int16, int32, int64:
|
||||
result = strconv.FormatInt(v.Int(), 10)
|
||||
return result
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
result = strconv.FormatUint(v.Uint(), 10)
|
||||
return result
|
||||
switch val := value.(type) {
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||
case int:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int8:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int16:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int32:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int64:
|
||||
return strconv.FormatInt(val, 10)
|
||||
case uint:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint8:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint16:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint32:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint64:
|
||||
return strconv.FormatUint(val, 10)
|
||||
case string:
|
||||
result = v.String()
|
||||
return result
|
||||
return val
|
||||
case []byte:
|
||||
result = string(v.Bytes())
|
||||
return result
|
||||
return string(val)
|
||||
default:
|
||||
newValue, _ := json.Marshal(value)
|
||||
result = string(newValue)
|
||||
return result
|
||||
b, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
|
||||
// todo: maybe we should't supprt other type conversion
|
||||
// v := reflect.ValueOf(value)
|
||||
// log.Panicf("Unsupported data type: %s ", v.String())
|
||||
// return ""
|
||||
}
|
||||
}
|
||||
|
||||
// ToJson convert value to a valid json string
|
||||
// ToJson convert value to a json string.
|
||||
// Play: https://go.dev/play/p/2rLIkMmXWvR
|
||||
func ToJson(value any) (string, error) {
|
||||
result, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
@@ -131,7 +156,8 @@ func ToJson(value any) (string, error) {
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
|
||||
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
|
||||
// Play: https://go.dev/play/p/4YTmPCibqHJ
|
||||
func ToFloat(value any) (float64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -158,12 +184,13 @@ func ToFloat(value any) (float64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
|
||||
// ToInt convert value to int64 value, if input is not numerical, return 0 and error.
|
||||
// Play: https://go.dev/play/p/9_h9vIt-QZ_b
|
||||
func ToInt(value any) (int64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
var result int64
|
||||
err := fmt.Errorf("ToInt: invalid interface type %T", value)
|
||||
err := fmt.Errorf("ToInt: invalid value type %T", value)
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
result = v.Int()
|
||||
@@ -185,12 +212,14 @@ func ToInt(value any) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToPointer returns a pointer to this value
|
||||
// ToPointer returns a pointer to passed value.
|
||||
// Play: https://go.dev/play/p/ASf_etHNlw1
|
||||
func ToPointer[T any](value T) *T {
|
||||
return &value
|
||||
}
|
||||
|
||||
// ToMap convert a slice or an array of structs to a map based on iteratee function
|
||||
// ToMap convert a slice of structs to a map based on iteratee function.
|
||||
// Play: https://go.dev/play/p/tVFy7E-t24l
|
||||
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
|
||||
result := make(map[K]V, len(array))
|
||||
for _, item := range array {
|
||||
@@ -202,7 +231,8 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
|
||||
}
|
||||
|
||||
// StructToMap convert struct to map, only convert exported struct field
|
||||
// map key is specified same as struct field tag `json` value
|
||||
// map key is specified same as struct field tag `json` value.
|
||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||
func StructToMap(value any) (map[string]any, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
@@ -231,7 +261,8 @@ func StructToMap(value any) (map[string]any, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MapToSlice convert a map to a slice based on iteratee function
|
||||
// MapToSlice convert map to slice based on iteratee function.
|
||||
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
|
||||
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
|
||||
result := make([]T, 0, len(aMap))
|
||||
|
||||
@@ -242,7 +273,8 @@ func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T)
|
||||
return result
|
||||
}
|
||||
|
||||
// ColorHexToRGB convert hex color to rgb color
|
||||
// ColorHexToRGB convert hex color to rgb color.
|
||||
// Play: https://go.dev/play/p/o7_ft-JCJBV
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
colorHex = strings.TrimPrefix(colorHex, "#")
|
||||
color64, err := strconv.ParseInt(colorHex, 16, 32)
|
||||
@@ -253,7 +285,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
|
||||
}
|
||||
|
||||
// ColorRGBToHex convert rgb color to hex color
|
||||
// ColorRGBToHex convert rgb color to hex color.
|
||||
// Play: https://go.dev/play/p/nzKS2Ro87J1
|
||||
func ColorRGBToHex(red, green, blue int) string {
|
||||
r := strconv.FormatInt(int64(red), 16)
|
||||
g := strconv.FormatInt(int64(green), 16)
|
||||
@@ -272,7 +305,8 @@ func ColorRGBToHex(red, green, blue int) string {
|
||||
return "#" + r + g + b
|
||||
}
|
||||
|
||||
// EncodeByte encode data to byte
|
||||
// EncodeByte encode data to byte slice.
|
||||
// Play: https://go.dev/play/p/DVmM1G5JfuP
|
||||
func EncodeByte(data any) ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
encoder := gob.NewEncoder(buffer)
|
||||
@@ -283,7 +317,8 @@ func EncodeByte(data any) ([]byte, error) {
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecodeByte decode byte data to target object
|
||||
// DecodeByte decode byte slice data to target object.
|
||||
// Play: https://go.dev/play/p/zI6xsmuQRbn
|
||||
func DecodeByte(data []byte, target any) error {
|
||||
buffer := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(buffer)
|
||||
|
||||
254
convertor/convertor_example_test.go
Normal file
254
convertor/convertor_example_test.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package convertor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ExampleToBool() {
|
||||
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
result, _ := ToBool(cases[i])
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleToBytes() {
|
||||
result1, _ := ToBytes(1)
|
||||
result2, _ := ToBytes("abc")
|
||||
result3, _ := ToBytes(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [0 0 0 0 0 0 0 1]
|
||||
// [97 98 99]
|
||||
// [116 114 117 101]
|
||||
}
|
||||
|
||||
func ExampleToChar() {
|
||||
result1 := ToChar("")
|
||||
result2 := ToChar("abc")
|
||||
result3 := ToChar("1 2#3")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [a b c]
|
||||
// [1 2 # 3]
|
||||
}
|
||||
|
||||
func ExampleToChannel() {
|
||||
ch := ToChannel([]int{1, 2, 3})
|
||||
result1 := <-ch
|
||||
result2 := <-ch
|
||||
result3 := <-ch
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleToString() {
|
||||
result1 := ToString("")
|
||||
result2 := ToString(nil)
|
||||
result3 := ToString(0)
|
||||
result4 := ToString(1.23)
|
||||
result5 := ToString(true)
|
||||
result6 := ToString(false)
|
||||
result7 := ToString([]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:
|
||||
//
|
||||
//
|
||||
// 0
|
||||
// 1.23
|
||||
// true
|
||||
// false
|
||||
// [1,2,3]
|
||||
}
|
||||
|
||||
func ExampleToJson() {
|
||||
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result1, err := ToJson(aMap)
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
}
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// {"a":1,"b":2,"c":3}
|
||||
}
|
||||
|
||||
func ExampleToFloat() {
|
||||
result1, _ := ToFloat("")
|
||||
result2, _ := ToFloat("abc")
|
||||
result3, _ := ToFloat("-1")
|
||||
result4, _ := ToFloat("-.11")
|
||||
result5, _ := ToFloat("1.23e3")
|
||||
result6, _ := ToFloat(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0
|
||||
// -1
|
||||
// -0.11
|
||||
// 1230
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToInt() {
|
||||
result1, _ := ToInt("123")
|
||||
result2, _ := ToInt("-123")
|
||||
result3, _ := ToInt(float64(12.3))
|
||||
result4, _ := ToInt("abc")
|
||||
result5, _ := ToInt(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// -123
|
||||
// 12
|
||||
// 0
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToPointer() {
|
||||
result := ToPointer(123)
|
||||
fmt.Println(*result)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
}
|
||||
|
||||
func ExampleToMap() {
|
||||
type Message struct {
|
||||
name string
|
||||
code int
|
||||
}
|
||||
messages := []Message{
|
||||
{name: "Hello", code: 100},
|
||||
{name: "Hi", code: 101},
|
||||
}
|
||||
result := ToMap(messages, func(msg Message) (int, string) {
|
||||
return msg.code, msg.name
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[100:Hello 101:Hi]
|
||||
}
|
||||
|
||||
func ExampleStructToMap() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
age int
|
||||
}
|
||||
p := People{
|
||||
"test",
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
|
||||
fmt.Println(pm)
|
||||
|
||||
// Output:
|
||||
// map[name:test]
|
||||
}
|
||||
|
||||
func ExampleMapToSlice() {
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result := MapToSlice(aMap, func(key string, value int) string {
|
||||
return key + ":" + strconv.Itoa(value)
|
||||
})
|
||||
|
||||
fmt.Println(result) //[]string{"a:1", "c:3", "b:2"} (random order)
|
||||
}
|
||||
|
||||
func ExampleColorHexToRGB() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := ColorHexToRGB(colorHex)
|
||||
|
||||
fmt.Println(r, g, b)
|
||||
|
||||
// Output:
|
||||
// 0 51 102
|
||||
}
|
||||
|
||||
func ExampleColorRGBToHex() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex)
|
||||
|
||||
// Output:
|
||||
// #003366
|
||||
}
|
||||
|
||||
func ExampleEncodeByte() {
|
||||
byteData, _ := EncodeByte("abc")
|
||||
fmt.Println(byteData)
|
||||
|
||||
// Output:
|
||||
// [6 12 0 3 97 98 99]
|
||||
}
|
||||
|
||||
func ExampleDecodeByte() {
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
err := DecodeByte(byteData, &obj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(obj)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
@@ -27,14 +27,9 @@ func TestToChannel(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToChannel")
|
||||
|
||||
ch := ToChannel([]int{1, 2, 3})
|
||||
val1, _ := <-ch
|
||||
assert.Equal(1, val1)
|
||||
|
||||
val2, _ := <-ch
|
||||
assert.Equal(2, val2)
|
||||
|
||||
val3, _ := <-ch
|
||||
assert.Equal(3, val3)
|
||||
assert.Equal(1, <-ch)
|
||||
assert.Equal(2, <-ch)
|
||||
assert.Equal(3, <-ch)
|
||||
|
||||
_, ok := <-ch
|
||||
assert.Equal(false, ok)
|
||||
@@ -137,9 +132,10 @@ func TestToString(t *testing.T) {
|
||||
"", "",
|
||||
"0", "1", "-1",
|
||||
"123", "123", "123", "123", "123", "123", "123",
|
||||
"12.3", "12.300000190734863",
|
||||
"12.3", "12.3",
|
||||
"true", "false",
|
||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
|
||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello",
|
||||
}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual := ToString(cases[i])
|
||||
@@ -253,6 +249,7 @@ func TestDecodeByte(t *testing.T) {
|
||||
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
DecodeByte(byteData, &obj)
|
||||
err := DecodeByte(byteData, &obj)
|
||||
assert.IsNil(err)
|
||||
assert.Equal("abc", obj)
|
||||
}
|
||||
|
||||
@@ -17,15 +17,19 @@ import (
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
@@ -108,27 +112,32 @@ func AesCfbEncrypt(data, key []byte) []byte {
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
@@ -139,6 +148,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
@@ -148,6 +158,7 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
@@ -170,5 +181,6 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
@@ -26,6 +25,8 @@ func DesEcbEncrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
@@ -59,6 +60,7 @@ func DesCbcEncrypt(data, key []byte) []byte {
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,11 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
@@ -49,12 +53,16 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
//file,err = os.Create("rsa_public.pem")
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
@@ -72,7 +80,11 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
file.Read(buf)
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
@@ -101,7 +113,11 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
file.Read(buf)
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
|
||||
@@ -146,9 +146,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
||||
lastNum := powerTwo(level - 1)
|
||||
lastLen := lastNum + (lastNum - 1)
|
||||
|
||||
heapTree := make([][]string, level, level)
|
||||
heapTree := make([][]string, level)
|
||||
for i := 0; i < level; i++ {
|
||||
heapTree[i] = make([]string, lastLen, lastLen)
|
||||
heapTree[i] = make([]string, lastLen)
|
||||
for j := 0; j < lastLen; j++ {
|
||||
heapTree[i][j] = ""
|
||||
}
|
||||
@@ -169,9 +169,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
||||
for n := 0; n < lastLen; n++ {
|
||||
val := heapTree[m][n]
|
||||
if val == "" {
|
||||
fmt.Printf(" ")
|
||||
fmt.Print(" ")
|
||||
} else {
|
||||
fmt.Printf(val)
|
||||
fmt.Print(val)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
@@ -30,8 +30,6 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
|
||||
assert.Equal(expected, heap.data)
|
||||
|
||||
assert.Equal(12, heap.Size())
|
||||
|
||||
heap.PrintStructure()
|
||||
}
|
||||
|
||||
func TestMaxHeap_Push(t *testing.T) {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
|
||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
|
||||
type DoublyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
@@ -19,30 +18,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into doubly linklist at head index
|
||||
func (link *DoublyLink[T]) InsertAtHead(value T) {
|
||||
func (dl *DoublyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
size := link.Size()
|
||||
size := dl.Size()
|
||||
|
||||
if size == 0 {
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
dl.Head = newNode
|
||||
dl.length++
|
||||
return
|
||||
}
|
||||
|
||||
newNode.Next = link.Head
|
||||
newNode.Next = dl.Head
|
||||
newNode.Pre = nil
|
||||
|
||||
link.Head.Pre = newNode
|
||||
link.Head = newNode
|
||||
dl.Head.Pre = newNode
|
||||
dl.Head = newNode
|
||||
|
||||
link.length++
|
||||
dl.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) InsertAtTail(value T) {
|
||||
current := dl.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
dl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,28 +54,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
|
||||
newNode.Pre = current
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
dl.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into doubly linklist at index
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
// param `index` should between [0, length], if index do not meet the conditions, do nothing
|
||||
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
|
||||
size := dl.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of doubly link.")
|
||||
return
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
dl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
dl.InsertAtTail(value)
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
current := dl.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
@@ -85,38 +85,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
||||
newNode.Pre = current
|
||||
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
dl.length++
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in doubly linklist at head index
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
func (dl *DoublyLink[T]) DeleteAtHead() {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.Head.Pre = nil
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
current := dl.Head
|
||||
dl.Head = current.Next
|
||||
dl.Head.Pre = nil
|
||||
dl.length--
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
// DeleteAtTail delete value in doubly linklist at tail
|
||||
func (dl *DoublyLink[T]) DeleteAtTail() {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := dl.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
dl.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
@@ -124,45 +122,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
dl.length--
|
||||
}
|
||||
|
||||
// DeleteAt delete value in doubly linklist at index
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
// param `index` should be [0, len(DoublyLink)-1]
|
||||
func (dl *DoublyLink[T]) DeleteAt(index int) {
|
||||
if dl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := dl.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
dl.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
if index == dl.length-1 {
|
||||
dl.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
if index < 0 || index > dl.length-1 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
dl.length--
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *DoublyLink[T]) Reverse() {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) Reverse() {
|
||||
current := dl.Head
|
||||
var temp *datastructure.LinkNode[T]
|
||||
|
||||
for current != nil {
|
||||
@@ -173,20 +170,20 @@ func (link *DoublyLink[T]) Reverse() {
|
||||
}
|
||||
|
||||
if temp != nil {
|
||||
link.Head = temp.Pre
|
||||
dl.Head = temp.Pre
|
||||
}
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if dl.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
if dl.Head.Next == nil {
|
||||
return dl.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
fast := dl.Head
|
||||
slow := dl.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
@@ -202,14 +199,14 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
}
|
||||
|
||||
// Size return the count of doubly linked list
|
||||
func (link *DoublyLink[T]) Size() int {
|
||||
return link.length
|
||||
func (dl *DoublyLink[T]) Size() int {
|
||||
return dl.length
|
||||
}
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (link *DoublyLink[T]) Values() []T {
|
||||
func (dl *DoublyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
current := link.Head
|
||||
current := dl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
current = current.Next
|
||||
@@ -218,8 +215,8 @@ func (link *DoublyLink[T]) Values() []T {
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *DoublyLink[T]) Print() {
|
||||
current := link.Head
|
||||
func (dl *DoublyLink[T]) Print() {
|
||||
current := dl.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
@@ -229,13 +226,13 @@ func (link *DoublyLink[T]) Print() {
|
||||
fmt.Println(info)
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *DoublyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
// IsEmpty checks if dl is empty or not
|
||||
func (dl *DoublyLink[T]) IsEmpty() bool {
|
||||
return dl.length == 0
|
||||
}
|
||||
|
||||
// Clear all nodes in doubly linklist
|
||||
func (link *DoublyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
func (dl *DoublyLink[T]) Clear() {
|
||||
dl.Head = nil
|
||||
dl.length = 0
|
||||
}
|
||||
|
||||
@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
link.InsertAt(1, 1) //do nothing
|
||||
|
||||
link.InsertAt(0, 1)
|
||||
link.InsertAt(1, 2)
|
||||
link.InsertAt(2, 4)
|
||||
link.InsertAt(2, 3)
|
||||
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
|
||||
}
|
||||
|
||||
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAtHead()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -71,7 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtHead()
|
||||
link.Print()
|
||||
|
||||
expected := []int{2, 3, 4}
|
||||
values := link.Values()
|
||||
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAtTail()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -92,7 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
link.DeleteAt(0)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -113,11 +104,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
link.DeleteAt(0)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
|
||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
|
||||
type SinglyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
@@ -20,18 +19,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into singly linklist at head index
|
||||
func (link *SinglyLink[T]) InsertAtHead(value T) {
|
||||
func (sl *SinglyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = link.Head
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
newNode.Next = sl.Head
|
||||
sl.Head = newNode
|
||||
sl.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into singly linklist at tail index
|
||||
func (link *SinglyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
func (sl *SinglyLink[T]) InsertAtTail(value T) {
|
||||
current := sl.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
sl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,65 +42,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
|
||||
newNode.Next = nil
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
sl.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into singly linklist at index
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
|
||||
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
|
||||
size := sl.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of singly link.")
|
||||
return
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
sl.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
sl.InsertAtTail(value)
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = current.Next
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
|
||||
return nil
|
||||
sl.length++
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in singly linklist at head index
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
func (sl *SinglyLink[T]) DeleteAtHead() {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
current := sl.Head
|
||||
sl.Head = current.Next
|
||||
sl.length--
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in singly linklist at tail index
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
// DeleteAtTail delete value in singly linklist at tail
|
||||
func (sl *SinglyLink[T]) DeleteAtTail() {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
|
||||
current := sl.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
sl.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
@@ -109,68 +106,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
sl.length--
|
||||
}
|
||||
|
||||
// DeleteAt delete value in singly linklist at index
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
// param `index` should be [0, len(SinglyLink)-1]
|
||||
func (sl *SinglyLink[T]) DeleteAt(index int) {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
sl.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
if index == sl.length-1 {
|
||||
sl.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
if index < 0 || index > sl.length-1 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
sl.length--
|
||||
return
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// DeleteValue delete value in singly linklist
|
||||
func (link *SinglyLink[T]) DeleteValue(value T) {
|
||||
if link.Head == nil {
|
||||
func (sl *SinglyLink[T]) DeleteValue(value T) {
|
||||
if sl.Head == nil {
|
||||
return
|
||||
}
|
||||
dummyHead := datastructure.NewLinkNode(value)
|
||||
dummyHead.Next = link.Head
|
||||
dummyHead.Next = sl.Head
|
||||
current := dummyHead
|
||||
|
||||
for current.Next != nil {
|
||||
if reflect.DeepEqual(current.Next.Value, value) {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
sl.length--
|
||||
} else {
|
||||
current = current.Next
|
||||
}
|
||||
}
|
||||
|
||||
link.Head = dummyHead.Next
|
||||
sl.Head = dummyHead.Next
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *SinglyLink[T]) Reverse() {
|
||||
func (sl *SinglyLink[T]) Reverse() {
|
||||
var pre, next *datastructure.LinkNode[T]
|
||||
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
|
||||
for current != nil {
|
||||
next = current.Next
|
||||
@@ -179,19 +174,19 @@ func (link *SinglyLink[T]) Reverse() {
|
||||
current = next
|
||||
}
|
||||
|
||||
link.Head = pre
|
||||
sl.Head = pre
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if sl.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
if sl.Head.Next == nil {
|
||||
return sl.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
fast := sl.Head
|
||||
slow := sl.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
@@ -207,14 +202,14 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
}
|
||||
|
||||
// Size return the count of singly linked list
|
||||
func (link *SinglyLink[T]) Size() int {
|
||||
return link.length
|
||||
func (sl *SinglyLink[T]) Size() int {
|
||||
return sl.length
|
||||
}
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (link *SinglyLink[T]) Values() []T {
|
||||
func (sl *SinglyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
current := link.Head
|
||||
current := sl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
current = current.Next
|
||||
@@ -222,20 +217,20 @@ func (link *SinglyLink[T]) Values() []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *SinglyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
// IsEmpty checks if sl is empty or not
|
||||
func (sl *SinglyLink[T]) IsEmpty() bool {
|
||||
return sl.length == 0
|
||||
}
|
||||
|
||||
// Clear all the node in singly linklist
|
||||
func (link *SinglyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
func (sl *SinglyLink[T]) Clear() {
|
||||
sl.Head = nil
|
||||
sl.length = 0
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *SinglyLink[T]) Print() {
|
||||
current := link.Head
|
||||
func (sl *SinglyLink[T]) Print() {
|
||||
current := sl.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
|
||||
@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
link.InsertAt(1, 1) //do nothing
|
||||
|
||||
err = link.InsertAt(0, 1)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(1, 2)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 4)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 3)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
link.InsertAt(0, 1)
|
||||
link.InsertAt(1, 2)
|
||||
link.InsertAt(2, 4)
|
||||
link.InsertAt(2, 3)
|
||||
|
||||
link.Print()
|
||||
|
||||
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.DeleteAtHead()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
@@ -142,11 +124,7 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
link.DeleteAt(0)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.Reverse()
|
||||
link.Print()
|
||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ func (l *List[T]) DeleteAt(index int) {
|
||||
return
|
||||
}
|
||||
if index == size-1 {
|
||||
data = append(data[:index])
|
||||
data = data[:index]
|
||||
} else {
|
||||
data = append(data[:index], data[index+1:]...)
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (l *List[T]) DeleteIf(f func(T) bool) int {
|
||||
continue
|
||||
}
|
||||
if index == size-1 {
|
||||
data = append(data[:index])
|
||||
data = data[:index]
|
||||
} else {
|
||||
data = append(data[:index], data[index+1:]...)
|
||||
index--
|
||||
@@ -221,7 +221,7 @@ func (l *List[T]) IsEmpty() bool {
|
||||
|
||||
// Clear the data of list
|
||||
func (l *List[T]) Clear() {
|
||||
l.data = make([]T, 0, 0)
|
||||
l.data = make([]T, 0)
|
||||
}
|
||||
|
||||
// Clone return a copy of list
|
||||
@@ -235,7 +235,7 @@ func (l *List[T]) Clone() *List[T] {
|
||||
// Merge two list, return new list, don't change original list
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||
l1, l2 := len(l.data), len(other.data)
|
||||
ml := NewList(make([]T, l1+l2, l1+l2))
|
||||
ml := NewList(make([]T, l1+l2))
|
||||
|
||||
data := append([]T{}, append(l.data, other.data...)...)
|
||||
ml.data = data
|
||||
@@ -274,7 +274,7 @@ func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
|
||||
uniqueData := make([]T, 0, 0)
|
||||
uniqueData := make([]T, 0)
|
||||
for i := 0; i < size; i++ {
|
||||
value := data[i]
|
||||
skip := true
|
||||
@@ -305,7 +305,7 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
|
||||
|
||||
// Intersection creates a new list whose element both be contained in list l and other
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||
result := NewList(make([]T, 0, 0))
|
||||
result := NewList(make([]T, 0))
|
||||
|
||||
for _, v := range l.data {
|
||||
if other.Contain(v) {
|
||||
|
||||
@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
|
||||
data := queue.Data()
|
||||
size := queue.Size()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(expected, data)
|
||||
assert.Equal(3, size)
|
||||
}
|
||||
@@ -35,7 +33,6 @@ func TestArrayQueue_Dequeue(t *testing.T) {
|
||||
val, ok := queue.Dequeue()
|
||||
assert.Equal(true, ok)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{2, 3}, queue.Data())
|
||||
}
|
||||
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
|
||||
|
||||
val := queue.Front()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
|
||||
|
||||
val := queue.Back()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(3, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
|
||||
@@ -10,31 +10,43 @@ func TestCircularQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(4)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(5)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
assert.Equal(5, queue.Size())
|
||||
|
||||
err := queue.Enqueue(6)
|
||||
err = queue.Enqueue(6)
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
func TestCircularQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue := NewCircularQueue[int](4)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
val, err := queue.Dequeue()
|
||||
assert.IsNil(err)
|
||||
@@ -43,11 +55,7 @@ func TestCircularQueue_Dequeue(t *testing.T) {
|
||||
assert.Equal(false, queue.IsFull())
|
||||
|
||||
val, _ = queue.Dequeue()
|
||||
queue.Print()
|
||||
assert.Equal(2, *val)
|
||||
|
||||
queue.Enqueue(6)
|
||||
queue.Print()
|
||||
assert.Equal(false, queue.IsFull())
|
||||
}
|
||||
|
||||
@@ -55,55 +63,52 @@ func TestCircularQueue_Front(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
|
||||
queue.Print()
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
val := queue.Front()
|
||||
assert.Equal(3, val)
|
||||
assert.Equal(5, queue.Size())
|
||||
assert.IsNil(err)
|
||||
assert.Equal(1, val)
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Back(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue := NewCircularQueue[int](3)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(5, queue.Back())
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
assert.Equal(2, queue.Back())
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(7, queue.Back())
|
||||
val, _ := queue.Dequeue()
|
||||
assert.Equal(1, *val)
|
||||
|
||||
err = queue.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, queue.Back())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||
|
||||
queue := NewCircularQueue[int](2)
|
||||
queue.Enqueue(1)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(2))
|
||||
}
|
||||
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Size())
|
||||
|
||||
queue.Enqueue(1)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
assert.Equal(1, queue.Size())
|
||||
|
||||
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
|
||||
func TestCircularQueue_Data(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
queue.Enqueue(4)
|
||||
queue.Enqueue(5)
|
||||
queue := NewCircularQueue[int](3)
|
||||
err := queue.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
|
||||
queue.Dequeue()
|
||||
queue.Dequeue()
|
||||
queue.Enqueue(6)
|
||||
queue.Enqueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
||||
err = queue.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal([]int{1, 2}, queue.Data())
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
@@ -23,19 +23,24 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
pq := NewPriorityQueue[int](3, comparator)
|
||||
|
||||
assert.Equal(true, pq.IsEmpty())
|
||||
assert.Equal(false, pq.IsFull())
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
err := pq.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, pq.IsFull())
|
||||
|
||||
queueData := pq.Data()
|
||||
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
|
||||
assert.Equal([]int{3, 1, 2}, queueData)
|
||||
|
||||
}
|
||||
|
||||
@@ -43,22 +48,23 @@ func TestPriorityQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
||||
|
||||
comparator := &intComparator{}
|
||||
pq := NewPriorityQueue[int](10, comparator)
|
||||
pq := NewPriorityQueue[int](3, comparator)
|
||||
|
||||
_, ok := pq.Dequeue()
|
||||
assert.Equal(false, ok)
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
pq.Enqueue(i)
|
||||
}
|
||||
err := pq.Enqueue(1)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(10, pq.Size())
|
||||
err = pq.Enqueue(2)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = pq.Enqueue(3)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, pq.Size())
|
||||
|
||||
val, ok := pq.Dequeue()
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(10, val)
|
||||
|
||||
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
|
||||
|
||||
assert.Equal(9, pq.Size())
|
||||
assert.Equal(3, val)
|
||||
}
|
||||
|
||||
@@ -4,22 +4,59 @@ package datastructure
|
||||
type Set[T comparable] map[T]struct{}
|
||||
|
||||
// NewSet return a instance of set
|
||||
func NewSet[T comparable](values ...T) Set[T] {
|
||||
func NewSet[T comparable](items ...T) Set[T] {
|
||||
set := make(Set[T])
|
||||
set.Add(values...)
|
||||
set.Add(items...)
|
||||
return set
|
||||
}
|
||||
|
||||
// Add value to set
|
||||
func (s Set[T]) Add(values ...T) {
|
||||
for _, v := range values {
|
||||
// NewSetFromSlice create a set from slice
|
||||
func NewSetFromSlice[T comparable](items []T) Set[T] {
|
||||
set := make(Set[T])
|
||||
for _, item := range items {
|
||||
set.Add(item)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// Add items to set
|
||||
func (s Set[T]) Add(items ...T) {
|
||||
for _, v := range items {
|
||||
s[v] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Contain checks if set contains value or not
|
||||
func (s Set[T]) Contain(value T) bool {
|
||||
_, ok := s[value]
|
||||
// AddIfNotExist checks if item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exist in the set,
|
||||
// or else it does nothing and returns false.
|
||||
func (s Set[T]) AddIfNotExist(item T) bool {
|
||||
if !s.Contain(item) {
|
||||
if _, ok := s[item]; !ok {
|
||||
s[item] = struct{}{}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddIfNotExistBy checks if item exists in the set and pass the `checker` function
|
||||
// it adds the item to set and returns true if it does not exists in the set and
|
||||
// function `checker` returns true, or else it does nothing and returns false.
|
||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool {
|
||||
if !s.Contain(item) {
|
||||
if checker(item) {
|
||||
if _, ok := s[item]; !ok {
|
||||
s[item] = struct{}{}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Contain checks if set contains item or not
|
||||
func (s Set[T]) Contain(item T) bool {
|
||||
_, ok := s[item]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -41,9 +78,9 @@ func (s Set[T]) Clone() Set[T] {
|
||||
return set
|
||||
}
|
||||
|
||||
// Delete value of set
|
||||
func (s Set[T]) Delete(values ...T) {
|
||||
for _, v := range values {
|
||||
// Delete item of set
|
||||
func (s Set[T]) Delete(items ...T) {
|
||||
for _, v := range items {
|
||||
delete(s, v)
|
||||
}
|
||||
}
|
||||
@@ -58,7 +95,7 @@ func (s Set[T]) Equal(other Set[T]) bool {
|
||||
}
|
||||
|
||||
// Iterate call function by every element of set
|
||||
func (s Set[T]) Iterate(fn func(value T)) {
|
||||
func (s Set[T]) Iterate(fn func(item T)) {
|
||||
for v := range s {
|
||||
fn(v)
|
||||
}
|
||||
@@ -76,13 +113,13 @@ func (s Set[T]) Size() int {
|
||||
|
||||
// Values return all values of set
|
||||
func (s Set[T]) Values() []T {
|
||||
values := make([]T, 0, 0)
|
||||
result := make([]T, 0, len(s))
|
||||
|
||||
s.Iterate(func(value T) {
|
||||
values = append(values, value)
|
||||
result = append(result, value)
|
||||
})
|
||||
|
||||
return values
|
||||
return result
|
||||
}
|
||||
|
||||
// Union creates a new set contain all element of set s and other
|
||||
|
||||
@@ -6,6 +6,19 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestSet_NewSetFromSlice(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_NewSetFromSlice")
|
||||
|
||||
s1 := NewSetFromSlice([]int{1, 2, 2, 3})
|
||||
assert.Equal(3, s1.Size())
|
||||
assert.Equal(true, s1.Contain(1))
|
||||
assert.Equal(true, s1.Contain(2))
|
||||
assert.Equal(true, s1.Contain(3))
|
||||
|
||||
s2 := NewSetFromSlice([]int{})
|
||||
assert.Equal(0, s2.Size())
|
||||
}
|
||||
|
||||
func TestSet_Add(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Add")
|
||||
|
||||
@@ -17,6 +30,38 @@ func TestSet_Add(t *testing.T) {
|
||||
assert.Equal(true, set.Equal(expected))
|
||||
}
|
||||
|
||||
func TestSet_AddIfNotExist(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_AddIfNotExist")
|
||||
|
||||
set := NewSet[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
assert.Equal(false, set.AddIfNotExist(1))
|
||||
assert.Equal(true, set.AddIfNotExist(4))
|
||||
assert.Equal(NewSet(1, 2, 3, 4), set)
|
||||
}
|
||||
|
||||
func TestSet_AddIfNotExistBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_AddIfNotExistBy")
|
||||
|
||||
set := NewSet[int]()
|
||||
set.Add(1, 2)
|
||||
|
||||
ok := set.AddIfNotExistBy(3, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
|
||||
notOk := set.AddIfNotExistBy(4, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(false, notOk)
|
||||
|
||||
assert.Equal(true, set.Contain(3))
|
||||
assert.Equal(false, set.Contain(4))
|
||||
}
|
||||
|
||||
func TestSet_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Contain")
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ func TestLinkedStack_Push(t *testing.T) {
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
stack.Print()
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := stack.Data()
|
||||
size := stack.Size()
|
||||
|
||||
@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
|
||||
bstree.Insert(5)
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
}
|
||||
|
||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
@@ -86,8 +84,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
acturl := bstree.LevelOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||
@@ -103,10 +99,8 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
bstree.Delete(4)
|
||||
bstree.Print()
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
t.Log(acturl1)
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
|
||||
bstree.Insert(2)
|
||||
bstree.Insert(4)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
assert.Equal(bstree.Depth(), 4)
|
||||
}
|
||||
|
||||
@@ -150,8 +142,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
|
||||
subTree.Insert(4)
|
||||
subTree.Insert(6)
|
||||
|
||||
subTree.Print()
|
||||
|
||||
assert.Equal(true, superTree.HasSubTree(subTree))
|
||||
assert.Equal(false, subTree.HasSubTree(superTree))
|
||||
}
|
||||
|
||||
@@ -38,35 +38,35 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
return data
|
||||
}
|
||||
|
||||
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
}
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// preOrderPrint(node.Left)
|
||||
// preOrderPrint(node.Right)
|
||||
// }
|
||||
|
||||
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
}
|
||||
// postOrderPrint(node.Left)
|
||||
// postOrderPrint(node.Right)
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// }
|
||||
|
||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
// if node == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
inOrderPrint(node.Left)
|
||||
fmt.Printf("%v, ", node.Value)
|
||||
inOrderPrint(node.Right)
|
||||
}
|
||||
// inOrderPrint(node.Left)
|
||||
// fmt.Printf("%v, ", node.Value)
|
||||
// inOrderPrint(node.Right)
|
||||
// }
|
||||
|
||||
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
||||
var q []*datastructure.TreeNode[T] // queue
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
@@ -31,7 +32,6 @@ import (
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
@@ -570,6 +570,8 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -586,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
@@ -571,6 +570,8 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -587,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
## Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>return a Channel pointer instance.</p>
|
||||
<p>Create a Channel pointer instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -57,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -87,25 +87,30 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>merge multiple channels into one channel until cancel the context.</p>
|
||||
<p>Merge multiple channels into one channel until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -136,17 +141,17 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -154,12 +159,12 @@ func main() {
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
|
||||
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -176,26 +181,30 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
||||
<p>Creates a channel, then put values into the channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -212,16 +221,58 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -234,7 +285,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -249,7 +300,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +310,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
@@ -282,7 +331,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -299,12 +348,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +366,12 @@ func main() {
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
|
||||
<p>Create a channel whose values are taken from another channel with limit number.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -335,7 +388,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +396,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +413,12 @@ func main() {
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>Split one chanel into two channels until cancel context.</p>
|
||||
<p>Split one chanel into two channels, until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -378,13 +435,19 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
### Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>返回一个 Channel 指针实例</p>
|
||||
<p>返回一个Channel指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -57,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,12 +65,12 @@ func main() {
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>将多个通道链接到一个通道,直到取消上下文。</p>
|
||||
<p>将多个channel链接到一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -84,28 +84,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>将多个通道合并为一个通道,直到取消上下文</p>
|
||||
<p>将多个channel合并为一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -133,33 +138,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
|
||||
<p>根据传入的值,生成channel.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -173,15 +178,58 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
@@ -190,12 +238,12 @@ func main() {
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
|
||||
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -209,19 +257,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -229,12 +281,12 @@ func main() {
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
|
||||
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -249,7 +301,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +311,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
@@ -277,12 +327,12 @@ func main() {
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>将一个通道读入另一个通道,直到取消上下文。</p>
|
||||
<p>将一个channel读入另一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -299,12 +349,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +367,12 @@ func main() {
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
|
||||
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -335,7 +389,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +397,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +414,12 @@ func main() {
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>将一个通道分成两个通道,直到取消上下文。</p>
|
||||
<p>将一个channel分成两个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -378,13 +436,19 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -120,7 +121,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
<p>Returns false iff neither a nor b is truthy.</p>
|
||||
<p>Returns false if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -148,7 +149,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Xor">Xor</span>
|
||||
<p>Returns true iff a or b but not both is truthy.</p>
|
||||
<p>Returns true if a or b but not both is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -176,7 +177,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Nor">Nor</span>
|
||||
<p>Returns true iff neither a nor b is truthy.</p>
|
||||
<p>Returns true if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -197,14 +198,40 @@ func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>Returns true if both a and b or neither a nor b are truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>Returns false iff both a and b are truthy</p>
|
||||
<p>Returns false if both a and b are truthy</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -196,12 +197,38 @@ func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>如果a和b都是真的或a和b均是假的,则返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>如果a和b都为真,返回false,否则返回true</p>
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToChannel](#ToChannel)
|
||||
|
||||
- [ToFloat](#ToFloat)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
@@ -103,7 +102,7 @@ func main() {
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
||||
<p>Convert string to bool. Use strconv.ParseBool.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -139,7 +138,7 @@ func main() {
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>Convert interface to byte slice.</p>
|
||||
<p>Convert value to byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -201,7 +200,7 @@ func main() {
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>Convert a collection of elements to a read-only channels.</p>
|
||||
<p>Convert a collection of elements to a read-only channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -239,7 +238,7 @@ func main() {
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
|
||||
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -272,7 +271,7 @@ func main() {
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -333,7 +332,7 @@ func main() {
|
||||
|
||||
### <span id="ToMap">ToMap</span>
|
||||
|
||||
<p>Convert a slice or an array of structs to a map based on iteratee function. </p>
|
||||
<p>Convert a slice of structs to a map based on iteratee function. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -395,6 +394,32 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToString(value any) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%q", convertor.ToString(1)) //"1"
|
||||
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
|
||||
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="StructToMap">StructToMap</span>
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToChannel](#ToChannel)
|
||||
|
||||
- [ToFloat](#ToFloat)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
@@ -401,7 +400,7 @@ func main() {
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>将interface转成字符串</p>
|
||||
<p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -523,7 +522,7 @@ func main() {
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ import (
|
||||
- [HmacSha1](#HmacSha1)
|
||||
- [HmacSha256](#HmacSha256)
|
||||
- [HmacSha512](#HmacSha512)
|
||||
|
||||
- [Md5String](#Md5String)
|
||||
- [Md5File](#Md5File)
|
||||
- [Sha1](#Sha1)
|
||||
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
- [AesOfbDecrypt](#AesOfbDecrypt)
|
||||
- [Base64StdEncode](#Base64StdEncode)
|
||||
- [Base64StdDecode](#Base64StdDecode)
|
||||
|
||||
- [DesEcbEncrypt](#DesEcbEncrypt)
|
||||
- [DesEcbDecrypt](#DesEcbDecrypt)
|
||||
- [DesCbcEncrypt](#DesCbcEncrypt)
|
||||
@@ -43,7 +42,6 @@ import (
|
||||
- [DesCfbDecrypt](#DesCfbDecrypt)
|
||||
- [DesOfbEncrypt](#DesOfbEncrypt)
|
||||
- [DesOfbDecrypt](#DesOfbDecrypt)
|
||||
|
||||
- [HmacMd5](#HmacMd5)
|
||||
- [HmacSha1](#HmacSha1)
|
||||
- [HmacSha256](#HmacSha256)
|
||||
|
||||
@@ -132,12 +132,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||
<p>Insert value into singly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
||||
<p>Insert value into singly linklist at index, param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -152,6 +152,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewSinglyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -228,12 +230,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
||||
<p>Delete value at specific index, param `index` should be [0, len(SinglyLink)-1]</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
||||
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -253,9 +255,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -268,7 +269,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
||||
func (link *SinglyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -288,9 +289,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -304,7 +304,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
||||
func (link *SinglyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -323,9 +323,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
@@ -628,12 +627,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||
<p>Insert value into doubly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
||||
<p>Insert value into doubly linklist at index, param `index` should between [0, len(DoublyLink)], if index do not meet the conditions, do nothing</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -648,6 +647,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewDoublyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -724,12 +725,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
||||
<p>Delete value at specific index, param `index` should be [0, len(DoublyLink)-1]</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
||||
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -749,9 +750,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -764,7 +764,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
||||
func (link *DoublyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -784,9 +784,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -132,12 +132,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -152,6 +152,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewSinglyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -228,12 +230,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
||||
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -253,9 +255,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -268,7 +269,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
||||
func (link *SinglyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -288,9 +289,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -304,7 +304,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
||||
func (link *SinglyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -323,9 +323,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
@@ -628,12 +627,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
||||
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -648,6 +647,8 @@ import (
|
||||
func main() {
|
||||
lk := link.NewDoublyLink[int]()
|
||||
|
||||
lk.InsertAt(1, 1) //do nothing
|
||||
|
||||
lk.InsertAt(0, 1)
|
||||
lk.InsertAt(1, 2)
|
||||
lk.InsertAt(2, 3)
|
||||
@@ -724,12 +725,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
||||
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -749,9 +750,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAt(3)
|
||||
lk.DeleteAt(3)
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||
}
|
||||
```
|
||||
@@ -764,7 +764,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
||||
func (link *DoublyLink[T]) DeleteAtHead()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -784,9 +784,8 @@ func main() {
|
||||
lk.InsertAtTail(3)
|
||||
lk.InsertAtTail(4)
|
||||
|
||||
err := lk.DeleteAtHead()
|
||||
lk.DeleteAtHead()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||
}
|
||||
```
|
||||
@@ -800,7 +799,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (link *DoublyLink[T]) DeleteAtTail() error
|
||||
func (link *DoublyLink[T]) DeleteAtTail()
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -819,9 +818,8 @@ func main() {
|
||||
lk.InsertAtTail(2)
|
||||
lk.InsertAtTail(3)
|
||||
|
||||
err := lk.DeleteAtTail()
|
||||
lk.DeleteAtTail()
|
||||
|
||||
fmt.Println(err) //nil
|
||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -22,8 +22,11 @@ import (
|
||||
## Index
|
||||
|
||||
- [NewSet](#NewSet)
|
||||
- [NewSetFromSlice](#NewSetFromSlice)
|
||||
- [Values](#Values)
|
||||
- [Add](#Add)
|
||||
- [AddIfNotExist](#AddIfNotExist)
|
||||
- [AddIfNotExistBy](#AddIfNotExistBy)
|
||||
- [Delete](#Delete)
|
||||
- [Contain](#Contain)
|
||||
- [ContainAll](#ContainAll)
|
||||
@@ -34,7 +37,6 @@ import (
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [Minus](#Minus)
|
||||
|
||||
@@ -45,13 +47,13 @@ import (
|
||||
## Documentation
|
||||
|
||||
### <span id="NewSet">NewSet</span>
|
||||
<p>Make a Set instance</p>
|
||||
<p>Create a set instance</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Set[T comparable] map[T]bool
|
||||
func NewSet[T comparable](values ...T) Set[T]
|
||||
func NewSet[T comparable](items ...T) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -70,6 +72,30 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||
<p>Create a set from slice</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSetFromSlice([]int{1, 2, 2, 3})
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
@@ -100,12 +126,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Add">Add</span>
|
||||
<p>Add value to set</p>
|
||||
<p>Add items to set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Add(values ...T)
|
||||
func (s Set[T]) Add(items ...T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -126,14 +152,83 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delete">Delete</span>
|
||||
<p>Delete value in set</p>
|
||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Delete(values ...T)
|
||||
func (s Set[T]) AddIfNotExist(item T) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
r1 := st.AddIfNotExist(1)
|
||||
r2 := st.AddIfNotExist(4)
|
||||
|
||||
fmt.Println(r1) // false
|
||||
fmt.Println(r2) // true
|
||||
fmt.Println(st.Values()) // 1,2,3,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2)
|
||||
|
||||
ok := st.AddIfNotExistBy(3, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
fmt.Println(ok) // true
|
||||
|
||||
|
||||
notOk := st.AddIfNotExistBy(4, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
fmt.Println(notOk) // false
|
||||
|
||||
fmt.Println(st.Values()) // 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Delete">Delete</span>
|
||||
<p>Delete item in set</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Delete(items ...T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -157,12 +252,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
<p>Check if value is in set or not</p>
|
||||
<p>Check if item is in set or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Contain(value T) bool
|
||||
func (s Set[T]) Contain(item T) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -309,7 +404,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Iterate(fn func(value T))
|
||||
func (s Set[T]) Iterate(fn func(item T))
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -324,8 +419,8 @@ import (
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
set.Iterate(func(item int) {
|
||||
arr = append(arr, item)
|
||||
})
|
||||
|
||||
fmt.Println(arr) //1,2,3
|
||||
|
||||
@@ -22,8 +22,11 @@ import (
|
||||
## 目录
|
||||
|
||||
- [NewSet](#NewSet)
|
||||
- [NewSetFromSlice](#NewSetFromSlice)
|
||||
- [Values](#Values)
|
||||
- [Add](#Add)
|
||||
- [AddIfNotExist](#AddIfNotExist)
|
||||
- [AddIfNotExistBy](#AddIfNotExistBy)
|
||||
- [Delete](#Delete)
|
||||
- [Contain](#Contain)
|
||||
- [ContainAll](#ContainAll)
|
||||
@@ -34,7 +37,6 @@ import (
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Union](#Union)
|
||||
- [Intersection](#Intersection)
|
||||
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [Minus](#Minus)
|
||||
|
||||
@@ -51,7 +53,7 @@ import (
|
||||
|
||||
```go
|
||||
type Set[T comparable] map[T]bool
|
||||
func NewSet[T comparable](values ...T) Set[T]
|
||||
func NewSet[T comparable](items ...T) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -71,6 +73,31 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||
<p>基于切片创建集合</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSetFromSlice([]int{1, 2, 2, 3})
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
<p>获取集合中所有元素的切片</p>
|
||||
@@ -105,7 +132,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Add(values ...T)
|
||||
func (s Set[T]) Add(items ...T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -126,6 +153,76 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) AddIfNotExist(item T) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
r1 := st.AddIfNotExist(1)
|
||||
r2 := st.AddIfNotExist(4)
|
||||
|
||||
fmt.Println(r1) // false
|
||||
fmt.Println(r2) // true
|
||||
fmt.Println(st.Values()) // 1,2,3,4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st.Add(1, 2)
|
||||
|
||||
ok := st.AddIfNotExistBy(3, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
fmt.Println(ok) // true
|
||||
|
||||
|
||||
notOk := st.AddIfNotExistBy(4, func(val int) bool {
|
||||
return val%2 != 0
|
||||
})
|
||||
fmt.Println(notOk) // false
|
||||
|
||||
fmt.Println(st.Values()) // 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delete">Delete</span>
|
||||
<p>删除集合中元素</p>
|
||||
@@ -133,7 +230,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Delete(values ...T)
|
||||
func (s Set[T]) Delete(items ...T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -162,7 +259,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Contain(value T) bool
|
||||
func (s Set[T]) Contain(item T) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -309,7 +406,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) Iterate(fn func(value T))
|
||||
func (s Set[T]) Iterate(fn func(item T))
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -324,8 +421,8 @@ import (
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
set.Iterate(func(item int) {
|
||||
arr = append(arr, item)
|
||||
})
|
||||
|
||||
fmt.Println(arr) //1,2,3
|
||||
@@ -420,9 +517,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
|
||||
- [InOrderTraverse](#BSTree_InOrderTraverse)
|
||||
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
|
||||
|
||||
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
|
||||
- [Depth](#BSTree_Depth)
|
||||
- [HasSubTree](#BSTree_HasSubTree)
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
- [PreOrderTraverse](#BSTree_PreOrderTraverse)
|
||||
- [InOrderTraverse](#BSTree_InOrderTraverse)
|
||||
- [PostOrderTraverse](#BSTree_PostOrderTraverse)
|
||||
|
||||
- [LevelOrderTraverse](#BSTree_LevelOrderTraverse)
|
||||
- [Depth](#BSTree_Depth)
|
||||
- [HasSubTree](#BSTree_HasSubTree)
|
||||
|
||||
@@ -42,7 +42,6 @@ import (
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
- [FormatStrToTime](#FormatStrToTime)
|
||||
|
||||
- [NewUnixNow](#NewUnixNow)
|
||||
- [NewUnix](#NewUnix)
|
||||
- [NewFormat](#NewFormat)
|
||||
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
- [FormatStrToTime](#FormatStrToTime)
|
||||
|
||||
- [NewUnixNow](#NewUnixNow)
|
||||
- [NewUnix](#NewUnix)
|
||||
- [NewFormat](#NewFormat)
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
@@ -120,7 +119,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="CopyFile">CopyFile</span>
|
||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
||||
<p>拷贝文件,会覆盖原有的文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -262,7 +261,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsDir">IsDir</span>
|
||||
<p>判断目录是否存在</p>
|
||||
<p>判断参数是否是目录</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -28,13 +28,12 @@ import (
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
|
||||
Param should be number or numberic string.</p>
|
||||
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Comma(v any, symbol string) string
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ import (
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
||||
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Comma(v any, symbol string) string
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## Index
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -125,15 +125,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
<p>Make a curry function.</p>
|
||||
<p>Make curry function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -149,12 +149,15 @@ func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -167,7 +170,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -180,17 +183,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -259,9 +262,9 @@ import (
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
fmt.Println(count) //delay 2 seconds
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
function.Delay(2*time.Second, print, "delay 2 seconds")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -332,9 +335,9 @@ func main() {
|
||||
return x * x
|
||||
}
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,10 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## 目录
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -124,15 +124,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
<p>创建一个柯里化的函数</p>
|
||||
<p>创建柯里化函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -148,11 +148,14 @@ func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
@@ -161,12 +164,12 @@ func main() {
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
||||
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -179,17 +182,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -197,7 +200,7 @@ func main() {
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -333,7 +336,7 @@ func main() {
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -341,7 +344,7 @@ func main() {
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
|
||||
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,11 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
@@ -46,7 +45,7 @@ import (
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -158,7 +157,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -219,12 +218,12 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
<p>Return the minimum value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -303,8 +302,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
@@ -45,7 +44,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -155,7 +154,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -221,7 +220,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -300,8 +299,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
## Index
|
||||
- [ConvertMapToQueryString](#ConvertMapToQueryString)
|
||||
- [EncodeUrl](#EncodeUrl)
|
||||
|
||||
- [GetInternalIp](#GetInternalIp)
|
||||
- [GetIps](#GetIps)
|
||||
- [GetMacAddrs](#GetMacAddrs)
|
||||
@@ -38,7 +37,6 @@ import (
|
||||
- [SendRequest](#SendRequest)
|
||||
- [DecodeResponse](#DecodeResponse)
|
||||
- [StructToUrlValues](#StructToUrlValues)
|
||||
|
||||
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
|
||||
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
|
||||
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
- [GetMacAddrs](#GetMacAddrs)
|
||||
- [GetPublicIpInfo](#GetPublicIpInfo)
|
||||
- [GetRequestPublicIp](#GetRequestPublicIp)
|
||||
|
||||
- [IsPublicIP](#IsPublicIP)
|
||||
- [IsInternalIP](#IsInternalIP)
|
||||
- [HttpRequest](#HttpRequest)
|
||||
@@ -38,13 +37,11 @@ import (
|
||||
- [SendRequest](#SendRequest)
|
||||
- [DecodeResponse](#DecodeResponse)
|
||||
- [StructToUrlValues](#StructToUrlValues)
|
||||
|
||||
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
|
||||
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
|
||||
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
|
||||
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
|
||||
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
|
||||
|
||||
- [ParseHttpResponse](#ParseHttpResponse)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [RandUpper](#RandUpper)
|
||||
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [RandUpper](#RandUpper)
|
||||
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
|
||||
238
docs/slice.md
238
docs/slice.md
@@ -29,6 +29,7 @@ import (
|
||||
- [Compact](#Compact)
|
||||
- [Concat](#Concat)
|
||||
- [Count](#Count)
|
||||
- [CountBy](#CountBy)
|
||||
- [Difference](#Difference)
|
||||
- [DifferenceBy](#DifferenceBy)
|
||||
- [DifferenceWith](#DifferenceWith)
|
||||
@@ -43,24 +44,27 @@ import (
|
||||
- [Flatten](#Flatten)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](#ForEach)
|
||||
|
||||
- [GroupBy](#GroupBy)
|
||||
- [GroupWith](#GroupWith)
|
||||
- [IntSlice](#IntSlice)
|
||||
- [InterfaceSlice](#InterfaceSlice)
|
||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||
- [InterfaceSlice<sup>deprecated</sup>](#InterfaceSlice)
|
||||
- [Intersection](#Intersection)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
- [Map](#Map)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
- [Replace](#Replace)
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
- [Shuffle](#Shuffle)
|
||||
- [SortByField](#SortByField)
|
||||
- [Sort](#Sort)
|
||||
- [SortBy](#SortBy)
|
||||
- [SortByField<sup>deprecated</sup>](#SortByField)
|
||||
- [Some](#Some)
|
||||
- [StringSlice](#StringSlice)
|
||||
- [StringSlice<sup>deprecated</sup>](#StringSlice)
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [ToSlicePointer](#ToSlicePointer)
|
||||
@@ -78,12 +82,12 @@ import (
|
||||
|
||||
### <span id="AppendIfAbsent">AppendIfAbsent</span>
|
||||
|
||||
<p>If slice doesn't contain the value, append it to the slice.</p>
|
||||
<p>If slice doesn't contain the item, append it to the slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AppendIfAbsent[T comparable](slice []T, value T) []T
|
||||
func AppendIfAbsent[T comparable](slice []T, item T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -106,12 +110,12 @@ func main() {
|
||||
|
||||
### <span id="Contain">Contain</span>
|
||||
|
||||
<p>Check if the value is in the slice or not.</p>
|
||||
<p>Check if the target value is in the slice or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Contain[T comparable](slice []T, value T) bool
|
||||
func Contain[T comparable](slice []T, target T) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -135,7 +139,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ContainSubSlice[T comparable](slice, subslice []T) bool
|
||||
func ContainSubSlice[T comparable](slice, subSlice []T) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -172,8 +176,8 @@ import (
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
res := slice.Chunk(InterfaceSlice(arr), 3)
|
||||
fmt.Println(res) //[][]any{{"a", "b", "c"}, {"d", "e"}}
|
||||
res := slice.Chunk((arr), 3)
|
||||
fmt.Println(res) //[][]string{{"a", "b", "c"}, {"d", "e"}}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,7 +188,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Compact[T any](slice []T) []T
|
||||
func Compact[T comparable](slice []T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -203,12 +207,12 @@ func main() {
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>Creates a new slice concatenating slice with any additional slices and/or values.</p>
|
||||
<p>Creates a new slice concatenating slice with any additional slices.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](slice []T, values ...[]T) []T
|
||||
func Concat[T any](slice []T, slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -230,12 +234,38 @@ func main() {
|
||||
|
||||
### <span id="Count">Count</span>
|
||||
|
||||
<p>Count iterates over elements of slice, returns a count of all matched elements.</p>
|
||||
<p>Returns the number of occurrences of the given item in the slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Count[T any](slice []T, predicate func(index int, t T) bool) int
|
||||
func Count[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 3, 4, 5}
|
||||
|
||||
fmt.Println(slice.Count(nums, 1)) //1
|
||||
fmt.Println(slice.Count(nums, 3)) //2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CountBy">CountBy</span>
|
||||
|
||||
<p>Iterates over elements of slice with predicate function, returns the number of all matched elements.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CountBy[T any](slice []T, predicate func(index int, item T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -248,15 +278,16 @@ import (
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
evenFunc := func(i, num int) bool {
|
||||
evenFunc := func(_, num int) bool {
|
||||
return (num % 2) == 0
|
||||
}
|
||||
|
||||
res := slice.Count(nums, evenFunc)
|
||||
res := slice.CountBy(nums, evenFunc)
|
||||
fmt.Println(res) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Difference">Difference</span>
|
||||
|
||||
<p>Creates an slice of whose element not included in the other given slice.</p>
|
||||
@@ -715,11 +746,12 @@ func main() {
|
||||
return math.Floor(num)
|
||||
}
|
||||
res := slice.GroupWith(nums, floor)
|
||||
|
||||
fmt.Println(res) //map[float64][]float64{ 4: {4.2}, 6: {6.1, 6.3},}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IntSlice">IntSlice</span>
|
||||
### <span id="IntSlice">IntSlice (Deprecated: use generic feature of go1.18+ for replacement)</span>
|
||||
|
||||
<p>Convert interface slice to int slice.</p>
|
||||
|
||||
@@ -744,7 +776,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="InterfaceSlice">InterfaceSlice</span>
|
||||
### <span id="InterfaceSlice">InterfaceSlice (Deprecated: use generic feature of go1.18+ for replacement)</span>
|
||||
|
||||
<p>Convert value to interface slice.</p>
|
||||
|
||||
@@ -827,12 +859,12 @@ func main() {
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>Returns the index at which the first occurrence of a value is found in a slice or return -1 if the value cannot be found.</p>
|
||||
<p>Returns the index at which the first occurrence of a item is found in a slice or return -1 if the item cannot be found.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IndexOf[T comparable](slice []T, value T) int
|
||||
func IndexOf[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -855,12 +887,12 @@ func main() {
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>Returns the index at which the last occurrence of a value is found in a slice or return -1 if the value cannot be found.</p>
|
||||
<p>Returns the index at which the last occurrence of a item is found in a slice or return -1 if the item cannot be found.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LastIndexOf[T comparable](slice []T, value T) int
|
||||
func LastIndexOf[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -909,6 +941,36 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
|
||||
<p>Merge all given slices into one slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Merge[T any](slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := []int{1, 2, 3}
|
||||
s2 := []int{2, 4}
|
||||
res := slice.Merge(s1, s2)
|
||||
|
||||
fmt.Println(res) //[]int{1, 2, 3, 2, 4}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
|
||||
<p>Reverse the elements order in slice.</p>
|
||||
@@ -1018,6 +1080,31 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>Creates a slice with length n whose elements are passed param item.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Repeat[T any](item T, n int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(slice.Repeat("a", 3)) //[]string{"a", "a", "a"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Shuffle">Shuffle</span>
|
||||
|
||||
<p>Creates an slice of shuffled values.</p>
|
||||
@@ -1043,7 +1130,94 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SortByField">SortByField</span>
|
||||
### <span id="Sort">Sort</span>
|
||||
|
||||
<p>Sorts a slice of any ordered type(number or string), use quick sort algrithm. Default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`. Ordered type: number(all ints uints floats) or string.
|
||||
</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
numbers := []int{1, 4, 3, 2, 5}
|
||||
|
||||
slice.Sort(numbers)
|
||||
fmt.Println(numbers) //{1,2,3,4,5}
|
||||
|
||||
slice.Sort(numbers, "desc")
|
||||
fmt.Println(numbers) //{5,4,3,2,1}
|
||||
|
||||
strings := []string{"a", "d", "c", "b", "e"}
|
||||
|
||||
slice.Sort(strings)
|
||||
fmt.Println(strings) //{"a", "b", "c", "d", "e"}
|
||||
|
||||
slice.Sort(strings, "desc")
|
||||
fmt.Println(strings) //{"e", "d", "c", "b", "a"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SortBy">SortBy</span>
|
||||
|
||||
<p>Sorts the slice in ascending order as determined by the less function. This sort is not guaranteed to be stable.<p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SortBy[T any](slice []T, less func(a, b T) bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
numbers := []int{1, 4, 3, 2, 5}
|
||||
|
||||
slice.SortBy(numbers, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
fmt.Println(numbers) //{1, 2, 3, 4, 5}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
slice.SortBy(users, func(a, b User) bool {
|
||||
return a.Age < b.Age
|
||||
})
|
||||
|
||||
fmt.Printf("sort users by age: %v", users)
|
||||
|
||||
// output
|
||||
// [{b 15} {a 21} {c 100}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SortByField">SortByField (Deprecated: use Sort and SortBy for replacement)</span>
|
||||
|
||||
<p>Sort struct slice by field. Slice element should be struct, field type should be int, uint, string, or bool. Default sort type is ascending (asc), if descending order, set sortType to desc</p>
|
||||
|
||||
@@ -1115,7 +1289,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StringSlice">StringSlice</span>
|
||||
### <span id="StringSlice">StringSlice (Deprecated: use generic feature of go1.18+ for replacement)</span>
|
||||
|
||||
<p>Convert interface slice to string slice.</p>
|
||||
|
||||
@@ -1171,12 +1345,12 @@ func main() {
|
||||
|
||||
### <span id="ToSlice">ToSlice</span>
|
||||
|
||||
<p>Returns a slices of a variable parameter transformation</p>
|
||||
<p>Creates a slice of give items.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToSlice[T any](value ...T) []T
|
||||
func ToSlice[T any](items ...T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -1200,7 +1374,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToSlicePointer[T any](value ...T) []*T
|
||||
func ToSlicePointer[T any](items ...T) []*T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
@@ -1351,12 +1525,12 @@ func main() {
|
||||
|
||||
### <span id="Without">Without</span>
|
||||
|
||||
<p>Creates a slice excluding all given values. </p>
|
||||
<p>Creates a slice excluding all given items. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Without[T comparable](slice []T, values ...T) []T
|
||||
func Without[T comparable](slice []T, items ...T) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
## 目录
|
||||
|
||||
|
||||
- [AppendIfAbsent](#AppendIfAbsent)
|
||||
- [Contain](#Contain)
|
||||
- [ContainSubSlice](#ContainSubSlice)
|
||||
@@ -29,6 +31,7 @@ import (
|
||||
- [Compact](#Compact)
|
||||
- [Concat](#Concat)
|
||||
- [Count](#Count)
|
||||
- [CountBy](#CountBy)
|
||||
- [Difference](#Difference)
|
||||
- [DifferenceBy](#DifferenceBy)
|
||||
- [DifferenceWith](#DifferenceWith)
|
||||
@@ -45,22 +48,25 @@ import (
|
||||
- [ForEach](#ForEach)
|
||||
- [GroupBy](#GroupBy)
|
||||
- [GroupWith](#GroupWith)
|
||||
- [IntSlice](#IntSlice)
|
||||
|
||||
- [InterfaceSlice](#InterfaceSlice)
|
||||
- [IntSlice<sup>deprecated</sup>](#IntSlice)
|
||||
- [InterfaceSlice<sup>deprecated</sup>](#InterfaceSlice)
|
||||
- [Intersection](#Intersection)
|
||||
- [InsertAt](#InsertAt)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
- [Map](#Map)
|
||||
- [Merge](#Merge)
|
||||
- [Reverse](#Reverse)
|
||||
- [Reduce](#Reduce)
|
||||
- [Replace](#Replace)
|
||||
- [ReplaceAll](#ReplaceAll)
|
||||
- [Repeat](#Repeat)
|
||||
- [Shuffle](#Shuffle)
|
||||
- [SortByField](#SortByField)
|
||||
- [Sort](#Sort)
|
||||
- [SortBy](#SortBy)
|
||||
- [SortByField<sup>deprecated</sup>](#SortByField)
|
||||
- [Some](#Some)
|
||||
- [StringSlice](#StringSlice)
|
||||
- [StringSlice<sup>deprecated</sup>](#StringSlice)
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [ToSlicePointer](#ToSlicePointer)
|
||||
@@ -72,6 +78,7 @@ import (
|
||||
- [Without](#Without)
|
||||
- [KeyBy](#KeyBy)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
@@ -83,7 +90,7 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AppendIfAbsent[T comparable](slice []T, value T) []T
|
||||
func AppendIfAbsent[T comparable](slice []T, item T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -111,7 +118,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Contain[T comparable](slice []T, value T) bool
|
||||
func Contain[T comparable](slice []T, target T) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -135,7 +142,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ContainSubSlice[T comparable](slice, subslice []T) bool
|
||||
func ContainSubSlice[T comparable](slice, subSlice []T) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -172,8 +179,8 @@ import (
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
res := slice.Chunk(InterfaceSlice(arr), 3)
|
||||
fmt.Println(res) //[][]any{{"a", "b", "c"}, {"d", "e"}}
|
||||
res := slice.Chunk(arr, 3)
|
||||
fmt.Println(res) //[][]string{{"a", "b", "c"}, {"d", "e"}}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,7 +191,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compact[T any](slice []T) []T
|
||||
func Compact[T comparable](slice []T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -203,12 +210,12 @@ func main() {
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>连接values到slice中,values类型可以是切片或多个值</p>
|
||||
<p>合并多个slices到slice中</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](slice []T, values ...[]T) []T
|
||||
func Concat[T any](slice []T, slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -230,12 +237,38 @@ func main() {
|
||||
|
||||
### <span id="Count">Count</span>
|
||||
|
||||
<p>遍历切片,对每个元素执行函数function. 返回符合函数返回值为true的元素的个数</p>
|
||||
<p>返回切片中指定元素的个数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Count[T any](slice []T, predicate func(index int, t T) bool) int
|
||||
func Count[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 3, 4, 5}
|
||||
|
||||
fmt.Println(slice.Count(nums, 1)) //1
|
||||
fmt.Println(slice.Count(nums, 3)) //2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CountBy">CountBy</span>
|
||||
|
||||
<p>遍历切片,对每个元素执行函数predicate. 返回符合函数返回值为true的元素的个数.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CountBy[T any](slice []T, predicate func(index int, item T) bool) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -248,11 +281,11 @@ import (
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
evenFunc := func(i, num int) bool {
|
||||
evenFunc := func(_, num int) bool {
|
||||
return (num % 2) == 0
|
||||
}
|
||||
|
||||
res := slice.Count(nums, evenFunc)
|
||||
res := slice.CountBy(nums, evenFunc)
|
||||
fmt.Println(res) //3
|
||||
}
|
||||
```
|
||||
@@ -286,7 +319,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceBy">DifferenceBy</span>
|
||||
|
||||
<p>在slice和comparedSlice中的每个元素调用iteratee函数,并比较它们的返回值,如果不想等返回在slice中对应的值</p>
|
||||
<p>将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -316,7 +349,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceWith">DifferenceWith</span>
|
||||
|
||||
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
<p>接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -346,7 +379,7 @@ func main() {
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
|
||||
<p>删除切片中从开始索引到结束索引-1的元素</p>
|
||||
<p>删除切片中指定开始索引到结束索引的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -374,7 +407,7 @@ func main() {
|
||||
|
||||
### <span id="Drop">Drop</span>
|
||||
|
||||
<p>创建一个切片,当 n > 0 时从开头删除 n 个元素,或者当 n < 0 时从结尾删除 n 个元素</p>
|
||||
<p>创建一个切片,当n > 0时从开头删除n个元素,或者当n < 0时从结尾删除n个元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -719,7 +752,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IntSlice">IntSlice</span>
|
||||
### <span id="IntSlice">IntSlice (已弃用: 使用go1.18+泛型代替)</span>
|
||||
|
||||
<p>将接口切片转换为int切片</p>
|
||||
|
||||
@@ -744,7 +777,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="InterfaceSlice">InterfaceSlice</span>
|
||||
### <span id="InterfaceSlice">InterfaceSlice(已弃用: 使用go1.18+泛型代替)</span>
|
||||
|
||||
<p>将值转换为接口切片</p>
|
||||
|
||||
@@ -832,7 +865,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IndexOf[T comparable](slice []T, value T) int
|
||||
func IndexOf[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -860,7 +893,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LastIndexOf[T comparable](slice []T, value T) int
|
||||
func LastIndexOf[T comparable](slice []T, item T) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -883,7 +916,7 @@ func main() {
|
||||
|
||||
### <span id="Map">Map</span>
|
||||
|
||||
<p>通过运行函数slice中的每个元素来创建一个新切片</p>
|
||||
<p>对slice中的每个元素执行map函数以创建一个新切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -909,6 +942,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
|
||||
<p>合并多个切片(不会消除重复元素).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Merge[T any](slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := []int{1, 2, 3}
|
||||
s2 := []int{2, 4}
|
||||
res := slice.Merge(s1, s2)
|
||||
|
||||
fmt.Println(res) //[]int{1, 2, 3, 2, 4}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
|
||||
<p>反转切片中的元素顺序</p>
|
||||
@@ -1018,6 +1079,30 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>创建一个切片,包含n个传入的item</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Repeat[T any](item T, n int) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(slice.Repeat("a", 3)) //[]string{"a", "a", "a"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Shuffle">Shuffle</span>
|
||||
|
||||
<p>随机打乱切片中的元素顺序</p>
|
||||
@@ -1043,7 +1128,93 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SortByField">SortByField</span>
|
||||
### <span id="Sort">Sort</span>
|
||||
|
||||
<p>对任何有序类型(数字或字符串)的切片进行排序,使用快速排序算法。 默认排序顺序为升序 (asc),如果需要降序,请将参数 `sortOrder` 设置为 `desc`。 Ordered类型:数字(所有整数浮点数)或字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
numbers := []int{1, 4, 3, 2, 5}
|
||||
|
||||
slice.Sort(numbers)
|
||||
fmt.Println(numbers) //{1,2,3,4,5}
|
||||
|
||||
slice.Sort(numbers, "desc")
|
||||
fmt.Println(numbers) //{5,4,3,2,1}
|
||||
|
||||
strings := []string{"a", "d", "c", "b", "e"}
|
||||
|
||||
slice.Sort(strings)
|
||||
fmt.Println(strings) //{"a", "b", "c", "d", "e"}
|
||||
|
||||
slice.Sort(strings, "desc")
|
||||
fmt.Println(strings) //{"e", "d", "c", "b", "a"}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SortBy">SortBy</span>
|
||||
|
||||
<p>按照less函数确定的升序规则对切片进行排序。排序不保证稳定性</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SortBy[T any](slice []T, less func(a, b T) bool)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
numbers := []int{1, 4, 3, 2, 5}
|
||||
|
||||
slice.SortBy(numbers, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
fmt.Println(numbers) //{1, 2, 3, 4, 5}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
slice.SortBy(users, func(a, b User) bool {
|
||||
return a.Age < b.Age
|
||||
})
|
||||
|
||||
fmt.Printf("sort users by age: %v", users)
|
||||
|
||||
// output
|
||||
// [{b 15} {a 21} {c 100}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SortByField">SortByField (已弃用: 请使用 Sort或SortBy 代替该方法)</span>
|
||||
|
||||
<p>按字段对结构切片进行排序。slice元素应为struct,字段类型应为int、uint、string或bool。 默认排序类型是升序(asc),如果是降序,设置 sortType 为 desc</p>
|
||||
|
||||
@@ -1115,7 +1286,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StringSlice">StringSlice</span>
|
||||
### <span id="StringSlice">StringSlice(已弃用: 使用go1.18+泛型代替)</span>
|
||||
|
||||
<p>将接口切片转换为字符串切片</p>
|
||||
|
||||
@@ -1176,7 +1347,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToSlice[T any](value ...T) []T
|
||||
func ToSlice[T any](items ...T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -1200,7 +1371,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToSlicePointer[T any](value ...T) []*T
|
||||
func ToSlicePointer[T any](items ...T) []*T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
@@ -1271,7 +1442,7 @@ func main() {
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
|
||||
<p>合并多个切片.</p>
|
||||
<p>合并多个切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1356,7 +1527,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Without[T comparable](slice []T, values ...T) []T
|
||||
func Without[T comparable](slice []T, items ...T) []T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
166
docs/strutil.md
166
docs/strutil.md
@@ -28,15 +28,17 @@ import (
|
||||
- [Capitalize](#Capitalize)
|
||||
- [IsString](#IsString)
|
||||
- [KebabCase](#KebabCase)
|
||||
- [UpperKebabCase](#UpperKebabCase)
|
||||
- [LowerFirst](#LowerFirst)
|
||||
- [UpperFirst](#UpperFirst)
|
||||
- [PadEnd](#PadEnd)
|
||||
- [PadStart](#PadStart)
|
||||
- [Reverse](#Reverse)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
|
||||
@@ -46,7 +48,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>Creates substring in source string after position when char first appear.</p>
|
||||
<p>Returns the substring after the first occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -76,7 +78,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>Creates substring in source string after position when char last appear.</p>
|
||||
<p>Returns the substring after the last occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -107,7 +109,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the first occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -138,7 +140,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the last occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -166,10 +168,8 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>Covert string to camelCase string.</p>
|
||||
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -196,6 +196,75 @@ func main() {
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.KebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo-bar
|
||||
|
||||
s2 := strutil.KebabCase("foo_Bar")
|
||||
fmt.Println(s2) //foo-bar
|
||||
|
||||
s3 := strutil.KebabCase("fooBar")
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -458,7 +527,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>Covert string to snake_case.</p>
|
||||
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -484,14 +553,47 @@ func main() {
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f_o_o_b_a_r
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
@@ -530,9 +632,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>Returns a substring of the specified length starting at the specified offset position.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Wrap a string with another string.</p>
|
||||
<p>Wrap a string with given string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -569,7 +707,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Unwrap a given string from anther string. will change str value.</p>
|
||||
<p>Unwrap a given string from anther string. will change source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -28,15 +28,17 @@ import (
|
||||
- [Capitalize](#Capitalize)
|
||||
- [IsString](#IsString)
|
||||
- [KebabCase](#KebabCase)
|
||||
- [UpperKebabCase](#UpperKebabCase)
|
||||
- [LowerFirst](#LowerFirst)
|
||||
- [UpperFirst](#UpperFirst)
|
||||
- [PadEnd](#PadEnd)
|
||||
- [PadStart](#PadStart)
|
||||
- [Reverse](#Reverse)
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
|
||||
@@ -47,7 +49,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -77,7 +79,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -108,7 +110,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -139,7 +141,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -170,7 +172,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>将字符串转换为驼峰式字符串</p>
|
||||
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -197,6 +199,9 @@ func main() {
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
}
|
||||
```
|
||||
|
||||
@@ -234,7 +239,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsString">IsString</span>
|
||||
<p>检查值的数据类型是否为字符串</p>
|
||||
<p>判断传入参数的数据类型是否为字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -262,7 +267,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>将字符串转换为kebab-case</p>
|
||||
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -288,7 +293,40 @@ func main() {
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f-o-o-b-a-r
|
||||
fmt.Println(s4) //foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -330,7 +368,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="UpperFirst">UpperFirst</span>
|
||||
<p>将字符串的第一个字符转换为大写</p>
|
||||
<p>将字符串的第一个字符转换为大写形式</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -459,7 +497,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>将字符串转换为snake_case形式</p>
|
||||
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -485,10 +523,45 @@ func main() {
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f_o_o_b_a_r
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
@@ -528,6 +601,42 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>根据指定的位置和长度截取子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
|
||||
@@ -102,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
@@ -211,7 +211,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
<p>Use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
||||
<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>
|
||||
|
||||
@@ -227,10 +227,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
// linux or mac
|
||||
stdout, stderr, err := system.ExecCommand("ls")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
assert.Equal("", stderr)
|
||||
|
||||
// windows
|
||||
stdout, stderr, err = system.ExecCommand("dir")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
|
||||
// error command
|
||||
stdout, stderr, err = system.ExecCommand("abc")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
@@ -103,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
@@ -212,7 +211,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -228,10 +227,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
// linux or mac
|
||||
stdout, stderr, err := system.ExecCommand("ls")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
assert.Equal("", stderr)
|
||||
|
||||
// windows
|
||||
stdout, stderr, err = system.ExecCommand("dir")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
|
||||
// error command
|
||||
stdout, stderr, err = system.ExecCommand("abc")
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import (
|
||||
- [IsCreditCard](#IsCreditCard)
|
||||
- [IsDns](#IsDns)
|
||||
- [IsEmail](#IsEmail)
|
||||
|
||||
- [IsEmptyString](#IsEmptyString)
|
||||
- [IsFloatStr](#IsFloatStr)
|
||||
- [IsNumberStr](#IsNumberStr)
|
||||
@@ -48,6 +47,7 @@ import (
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -822,7 +822,34 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsGBK">IsGBK</span>
|
||||
<p>Checks if data encoding is gbk(Chinese character internal code extension specification). this function is implemented by whether double bytes fall within the encoding range of gbk,while each byte of utf-8 encoding format falls within the encoding range of gbk.Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding and then call IsGBK() to check gbk encoding. like the example.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsGBK(data []byte) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("你好")
|
||||
|
||||
// check utf8 first
|
||||
if utf8.Valid(data) {
|
||||
fmt.Println("data encoding is utf-8")
|
||||
}else if(validator.IsGBK(data)) {
|
||||
fmt.Println("data encoding is GBK")
|
||||
}
|
||||
fmt.Println("data encoding is unknown")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import (
|
||||
- [IsCreditCard](#IsCreditCard)
|
||||
- [IsDns](#IsDns)
|
||||
- [IsEmail](#IsEmail)
|
||||
|
||||
- [IsEmptyString](#IsEmptyString)
|
||||
- [IsFloatStr](#IsFloatStr)
|
||||
- [IsNumberStr](#IsNumberStr)
|
||||
@@ -48,6 +47,7 @@ import (
|
||||
- [IsUrl](#IsUrl)
|
||||
- [IsWeakPassword](#IsWeakPassword)
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -459,8 +459,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmptyString">IsEmptyString</span>
|
||||
<p>验证字符串是否是空字符串</p>
|
||||
|
||||
@@ -488,7 +486,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
<p>验证字符串是否是可以转换为浮点数</p>
|
||||
|
||||
@@ -574,8 +571,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsRegexMatch">IsRegexMatch</span>
|
||||
<p>验证字符串是否可以匹配正则表达式</p>
|
||||
|
||||
@@ -601,7 +596,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
|
||||
@@ -821,3 +815,31 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsGBK">IsGBK</span>
|
||||
<p>检查数据编码是否为gbk(汉字内部代码扩展规范)。该函数的实现取决于双字节是否在gbk的编码范围内,而utf-8编码格式的每个字节都在gbk编码范围内。因此,应该首先调用utf8.valid检查它是否是utf-8编码,然后调用IsGBK检查gbk编码。如示例所示。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsGBK(data []byte) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("你好")
|
||||
|
||||
// 先检查utf8编码
|
||||
if utf8.Valid(data) {
|
||||
fmt.Println("data encoding is utf-8")
|
||||
}else if(validator.IsGBK(data)) {
|
||||
fmt.Println("data encoding is GBK")
|
||||
}
|
||||
fmt.Println("data encoding is unknown")
|
||||
}
|
||||
```
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsExist checks if a file or directory exists
|
||||
// IsExist checks if a file or directory exists.
|
||||
// Play: https://go.dev/play/p/nKKXt8ZQbmh
|
||||
func IsExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@@ -30,7 +31,8 @@ func IsExist(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CreateFile create a file in path
|
||||
// CreateFile create a file in path.
|
||||
// Play: https://go.dev/play/p/lDt8PEsTNKI
|
||||
func CreateFile(path string) bool {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -41,12 +43,14 @@ func CreateFile(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/.
|
||||
// Play: https://go.dev/play/p/qUuCe1OGQnM
|
||||
func CreateDir(absPath string) error {
|
||||
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
|
||||
}
|
||||
|
||||
// IsDir checks if the path is directory or not
|
||||
// IsDir checks if the path is directory or not.
|
||||
// Play: https://go.dev/play/p/WkVwEKqtOWk
|
||||
func IsDir(path string) bool {
|
||||
file, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@@ -55,12 +59,14 @@ func IsDir(path string) bool {
|
||||
return file.IsDir()
|
||||
}
|
||||
|
||||
// RemoveFile remove the path file
|
||||
// RemoveFile remove the path file.
|
||||
// Play: https://go.dev/play/p/P2y0XW8a1SH
|
||||
func RemoveFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// CopyFile copy src file to dest file
|
||||
// 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)
|
||||
if err != nil {
|
||||
@@ -77,17 +83,21 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
var tmp = make([]byte, 1024*4)
|
||||
for {
|
||||
n, err := srcFile.Read(tmp)
|
||||
distFile.Write(tmp[:n])
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
_, err = distFile.Write(tmp[:n])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ClearFile write empty string to path file
|
||||
// ClearFile write empty string to path file.
|
||||
// Play: https://go.dev/play/p/NRZ0ZT-G94H
|
||||
func ClearFile(path string) error {
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
@@ -99,16 +109,18 @@ func ClearFile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
//ReadFileToString return string of file content
|
||||
// ReadFileToString return string of file content.
|
||||
// Play: https://go.dev/play/p/cmfwp_5SQTp
|
||||
func ReadFileToString(path string) (string, error) {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// ReadFileByLine read file line by line
|
||||
// ReadFileByLine read file line by line.
|
||||
// Play: https://go.dev/play/p/svJP_7ZrBrD
|
||||
func ReadFileByLine(path string) ([]string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -134,13 +146,14 @@ func ReadFileByLine(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ListFileNames return all file names in the path
|
||||
// ListFileNames return all file names in the path.
|
||||
// Play: https://go.dev/play/p/Tjd7Y07rejl
|
||||
func ListFileNames(path string) ([]string, error) {
|
||||
if !IsExist(path) {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
fs, err := ioutil.ReadDir(path)
|
||||
fs, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
@@ -160,7 +173,8 @@ func ListFileNames(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory
|
||||
// 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 {
|
||||
zipFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
@@ -171,7 +185,7 @@ func Zip(fpath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -208,11 +222,17 @@ func Zip(fpath string, destPath string) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath
|
||||
// UnZip unzip the file and save it to destPath.
|
||||
// Play: https://go.dev/play/p/g0w34kS7B8m
|
||||
func UnZip(zipFile string, destPath string) error {
|
||||
|
||||
zipReader, err := zip.OpenReader(zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -220,11 +240,20 @@ func UnZip(zipFile string, destPath string) error {
|
||||
defer zipReader.Close()
|
||||
|
||||
for _, f := range zipReader.File {
|
||||
path := filepath.Join(destPath, f.Name)
|
||||
//issue#62: fix ZipSlip bug
|
||||
path, err := safeFilepathJoin(destPath, f.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(path, os.ModePerm)
|
||||
err = os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -249,7 +278,19 @@ func UnZip(zipFile string, destPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsLink checks if a file is symbol link or not
|
||||
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
relPath, err := filepath.Rel(".", path2)
|
||||
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||
return "", fmt.Errorf("(zipslip) filepath is unsafe %q: %v", path2, err)
|
||||
}
|
||||
if path1 == "" {
|
||||
path1 = "."
|
||||
}
|
||||
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
||||
}
|
||||
|
||||
// IsLink checks if a file is symbol link or not.
|
||||
// Play: https://go.dev/play/p/TL-b-Kzvf44
|
||||
func IsLink(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -258,7 +299,8 @@ func IsLink(path string) bool {
|
||||
return fi.Mode()&os.ModeSymlink != 0
|
||||
}
|
||||
|
||||
// FileMode return file's mode and permission
|
||||
// FileMode return file's mode and permission.
|
||||
// Play: https://go.dev/play/p/2l2hI42fA3p
|
||||
func FileMode(path string) (fs.FileMode, error) {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -268,7 +310,8 @@ func FileMode(path string) (fs.FileMode, error) {
|
||||
}
|
||||
|
||||
// MiMeType return file mime type
|
||||
// param `file` should be string(file path) or *os.File
|
||||
// param `file` should be string(file path) or *os.File.
|
||||
// Play: https://go.dev/play/p/bd5sevSUZNu
|
||||
func MiMeType(file any) string {
|
||||
var mediatype string
|
||||
|
||||
|
||||
225
fileutil/file_example_test.go
Normal file
225
fileutil/file_example_test.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ExampleIsExist() {
|
||||
|
||||
result1 := IsExist("./")
|
||||
result2 := IsExist("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleCreateFile() {
|
||||
fname := "./test.txt"
|
||||
|
||||
result1 := IsExist(fname)
|
||||
|
||||
CreateFile(fname)
|
||||
|
||||
result2 := IsExist(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleCreateDir() {
|
||||
pwd, _ := os.Getwd()
|
||||
dirPath := pwd + "/test_xxx/"
|
||||
|
||||
result1 := IsExist(dirPath)
|
||||
|
||||
err := CreateDir(dirPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result2 := IsExist(dirPath)
|
||||
|
||||
os.Remove(dirPath)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsDir() {
|
||||
|
||||
result1 := IsDir("./")
|
||||
result2 := IsDir("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleRemoveFile() {
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
copyFile := "./text_copy.txt"
|
||||
err := CopyFile(srcFile, copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file, err := os.Open(copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result1 := IsExist(copyFile)
|
||||
result2 := file.Name()
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(copyFile)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// ./text_copy.txt
|
||||
}
|
||||
|
||||
func ExampleReadFileToString() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleClearFile() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content1, _ := ReadFileToString(fname)
|
||||
|
||||
err = ClearFile(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content2, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content1)
|
||||
fmt.Println(content2)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleReadFileByLine() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileByLine(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [hello world]
|
||||
}
|
||||
|
||||
func ExampleListFileNames() {
|
||||
fileList, _ := ListFileNames("./")
|
||||
fmt.Println(fileList)
|
||||
|
||||
// Output:
|
||||
// [file.go file_example_test.go file_test.go]
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
zipFile := "./test.zip"
|
||||
err := Zip(srcFile, zipFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result := IsExist(zipFile)
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
@@ -25,9 +25,10 @@ func TestCreateFile(t *testing.T) {
|
||||
f := "./text.txt"
|
||||
if CreateFile(f) {
|
||||
file, err := os.Open(f)
|
||||
defer file.Close()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(f, file.Name())
|
||||
|
||||
defer file.Close()
|
||||
} else {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -113,7 +114,11 @@ func TestReadFileToString(t *testing.T) {
|
||||
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
f.WriteString("hello world")
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(path)
|
||||
assert.Equal("hello world", content)
|
||||
@@ -130,9 +135,12 @@ func TestClearFile(t *testing.T) {
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
f.WriteString("hello world")
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
err := ClearFile(path)
|
||||
err = ClearFile(path)
|
||||
assert.IsNil(err)
|
||||
|
||||
content, _ := ReadFileToString(path)
|
||||
@@ -148,8 +156,13 @@ func TestReadFileByLine(t *testing.T) {
|
||||
CreateFile(path)
|
||||
|
||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
|
||||
defer f.Close()
|
||||
f.WriteString("hello\nworld")
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
expected := []string{"hello", "world"}
|
||||
actual, _ := ReadFileByLine(path)
|
||||
@@ -166,10 +179,14 @@ func TestZipAndUnZip(t *testing.T) {
|
||||
|
||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer file.Close()
|
||||
file.WriteString("hello\nworld")
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
zipFile := "./text.zip"
|
||||
err := Zip(srcFile, zipFile)
|
||||
err = Zip(srcFile, zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
|
||||
@@ -4,14 +4,68 @@
|
||||
// Package formatter implements some functions to format string, struct.
|
||||
package formatter
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
||||
// if value is invalid number string eg "aa", return empty string
|
||||
// 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 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
||||
func Comma(v any, symbol string) string {
|
||||
s := numString(v)
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return symbol + commaString(s)
|
||||
}
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
18
formatter/formatter_example_test.go
Normal file
18
formatter/formatter_example_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package formatter
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleComma() {
|
||||
result1 := Comma("123", "")
|
||||
result2 := Comma("12345", "$")
|
||||
result3 := Comma(1234567, "¥")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
func numString(value any) string {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value)
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -12,12 +12,16 @@ func TestComma(t *testing.T) {
|
||||
assert.Equal("", Comma("", ""))
|
||||
assert.Equal("", Comma("aa", ""))
|
||||
assert.Equal("", Comma("aa.a", ""))
|
||||
assert.Equal("", Comma([]int{1}, ""))
|
||||
assert.Equal("123", Comma("123", ""))
|
||||
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", 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("123,456,789,000", Comma(123456789000, ""))
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// After creates a function that invokes func once it's called n or more times
|
||||
// After creates a function that invokes func once it's called n or more times.
|
||||
// Play: https://go.dev/play/p/8mQhkFmsgqs
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -23,7 +25,8 @@ func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Before creates a function that invokes func once it's called less than n times
|
||||
// Before creates a function that invokes func once it's called less than n times.
|
||||
// Play: https://go.dev/play/p/0HqUDIFZ3IL
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -40,41 +43,48 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Fn is for curry function which is func(...any) any
|
||||
type Fn func(...any) any
|
||||
// CurryFn is for make curry function
|
||||
type CurryFn[T any] func(...T) T
|
||||
|
||||
// Curry make a curry function
|
||||
func (f Fn) Curry(i any) func(...any) any {
|
||||
return func(values ...any) any {
|
||||
v := append([]any{i}, values...)
|
||||
return f(v...)
|
||||
// New make a curry function for specific value.
|
||||
// Play: Todo
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T {
|
||||
return func(vals ...T) T {
|
||||
args := append([]T{val}, vals...)
|
||||
return cf(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Compose compose the functions from right to left
|
||||
func Compose(fnList ...func(...any) any) func(...any) any {
|
||||
return func(s ...any) any {
|
||||
f := fnList[0]
|
||||
restFn := fnList[1:]
|
||||
// Compose compose the functions from right to left.
|
||||
// Play: Todo
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T {
|
||||
return func(args ...T) T {
|
||||
firstFn := fnList[0]
|
||||
restFns := fnList[1:]
|
||||
|
||||
if len(fnList) == 1 {
|
||||
return f(s...)
|
||||
return firstFn(args...)
|
||||
}
|
||||
|
||||
return f(Compose(restFn...)(s...))
|
||||
fn := Compose(restFns...)
|
||||
arg := fn(args...)
|
||||
|
||||
return firstFn(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Delay make the function execution after delayed time
|
||||
// Delay make the function execution after delayed time.
|
||||
// Play: https://go.dev/play/p/Ivtc2ZE-Tye
|
||||
func Delay(delay time.Duration, fn any, args ...any) {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
time.Sleep(delay)
|
||||
invokeFunc(fn, args...)
|
||||
unsafeInvokeFunc(fn, args...)
|
||||
}
|
||||
|
||||
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||
// Play: https://go.dev/play/p/absuEGB_GN7
|
||||
func Debounced(fn func(), duration time.Duration) func() {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -84,17 +94,16 @@ func Debounced(fn func(), duration time.Duration) func() {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
go fn()
|
||||
}
|
||||
<-timer.C
|
||||
go fn()
|
||||
}
|
||||
}()
|
||||
|
||||
return func() { timer.Reset(duration) }
|
||||
}
|
||||
|
||||
// Schedule invoke function every duration time, util close the returned bool chan
|
||||
// Schedule invoke function every duration time, util close the returned bool channel.
|
||||
// Play: https://go.dev/play/p/hbON-Xeyn5N
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -116,6 +125,7 @@ func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
|
||||
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
// the functions one by one.
|
||||
// Play: https://go.dev/play/p/mPdUVvj6HD6
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return func(arg T) (result T) {
|
||||
result = arg
|
||||
@@ -125,3 +135,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
|
||||
147
function/function_example_test.go
Normal file
147
function/function_example_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleAfter() {
|
||||
fn := After(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleBefore() {
|
||||
fn := Before(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleCurryFn_New() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleCompose() {
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
|
||||
func ExampleDelay() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDebounced() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := Debounced(add, 50*time.Microsecond)
|
||||
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleSchedule() {
|
||||
var result []string
|
||||
|
||||
appendFn := func(s string) {
|
||||
result = append(result, s)
|
||||
}
|
||||
|
||||
stop := Schedule(1*time.Second, appendFn, "*")
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [* * *]
|
||||
}
|
||||
|
||||
func ExamplePipeline() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func invokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := functionValue(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
@@ -62,24 +62,26 @@ func TestCurry(t *testing.T) {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
assert.Equal(3, add1(2))
|
||||
}
|
||||
|
||||
func TestCompose(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCompose")
|
||||
|
||||
toUpper := func(a ...any) any {
|
||||
return strings.ToUpper(a[0].(string))
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(a ...any) any {
|
||||
return strings.ToLower(a[0].(string))
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
|
||||
expected := toUpper(toLower("aBCde"))
|
||||
|
||||
cf := Compose(toUpper, toLower)
|
||||
res := cf("aBCde")
|
||||
|
||||
|
||||
@@ -3,12 +3,18 @@ package function
|
||||
import "time"
|
||||
|
||||
// Watcher is used for record code excution time
|
||||
// Play: Todo
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func NewWatcher() *Watcher {
|
||||
return &Watcher{}
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func (w *Watcher) Start() {
|
||||
w.startTime = time.Now().UnixNano()
|
||||
|
||||
22
function/watcher_example_test.go
Normal file
22
function/watcher_example_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package function
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleWatcher() {
|
||||
w := NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
w.Stop()
|
||||
|
||||
// eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println("foo")
|
||||
|
||||
w.Reset()
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func TestWatcher(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWatcher")
|
||||
|
||||
w := &Watcher{}
|
||||
w := NewWatcher()
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
||||
module github.com/duke-git/lancet/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
|
||||
golang.org/x/text v0.5.0
|
||||
)
|
||||
|
||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
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=
|
||||
207
iterator/iterator.go
Normal file
207
iterator/iterator.go
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Iterator supports iterating over a sequence of values of type `E`.
|
||||
type Iterator[T any] interface {
|
||||
// Next checks if there is a next value in the iteration or not
|
||||
HasNext() bool
|
||||
// Next returns the next value in the iteration if there is one,
|
||||
// and reports whether the returned value is valid.
|
||||
// Once Next returns ok==false, the iteration is over,
|
||||
// and all subsequent calls will return ok==false.
|
||||
Next() (item T, ok bool)
|
||||
}
|
||||
|
||||
// StopIterator is an interface for stopping Iterator.
|
||||
type StopIterator[T any] interface {
|
||||
Iterator[T]
|
||||
|
||||
// Stop indicates that the iterator will no longer be used.
|
||||
// After a call to Stop, future calls to Next may panic.
|
||||
// Stop may be called multiple times;
|
||||
// all calls after the first will have no effect.
|
||||
Stop()
|
||||
}
|
||||
|
||||
// DeleteIter is an Iter that implements a Delete method.
|
||||
type DeleteIterator[T any] interface {
|
||||
Iterator[T]
|
||||
|
||||
// Delete deletes the current iterator element;
|
||||
// that is, the one returned by the last call to Next.
|
||||
// Delete should panic if called before Next or after
|
||||
// Next returns false.
|
||||
Delete()
|
||||
}
|
||||
|
||||
// SetIterator is an Iter that implements a Set method.
|
||||
type SetIterator[T any] interface {
|
||||
Iterator[T]
|
||||
|
||||
// Set replaces the current iterator element with v.
|
||||
// Set should panic if called before Next or after
|
||||
// Next returns false.
|
||||
Set(v T)
|
||||
}
|
||||
|
||||
// PrevIterator is an iterator with a Prev method.
|
||||
type PrevIterator[T any] interface {
|
||||
Iterator[T]
|
||||
|
||||
// Prev moves the iterator to the previous position.
|
||||
// After calling Prev, Next will return the value at
|
||||
// that position in the container. For example, after
|
||||
// it.Next() returning (v, true)
|
||||
// it.Prev()
|
||||
// another call to it.Next will again return (v, true).
|
||||
// Calling Prev before calling Next may panic.
|
||||
// Calling Prev after Next returns false will move
|
||||
// to the last element, or, if there are no elements,
|
||||
// to the iterator's initial state.
|
||||
Prev()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions that create an Iterator from some other type. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FromSlice returns an iterator over a slice of data.
|
||||
func FromSlice[T any](slice []T) Iterator[T] {
|
||||
return &sliceIterator[T]{slice: slice, index: -1}
|
||||
}
|
||||
|
||||
func ToSlice[T any](iter Iterator[T]) []T {
|
||||
result := []T{}
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
result = append(result, item)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type sliceIterator[T any] struct {
|
||||
slice []T
|
||||
index int
|
||||
}
|
||||
|
||||
func (iter *sliceIterator[T]) HasNext() bool {
|
||||
return iter.index < len(iter.slice)-1
|
||||
}
|
||||
|
||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||
iter.index++
|
||||
|
||||
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||
|
||||
var item T
|
||||
if ok {
|
||||
item = iter.slice[iter.index]
|
||||
}
|
||||
|
||||
return item, ok
|
||||
}
|
||||
|
||||
// Prev implements PrevIterator.
|
||||
func (iter *sliceIterator[T]) Prev() {
|
||||
if iter.index == -1 {
|
||||
panic("Next function should be called Prev")
|
||||
}
|
||||
if iter.HasNext() {
|
||||
iter.index--
|
||||
} else {
|
||||
iter.index = len(iter.slice) - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Set implements SetIterator.
|
||||
func (iter *sliceIterator[T]) Set(value T) {
|
||||
if iter.index == -1 {
|
||||
panic("Next function should be called Set")
|
||||
}
|
||||
if iter.index >= len(iter.slice) || len(iter.slice) == 0 {
|
||||
panic("No element in current iterator")
|
||||
}
|
||||
iter.slice[iter.index] = value
|
||||
}
|
||||
|
||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) Iterator[T] {
|
||||
if end < start {
|
||||
panic("RangeIterator: start should be before end")
|
||||
} else if step <= 0 {
|
||||
panic("RangeIterator: step should be positive")
|
||||
}
|
||||
|
||||
return &rangeIterator[T]{start: start, end: end, step: step}
|
||||
}
|
||||
|
||||
type rangeIterator[T constraints.Integer | constraints.Float] struct {
|
||||
start, end, step T
|
||||
}
|
||||
|
||||
func (iter *rangeIterator[T]) HasNext() bool {
|
||||
return iter.start < iter.end
|
||||
}
|
||||
|
||||
func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||
if iter.start >= iter.end {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
num := iter.start
|
||||
iter.start += iter.step
|
||||
return num, true
|
||||
}
|
||||
|
||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||
func FromChannel[T any](channel <-chan T) Iterator[T] {
|
||||
return &channelIterator[T]{channel: channel}
|
||||
}
|
||||
|
||||
type channelIterator[T any] struct {
|
||||
channel <-chan T
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) Next() (T, bool) {
|
||||
item, ok := <-iter.channel
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) HasNext() bool {
|
||||
return len(iter.channel) == 0
|
||||
}
|
||||
|
||||
// ToChannel create a new goroutine to pull items from the channel iterator to the returned channel.
|
||||
func ToChannel[T any](ctx context.Context, iter Iterator[T], buffer int) <-chan T {
|
||||
result := make(chan T, buffer)
|
||||
|
||||
go func() {
|
||||
defer close(result)
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
select {
|
||||
case result <- item:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return result
|
||||
}
|
||||
103
iterator/iterator_test.go
Normal file
103
iterator/iterator_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator implements some feature of C++ STL iterators
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestSliceIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSliceIterator")
|
||||
|
||||
// HashNext
|
||||
t.Run("slice iterator HasNext: ", func(t *testing.T) {
|
||||
iter1 := FromSlice([]int{1, 2, 3, 4})
|
||||
for {
|
||||
item, _ := iter1.Next()
|
||||
|
||||
if item == 4 {
|
||||
assert.Equal(false, iter1.HasNext())
|
||||
break
|
||||
} else {
|
||||
assert.Equal(true, iter1.HasNext())
|
||||
}
|
||||
}
|
||||
|
||||
iter2 := FromSlice([]int{})
|
||||
assert.Equal(false, iter2.HasNext())
|
||||
})
|
||||
|
||||
//Next
|
||||
t.Run("slice iterator Next: ", func(t *testing.T) {
|
||||
iter1 := FromSlice([]int{1, 2, 3, 4})
|
||||
for i := 0; i < 4; i++ {
|
||||
item, ok := iter1.Next()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
assert.Equal(i+1, item)
|
||||
}
|
||||
|
||||
iter2 := FromSlice([]int{})
|
||||
_, ok := iter2.Next()
|
||||
assert.Equal(false, ok)
|
||||
})
|
||||
|
||||
t.Run("slice iterator ToSlice: ", func(t *testing.T) {
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
item, _ := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
|
||||
data := ToSlice(iter)
|
||||
assert.Equal([]int{2, 3, 4}, data)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRangeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
t.Run("range iterator: ", func(t *testing.T) {
|
||||
iter := FromRange(1, 4, 1)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(2, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(3, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(false, iter.HasNext())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestChannelIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
iter = FromChannel(ToChannel(ctx, iter, 0))
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(true, iter.HasNext())
|
||||
|
||||
cancel()
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
139
iterator/operation.go
Normal file
139
iterator/operation.go
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
// Map creates a new iterator which applies a function to all items of input iterator.
|
||||
func Map[T any, U any](iter Iterator[T], iteratee func(item T) U) Iterator[U] {
|
||||
return &mapIterator[T, U]{
|
||||
iter: iter,
|
||||
iteratee: iteratee,
|
||||
}
|
||||
}
|
||||
|
||||
type mapIterator[T any, U any] struct {
|
||||
iter Iterator[T]
|
||||
iteratee func(T) U
|
||||
}
|
||||
|
||||
func (mr *mapIterator[T, U]) HasNext() bool {
|
||||
return mr.iter.HasNext()
|
||||
}
|
||||
|
||||
func (mr *mapIterator[T, U]) Next() (U, bool) {
|
||||
var zero U
|
||||
item, ok := mr.iter.Next()
|
||||
if !ok {
|
||||
return zero, false
|
||||
}
|
||||
return mr.iteratee(item), true
|
||||
}
|
||||
|
||||
// Filter creates a new iterator that returns only the items that pass specified predicate function.
|
||||
func Filter[T any](iter Iterator[T], predicateFunc func(item T) bool) Iterator[T] {
|
||||
return &filterIterator[T]{iter: iter, predicateFunc: predicateFunc}
|
||||
}
|
||||
|
||||
type filterIterator[T any] struct {
|
||||
iter Iterator[T]
|
||||
predicateFunc func(T) bool
|
||||
}
|
||||
|
||||
func (fr *filterIterator[T]) Next() (T, bool) {
|
||||
for item, ok := fr.iter.Next(); ok; item, ok = fr.iter.Next() {
|
||||
if fr.predicateFunc(item) {
|
||||
return item, true
|
||||
}
|
||||
}
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
|
||||
func (fr *filterIterator[T]) HasNext() bool {
|
||||
return fr.iter.HasNext()
|
||||
}
|
||||
|
||||
// Join creates an iterator that join all elements of iters[0], then all elements of iters[1] and so on.
|
||||
func Join[T any](iters ...Iterator[T]) Iterator[T] {
|
||||
return &joinIterator[T]{
|
||||
iters: iters,
|
||||
}
|
||||
}
|
||||
|
||||
type joinIterator[T any] struct {
|
||||
iters []Iterator[T]
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) Next() (T, bool) {
|
||||
for len(iter.iters) > 0 {
|
||||
item, ok := iter.iters[0].Next()
|
||||
if ok {
|
||||
return item, true
|
||||
}
|
||||
iter.iters = iter.iters[1:]
|
||||
}
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) HasNext() bool {
|
||||
if len(iter.iters) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(iter.iters) == 1 {
|
||||
return iter.iters[0].HasNext()
|
||||
}
|
||||
|
||||
result := iter.iters[0].HasNext()
|
||||
|
||||
for i := 1; i < len(iter.iters); i++ {
|
||||
it := iter.iters[i]
|
||||
hasNext := it.HasNext()
|
||||
result = result || hasNext
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Reduce reduces iter to a single value using the reduction function reducer
|
||||
func Reduce[T any, U any](iter Iterator[T], initial U, reducer func(U, T) U) U {
|
||||
acc := initial
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
acc = reducer(acc, item)
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func Take[T any](it Iterator[T], num int) Iterator[T] {
|
||||
return &takeIterator[T]{it: it, num: num}
|
||||
}
|
||||
|
||||
type takeIterator[T any] struct {
|
||||
it Iterator[T]
|
||||
num int
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) Next() (T, bool) {
|
||||
if iter.num <= 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
item, ok := iter.it.Next()
|
||||
if ok {
|
||||
iter.num--
|
||||
}
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) HasNext() bool {
|
||||
return iter.num > 0
|
||||
}
|
||||
73
iterator/operation_test.go
Normal file
73
iterator/operation_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestMapIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMapIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Map(iter, func(n int) int { return n / 2 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{0, 1, 1, 2}, result)
|
||||
}
|
||||
|
||||
func TestFilterIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFilterIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Filter(iter, func(n int) bool { return n < 3 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2}, result)
|
||||
}
|
||||
|
||||
func TestJoinIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestJoinIterator")
|
||||
|
||||
iter1 := FromSlice([]int{1, 2})
|
||||
iter2 := FromSlice([]int{3, 4})
|
||||
|
||||
iter := Join(iter1, iter2)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
assert.Equal([]int{2, 3, 4}, ToSlice(iter))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReduce")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
sum := Reduce(iter, 0, func(a, b int) int { return a + b })
|
||||
assert.Equal(10, sum)
|
||||
}
|
||||
|
||||
func TestTakeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTakeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
iter = Take(iter, 3)
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2, 3}, result)
|
||||
}
|
||||
@@ -11,8 +11,3 @@ type Comparator interface {
|
||||
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
||||
Compare(v1, v2 any) int
|
||||
}
|
||||
|
||||
// Number contains all types of number and uintptr, used for generics constraint
|
||||
type Number interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ package maputil
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Keys returns a slice of the map's keys
|
||||
// Keys returns a slice of the map's keys.
|
||||
// Play: https://go.dev/play/p/xNB5bTb97Wd
|
||||
func Keys[K comparable, V any](m map[K]V) []K {
|
||||
keys := make([]K, len(m))
|
||||
|
||||
@@ -19,7 +20,8 @@ func Keys[K comparable, V any](m map[K]V) []K {
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the map's values
|
||||
// Values returns a slice of the map's values.
|
||||
// Play: https://go.dev/play/p/CBKdUc5FTW6
|
||||
func Values[K comparable, V any](m map[K]V) []V {
|
||||
values := make([]V, len(m))
|
||||
|
||||
@@ -32,7 +34,8 @@ func Values[K comparable, V any](m map[K]V) []V {
|
||||
return values
|
||||
}
|
||||
|
||||
// Merge maps, next key will overwrite previous key
|
||||
// Merge maps, next key will overwrite previous key.
|
||||
// Play: https://go.dev/play/p/H95LENF1uB-
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
result := make(map[K]V, 0)
|
||||
|
||||
@@ -45,14 +48,16 @@ func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach executes iteratee funcation for every key and value pair in map
|
||||
// ForEach executes iteratee funcation for every key and value pair in map.
|
||||
// Play: https://go.dev/play/p/OaThj6iNVXK
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) {
|
||||
for k, v := range m {
|
||||
iteratee(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function.
|
||||
// Play: https://go.dev/play/p/fSvF3wxuNG7
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -64,7 +69,8 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
// Play: https://go.dev/play/p/Zld0oj3sjcC
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
if len(maps) == 0 {
|
||||
return map[K]V{}
|
||||
@@ -85,7 +91,7 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return m
|
||||
}
|
||||
|
||||
reduceMaps := make([]map[K]V, 2, 2)
|
||||
reduceMaps := make([]map[K]V, 2)
|
||||
result = reducer(maps[0], maps[1])
|
||||
|
||||
for i := 2; i < len(maps); i++ {
|
||||
@@ -97,7 +103,8 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// Minus creates an map of whose key in mapA but not in mapB
|
||||
// Minus creates a map of whose key in mapA but not in mapB.
|
||||
// Play: https://go.dev/play/p/3u5U9K7YZ9m
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -109,7 +116,8 @@ func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsDisjoint two map are disjoint if they have no keys in common
|
||||
// IsDisjoint two map are disjoint if they have no keys in common.
|
||||
// Play: https://go.dev/play/p/N9qgYg_Ho6f
|
||||
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool {
|
||||
for k := range mapA {
|
||||
if _, ok := mapB[k]; ok {
|
||||
|
||||
181
maputil/map_example_test.go
Normal file
181
maputil/map_example_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func ExampleKeys() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleValues() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [a a b c d]
|
||||
}
|
||||
|
||||
func ExampleMerge() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "c",
|
||||
3: "d",
|
||||
}
|
||||
|
||||
result := Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:c 2:b 3:d]
|
||||
}
|
||||
|
||||
func ExampleForEach() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
result := Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[b:2 d:4]
|
||||
}
|
||||
|
||||
func ExampleIntersect() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
result1 := Intersect(m1)
|
||||
result2 := Intersect(m1, m2)
|
||||
result3 := Intersect(m1, m2, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
// map[a:1 b:2]
|
||||
// map[a:1]
|
||||
}
|
||||
|
||||
func ExampleMinus() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
result := Minus(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[c:3]
|
||||
}
|
||||
|
||||
func ExampleIsDisjoint() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"d": 22,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 22,
|
||||
}
|
||||
|
||||
result1 := IsDisjoint(m1, m2)
|
||||
result2 := IsDisjoint(m1, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user