mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-23 13:52:26 +08:00
Compare commits
43 Commits
v2.2.7
...
38920e3be6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38920e3be6 | ||
|
|
a630a7cda9 | ||
|
|
66dfd9c4fd | ||
|
|
be62aaac9b | ||
|
|
e0c9ccbce3 | ||
|
|
d2d1e5a055 | ||
|
|
bbc58c7e46 | ||
|
|
ac2ecceaec | ||
|
|
a06bb8ee6a | ||
|
|
27b5702fd3 | ||
|
|
b2c3fa0ab8 | ||
|
|
4afc838937 | ||
|
|
3482f80d1c | ||
|
|
565f2893b9 | ||
|
|
1b1b10d0ee | ||
|
|
c5c3888ffc | ||
|
|
11214986cc | ||
|
|
0bc7b83e59 | ||
|
|
6225418074 | ||
|
|
ddd265de78 | ||
|
|
80e48f06ca | ||
|
|
0b976e9a4c | ||
|
|
96320069f4 | ||
|
|
c5297ec329 | ||
|
|
aa4b61ff85 | ||
|
|
7dbd7002a3 | ||
|
|
a995db445a | ||
|
|
6e5b67bee7 | ||
|
|
52b8ea8166 | ||
|
|
6fe8a9efe7 | ||
|
|
dcef06e9da | ||
|
|
8f410bf9cb | ||
|
|
9cd6eb4ddf | ||
|
|
bf581162ee | ||
|
|
bd984fa378 | ||
|
|
d7f23e2dee | ||
|
|
3802c715c3 | ||
|
|
4b12173f24 | ||
|
|
31c618c187 | ||
|
|
6497b321b0 | ||
|
|
bda78201f5 | ||
|
|
0753ea2801 | ||
|
|
e25b53712b |
130
README.md
130
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)
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
## <a href="https://www.golancet.cn/en/" target="_blank"> Website</a> | [简体中文](./README_zh-CN.md)
|
||||
|
||||
## Feature
|
||||
## Features
|
||||
|
||||
- 👏 Comprehensive, efficient and reusable.
|
||||
- 💪 600+ go util functions, support string, slice, datetime, net, crypt...
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
### Note:
|
||||
|
||||
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>
|
||||
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 were rewritten with generics of go1.18.</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
@@ -201,10 +201,10 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
||||
- **<big>OrDone</big>** : read a channel into another channel, will close until cancel context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#OrDone)]
|
||||
[[play](https://go.dev/play/p/lm_GoS6aDjo)]
|
||||
- **<big>Repeat</big>** : create channel, put values into the channel repeatly until cancel the context.
|
||||
- **<big>Repeat</big>** : create channel, put values into the channel repeatedly until cancel the context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#Repeat)]
|
||||
[[play](https://go.dev/play/p/k5N_ALVmYjE)]
|
||||
- **<big>RepeatFn</big>** : create a channel, excutes fn repeatly, and put the result into the channel, until close context.
|
||||
- **<big>RepeatFn</big>** : create a channel, executes fn repeatedly, and put the result into the channel, until close context.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/concurrency.md#RepeatFn)]
|
||||
[[play](https://go.dev/play/p/4J1zAWttP85)]
|
||||
- **<big>Take</big>** : create a channel whose values are taken from another channel with limit number.
|
||||
@@ -247,7 +247,7 @@ import "github.com/duke-git/lancet/v2/condition"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/condition.md#TernaryOperator)]
|
||||
[[play](https://go.dev/play/p/ElllPZY0guT)]
|
||||
|
||||
<h3 id="convertor"> 5. Convertor package contains some functions for data convertion. <a href="#index">index</a> </h3>
|
||||
<h3 id="convertor"> 5. Convertor package contains some functions for data conversion. <a href="#index">index</a> </h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
@@ -453,10 +453,14 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
- **<big>GenerateRsaKeyPair</big>** : creates rsa private and public key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
- **<big>RsaEncryptOAEP</big>** : encrypts the given data with RSA-OAEP.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaEncryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
- **<big>RsaDecryptOAEP</big>** : decrypts the data with RSA-OAEP
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
|
||||
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -592,7 +596,7 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#TimestampNano)]
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
|
||||
<h3 id="datastructure"> 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. <a href="#index">index</a></h3>
|
||||
<h3 id="datastructure"> 8. Datastructure package contains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. <a href="#index">index</a></h3>
|
||||
|
||||
```go
|
||||
import list "github.com/duke-git/lancet/v2/datastructure/list"
|
||||
@@ -702,6 +706,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
||||
- **<big>WriteCsvFile</big>** : write content to target csv file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteCsvFile)]
|
||||
- **<big>WriteMapsToCsv</big>** : write slice of map to csv file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteMapsToCsv)]
|
||||
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||
- **<big>WriteBytesToFile</big>** : write bytes to target file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#WriteBytesToFile)]
|
||||
@@ -750,10 +756,10 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>After</big>** : return a function that invokes passed funcation once the returned function is called more than n times.
|
||||
- **<big>After</big>** : return a function that invokes passed function once the returned function is called more than n times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/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
|
||||
- **<big>Before</big>** : return a function that invokes passed function once the returned function is called less than n times
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Before)]
|
||||
[[play](https://go.dev/play/p/0HqUDIFZ3IL)]
|
||||
- **<big>CurryFn</big>** : make a curry function.
|
||||
@@ -774,7 +780,7 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
- **<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/en/api/packages/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.
|
||||
- **<big>Watcher</big>** : Watcher is used for record code execution 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/en/api/packages/function.md#Watcher)]
|
||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||
|
||||
@@ -789,7 +795,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>MapTo</big>** : quick map any value to struct or any base type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#MapTo)]
|
||||
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
|
||||
- **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map.
|
||||
- **<big>ForEach</big>** : executes iteratee function for every key and value pair in map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/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.
|
||||
@@ -807,7 +813,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>OmitByKeys</big>** : the opposite of FilterByKeys, extracts all the map elements which keys are not omitted.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OmitByKeys)]
|
||||
[[play](https://go.dev/play/p/jXGrWDBfSRp)]
|
||||
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remov all elements whose value are in the give slice.
|
||||
- **<big>OmitByValues</big>** : the opposite of FilterByValues. remove all elements whose value are in the give slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OmitByValues)]
|
||||
[[play](https://go.dev/play/p/XB7Y10uw20_U)]
|
||||
- **<big>Intersect</big>** : iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
@@ -957,7 +963,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
- **<big>Sum</big>** : return sum of passed numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
|
||||
[[play](https://go.dev/play/p/1To2ImAMJA7)]
|
||||
- **<big>Abs</big>** : returns the absolute value of param nubmer.
|
||||
- **<big>Abs</big>** : returns the absolute value of param number.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
|
||||
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
|
||||
|
||||
@@ -1008,7 +1014,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
||||
- **<big>DecodeResponse</big>** : decode http response into target object.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#DecodeResponse)]
|
||||
[[play](https://go.dev/play/p/jUSgynekH7G)]
|
||||
- **<big>StructToUrlValues</big>** : convert struct to url valuse.
|
||||
- **<big>StructToUrlValues</big>** : convert struct to url values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#StructToUrlValues)]
|
||||
[[play](https://go.dev/play/p/pFqMkM40w9z)]
|
||||
- **<big>HttpGet<sup>deprecated</sup></big>** : send http get request.
|
||||
@@ -1093,6 +1099,18 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandUniqueIntSlice</big>** : generate a slice of random int of length n that do not repeat.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
- **<big>RandSymbolChar</big>** : Generate a random symbol char of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandSymbolChar)]
|
||||
[[play](https://go.dev/play/p/Im6ZJxAykOm)]
|
||||
|
||||
- **<big>RandFloat</big>** : Generate a random float64 number between [min, max) with specific precision.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFloat)]
|
||||
[[play](https://go.dev/play/p/zbD_tuobJtr)]
|
||||
|
||||
- **<big>RandFloats</big>** : Generate a slice of random float64 numbers of length n that do not repeat.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFloats)]
|
||||
[[play](https://go.dev/play/p/I3yndUQ-rhh)]
|
||||
|
||||
|
||||
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1141,7 +1159,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<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/en/api/packages/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.
|
||||
- **<big>Compact</big>** : creates an slice with all falsy values removed. The values false, nil, 0, and "" are falsy.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Compact)]
|
||||
[[play](https://go.dev/play/p/pO5AnxEr3TK)]
|
||||
- **<big>Concat</big>** : creates a new slice concatenating slice with any additional slices.
|
||||
@@ -1162,9 +1180,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<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/en/api/packages/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.
|
||||
- **<big>DeleteAt</big>** : delete the element of slice at index.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>DeleteRange</big>** : delete the element of slice from start index to end index(exclude).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#DeleteRange)]
|
||||
- **<big>Drop</big>** : drop n elements from the start of a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Drop)]
|
||||
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
||||
@@ -1222,7 +1241,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<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/en/api/packages/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.
|
||||
- **<big>GroupWith</big>** : return a map composed of keys generated from the results of running each element of slice thru iteratee.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#GroupWith)]
|
||||
[[play](https://go.dev/play/p/ApCvMNTLO8a)]
|
||||
- **<big>IntSlice<sup>deprecated</sup></big>** : convert param to int slice.
|
||||
@@ -1336,6 +1355,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Partition</big>** : partition all slice elements with the evaluation of the given predicate functions.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Partition)]
|
||||
[[play](https://go.dev/play/p/lkQ3Ri2NQhV)]
|
||||
- **<big>Random</big>** : get a random item of slice, return its index, when slice is empty, return -1.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Random)]
|
||||
[[play](https://go.dev/play/p/UzpGQptWppw)]
|
||||
|
||||
|
||||
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1357,7 +1380,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>FromRange</big>** : creates a number stream from start to end. both start and end are included. [start, end]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FromRange)]
|
||||
[[play](https://go.dev/play/p/9Ex1-zcg-B-)]
|
||||
- **<big>Generate</big>** : creates a stream where each element is generated by the provided generater function.
|
||||
- **<big>Generate</big>** : creates a stream where each element is generated by the provided generator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Generate)]
|
||||
[[play](https://go.dev/play/p/rkOWL1yA3j9)]
|
||||
- **<big>Concat</big>** : creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
|
||||
@@ -1402,10 +1425,10 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>FindLast</big>** : returns the last element of this stream and true, or zero value and false if the stream is empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/WZD2rDAW-2h)]
|
||||
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less fuction: a > b
|
||||
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less function: a > b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Max)]
|
||||
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
|
||||
- **<big>Min</big>** : returns the minimum element of this stream according to the provided less function. less fuction: a < b
|
||||
- **<big>Min</big>** : returns the minimum element of this stream according to the provided less function. less function: a < b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Min)]
|
||||
[[play](https://go.dev/play/p/vZfIDgGNRe_0)]
|
||||
- **<big>AllMatch</big>** : returns whether all elements of this stream match the provided predicate.
|
||||
@@ -1433,29 +1456,31 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
#### Function list:
|
||||
|
||||
- **<big>New</big>** : creates a `Struct` instance.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#New)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#New)]
|
||||
- **<big>ToMap</big>** : converts a valid struct to a map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#ToMap)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#ToMap)]
|
||||
- **<big>Fields</big>** : get all fields of a given struct, that the fields are abstract struct field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#Fields)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Fields)]
|
||||
- **<big>IsStruct</big>** : check if the struct is valid.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/struct.md#IsStruct)]
|
||||
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Tag)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsStruct)]
|
||||
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Tag)]
|
||||
- **<big>Name</big>** : get the field name.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Name)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Name)]
|
||||
- **<big>Value</big>** : get the `Field` underlying value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Value)]
|
||||
- **<big>Kind</big>** : get the field's kind
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#Kind)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Value)]
|
||||
- **<big>Kind</big>** : get the field's kind.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#Kind)]
|
||||
- **<big>IsEmbedded</big>** : check if the field is an embedded field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsEmbedded)]
|
||||
- **<big>IsExported</big>** : check if the field is exporte
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsExported)]
|
||||
- **<big>IsZero</big>** : check if the field is zero value
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsZero)]
|
||||
- **<big>IsSlice</big>** : check if the field is a slice
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/structs/field.md#IsSlice)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsEmbedded)]
|
||||
- **<big>IsExported</big>** : check if the field is exported.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsExported)]
|
||||
- **<big>IsZero</big>** : check if the field is zero value.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsZero)]
|
||||
- **<big>IsSlice</big>** : check if the field is a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsSlice)]
|
||||
- **<big>IsTargetType</big>** : check if the field is target type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#IsTargetType)]
|
||||
|
||||
<h3 id="strutil"> 21. Strutil package contains some functions to manipulate string. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1553,6 +1578,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/6zXRH_c0Qd3)]
|
||||
- **<big>IsNotBlank</big>** : checks if a string is not whitespace or not empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#IsNotBlank)]
|
||||
[[play](https://go.dev/play/p/e_oJW0RAquA)]
|
||||
- **<big>HasPrefixAny</big>** : checks if a string starts with any of an array of specified strings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#HasPrefixAny)]
|
||||
[[play](https://go.dev/play/p/8UUTl2C5slo)]
|
||||
@@ -1623,7 +1649,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
|
||||
#### Function list:
|
||||
|
||||
- **<big>Tuple2</big>** : represents a 2 elemnets tuple.
|
||||
- **<big>Tuple2</big>** : represents a 2 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple2)]
|
||||
[[play](https://go.dev/play/p/3sHVqBQpLYN)]
|
||||
- **<big>Tuple2_Unbox</big>** : returns values in Tuple2.
|
||||
@@ -1635,7 +1661,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip2</big>** : create a group of slice from a slice of Tuple2.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip2)]
|
||||
[[play](https://go.dev/play/p/KBecr60feXb)]
|
||||
- **<big>Tuple3</big>** : represents a 3 elemnets tuple.
|
||||
- **<big>Tuple3</big>** : represents a 3 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple3)]
|
||||
[[play](https://go.dev/play/p/FtH2sdCLlCf)]
|
||||
- **<big>Tuple3_Unbox</big>** : returns values in Tuple3.
|
||||
@@ -1647,7 +1673,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip3</big>** : create a group of slice from a slice of Tuple3.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip3)]
|
||||
[[play](https://go.dev/play/p/bba4cpAa7KO)]
|
||||
- **<big>Tuple4</big>** : represents a 4 elemnets tuple.
|
||||
- **<big>Tuple4</big>** : represents a 4 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple4)]
|
||||
[[play](https://go.dev/play/p/D2EqDz096tk)]
|
||||
- **<big>Tuple4_Unbox</big>** : returns values in Tuple4.
|
||||
@@ -1659,7 +1685,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip4</big>** : create a group of slice from a slice of Tuple4.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip4)]
|
||||
[[play](https://go.dev/play/p/rb8z4gyYSRN)]
|
||||
- **<big>Tuple5</big>** : represents a 5 elemnets tuple.
|
||||
- **<big>Tuple5</big>** : represents a 5 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple5)]
|
||||
[[play](https://go.dev/play/p/2WndmVxPg-r)]
|
||||
- **<big>Tuple5_Unbox</big>** : returns values in Tuple4.
|
||||
@@ -1671,7 +1697,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip5</big>** : create a group of slice from a slice of Tuple5.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip5)]
|
||||
[[play](https://go.dev/play/p/gyl6vKfhqPb)]
|
||||
- **<big>Tuple6</big>** : represents a 6 elemnets tuple.
|
||||
- **<big>Tuple6</big>** : represents a 6 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple6)]
|
||||
[[play](https://go.dev/play/p/VjqcCwEJZbs)]
|
||||
- **<big>Tuple6_Unbox</big>** : returns values in Tuple6.
|
||||
@@ -1683,7 +1709,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip6</big>** : create a group of slice from a slice of Tuple6.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip6)]
|
||||
[[play](https://go.dev/play/p/l41XFqCyh5E)]
|
||||
- **<big>Tuple7</big>** : represents a 7 elemnets tuple.
|
||||
- **<big>Tuple7</big>** : represents a 7 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple7)]
|
||||
[[play](https://go.dev/play/p/dzAgv_Ezub9)]
|
||||
- **<big>Tuple7_Unbox</big>** : returns values in Tuple7.
|
||||
@@ -1695,7 +1721,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip7</big>** : create a group of slice from a slice of Tuple7.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip7)]
|
||||
[[play](https://go.dev/play/p/hws_P1Fr2j3)]
|
||||
- **<big>Tuple8</big>** : represents a 8 elemnets tuple.
|
||||
- **<big>Tuple8</big>** : represents a 8 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple8)]
|
||||
[[play](https://go.dev/play/p/YA9S0rz3dRz)]
|
||||
- **<big>Tuple8_Unbox</big>** : returns values in Tuple8.
|
||||
@@ -1707,7 +1733,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip8</big>** : create a group of slice from a slice of Tuple8.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip8)]
|
||||
[[play](https://go.dev/play/p/1SndOwGsZB4)]
|
||||
- **<big>Tuple9</big>** : represents a 9 elemnets tuple.
|
||||
- **<big>Tuple9</big>** : represents a 9 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple9)]
|
||||
[[play](https://go.dev/play/p/yS2NGGtZpQr)]
|
||||
- **<big>Tuple9_Unbox</big>** : returns values in Tuple9.
|
||||
@@ -1719,7 +1745,7 @@ import "github.com/duke-git/lancet/v2/tuple"
|
||||
- **<big>Unzip9</big>** : create a group of slice from a slice of Tuple9.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip9)]
|
||||
[[play](https://go.dev/play/p/91-BU_KURSA)]
|
||||
- **<big>Tuple10</big>** : represents a 10 elemnets tuple.
|
||||
- **<big>Tuple10</big>** : represents a 10 elements tuple.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Tuple10)]
|
||||
[[play](https://go.dev/play/p/799qqZg0hUv)]
|
||||
- **<big>Tuple10_Unbox</big>** : returns values in Tuple10.
|
||||
@@ -1851,19 +1877,19 @@ import "github.com/duke-git/lancet/v2/validator"
|
||||
- **<big>IsJWT</big>** : check if a give string is a valid JSON Web Token (JWT).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsJWT)]
|
||||
[[play](https://go.dev/play/p/R6Op7heJbKI)]
|
||||
- **<big>IsVisa</big>** : check if a give string is a valid visa card nubmer or not.
|
||||
- **<big>IsVisa</big>** : check if a give string is a valid visa card number or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsVisa)]
|
||||
[[play](https://go.dev/play/p/SdS2keOyJsl)]
|
||||
- **<big>IsMasterCard</big>** : check if a give string is a valid master card nubmer or not.
|
||||
- **<big>IsMasterCard</big>** : check if a give string is a valid master card number or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsMasterCard)]
|
||||
[[play](https://go.dev/play/p/CwWBFRrG27b)]
|
||||
- **<big>IsAmericanExpress</big>** : check if a give string is a valid american expression card nubmer or not.
|
||||
- **<big>IsAmericanExpress</big>** : check if a give string is a valid american expression card number or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsAmericanExpress)]
|
||||
[[play](https://go.dev/play/p/HIDFpcOdpkd)]
|
||||
- **<big>IsUnionPay</big>** : check if a give string is a valid union pay nubmer or not.
|
||||
- **<big>IsUnionPay</big>** : check if a give string is a valid union pay number or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsUnionPay)]
|
||||
[[play](https://go.dev/play/p/CUHPEwEITDf)]
|
||||
- **<big>IsChinaUnionPay</big>** : check if a give string is a valid china union pay nubmer or not.
|
||||
- **<big>IsChinaUnionPay</big>** : check if a give string is a valid china union pay number or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsChinaUnionPay)]
|
||||
[[play](https://go.dev/play/p/yafpdxLiymu)]
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -453,10 +453,14 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/uef0q1fz53I)]
|
||||
- **<big>GenerateRsaKeyPair</big>** : 创建rsa公钥私钥和key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateRsaKeyPair)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
- **<big>RsaEncryptOAEP</big>** : rsa OAEP加密。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaEncryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
- **<big>RsaDecryptOAEP</big>** : rsa OAEP解密。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaDecryptOAEP)]
|
||||
[[play](https://go.dev/play/p/sSVmkfENKMz)]
|
||||
|
||||
|
||||
<h3 id="datetime"> 7. datetime 日期时间处理包,格式化日期,比较日期。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -568,9 +572,6 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>IsLeapYear</big>** :验证是否是闰年。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#IsLeapYear)]
|
||||
[[play](https://go.dev/play/p/xS1eS2ejGew)]
|
||||
- **<big>IsLeapYear</big>** : check if param `year` is leap year or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#IsLeapYear)]
|
||||
[[play](https://go.dev/play/p/xS1eS2ejGew)]
|
||||
- **<big>BetweenSeconds</big>** : 返回两个时间的间隔秒数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#BetweenSeconds)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#BetweenSeconds)]
|
||||
@@ -704,8 +705,10 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadCsvFile)]
|
||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
||||
- **<big>WriteCsvFile</big>** : 向 csv 文件写入内容。
|
||||
- **<big>WriteCsvFile</big>** : 向csv文件写入切片数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteCsvFile)]
|
||||
- **<big>WriteMapsToCsv</big>** : 将map切片写入csv文件中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteMapsToCsv)]
|
||||
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#WriteBytesToFile)]
|
||||
@@ -1097,6 +1100,16 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>RandUniqueIntSlice</big>** : 生成一个不重复的长度为 n 的随机 int 切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
- **<big>RandSymbolChar</big>** : 生成给定长度的随机符号字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandSymbolChar)]
|
||||
[[play](https://go.dev/play/p/Im6ZJxAykOm)]
|
||||
- **<big>RandFloat</big>** : 生成随机float64数字,可以指定范围和精度。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFloat)]
|
||||
[[play](https://go.dev/play/p/zbD_tuobJtr)]
|
||||
- **<big>RandFloats</big>** : 生成随机float64数字切片,可以指定长度,范围和精度.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFloats)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
|
||||
|
||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1122,7 +1135,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
|
||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||
|
||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 [回到目录](#index)
|
||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
@@ -1166,9 +1179,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>DifferenceWith</big>** : 接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DifferenceWith)]
|
||||
[[play](https://go.dev/play/p/v2U2deugKuV)]
|
||||
- **<big>DeleteAt</big>** : 删除切片中指定开始索引到结束索引的元素。
|
||||
- **<big>DeleteAt</big>** : 删除切片中指定索引到的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DeleteAt)]
|
||||
[[play](https://go.dev/play/p/pJ-d6MUWcvK)]
|
||||
- **<big>DeleteRange</big>** : 删除切片中指定开始索引到结束索引的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#DeleteRange)]
|
||||
- **<big>Drop</big>** : 从切片头部删除 n 个元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Drop)]
|
||||
[[play](https://go.dev/play/p/jnPO2yQsT8H)]
|
||||
@@ -1331,7 +1345,6 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Without</big>** : 创建一个不包括所有给定值的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Without)]
|
||||
[[play](https://go.dev/play/p/bwhEXEypThg)]
|
||||
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为 map。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
- **<big>Join</big>** : 用指定的分隔符链接切片元素。
|
||||
@@ -1340,6 +1353,11 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
- **<big>Partition</big>** : 根据给定的predicate判断函数分组切片元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Partition)]
|
||||
[[play](https://go.dev/play/p/lkQ3Ri2NQhV)]
|
||||
- **<big>Random</big>** : 随机返回切片中元素以及下标, 当切片长度为0时返回下标-1。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Random)]
|
||||
[[play](https://go.dev/play/p/UzpGQptWppw)]
|
||||
|
||||
|
||||
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1437,31 +1455,33 @@ import "github.com/duke-git/lancet/v2/structs"
|
||||
#### 函数列表:
|
||||
|
||||
- **<big>New</big>** : `Struct`结构体的构造函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#New)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#New)]
|
||||
- **<big>ToMap</big>** : 将一个合法的 struct 对象转换为 map[string]any。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#ToMap)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#ToMap)]
|
||||
- **<big>Fields</big>** : 获取一个 struct 对象的属性列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#Fields)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Fields)]
|
||||
- **<big>Field</big>** : 根据属性名获取一个 struct 对象的属性。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#Fields)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Fields)]
|
||||
- **<big>IsStruct</big>** : 判断是否为一个合法的 struct 对象。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/struct.md#IsStruct)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsStruct)]
|
||||
- **<big>Tag</big>** : 获取`Field`的`Tag`,默认的 tag key 是 json。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Tag)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Tag)]
|
||||
- **<big>Name</big>** : 获取属性名。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Name)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Name)]
|
||||
- **<big>Value</big>** : 获取`Field`属性的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Value)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Value)]
|
||||
- **<big>Kind</big>** : 获取属性 Kind。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#Kind)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#Kind)]
|
||||
- **<big>IsEmbedded</big>** : 判断属性是否为嵌入。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsEmbedded)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsEmbedded)]
|
||||
- **<big>IsExported</big>** : 判断属性是否导出。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsExported)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsExported)]
|
||||
- **<big>IsZero</big>** : 判断属性是否为零值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsZero)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsZero)]
|
||||
- **<big>IsSlice</big>** : 判断属性是否是切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/structs/field.md#IsSlice)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsSlice)]
|
||||
- **<big>IsTargetType</big>** : 判断属性是否是目标类型。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#IsTargetType)]
|
||||
|
||||
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1560,6 +1580,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/6zXRH_c0Qd3)]
|
||||
- **<big>IsNotBlank</big>** : 检查字符串是否不为空。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#IsNotBlank)]
|
||||
[[play](https://go.dev/play/p/e_oJW0RAquA)]
|
||||
- **<big>HasPrefixAny</big>** : 检查字符串是否以指定字符串数组中的任何一个开头。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#HasPrefixAny)]
|
||||
[[play](https://go.dev/play/p/8UUTl2C5slo)]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// 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"
|
||||
import "github.com/duke-git/lancet/v2/constraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
@@ -23,7 +23,7 @@ func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||
// 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 {
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
||||
// 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 {
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
|
||||
@@ -3,24 +3,29 @@
|
||||
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
import "github.com/duke-git/lancet/v2/constraints"
|
||||
|
||||
// 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) {
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
breakTag := false
|
||||
for j := 0; j < len(slice)-1-i; j++ {
|
||||
isCurrGreatThanNext := comparator.Compare(slice[j], slice[j+1]) == 1
|
||||
if isCurrGreatThanNext {
|
||||
swap(slice, j, j+1)
|
||||
breakTag = true
|
||||
}
|
||||
}
|
||||
if !breakTag {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
|
||||
@@ -35,7 +40,7 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// 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) {
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
for j := i + 1; j < len(slice); j++ {
|
||||
@@ -49,7 +54,7 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// 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) {
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
gap := 1
|
||||
@@ -69,11 +74,11 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// 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) {
|
||||
func QuickSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
quickSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
|
||||
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
p := partition(slice, lowIndex, highIndex, comparator)
|
||||
quickSort(slice, lowIndex, p-1, comparator)
|
||||
@@ -82,7 +87,7 @@ func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
}
|
||||
|
||||
// partition split slice into two parts
|
||||
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
func partition[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
p := slice[highIndex]
|
||||
i := lowIndex
|
||||
for j := lowIndex; j < highIndex; j++ {
|
||||
@@ -99,7 +104,7 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
|
||||
// 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) {
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
for i := size/2 - 1; i >= 0; i-- {
|
||||
@@ -111,7 +116,7 @@ func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func sift[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := 2*i + 1
|
||||
|
||||
@@ -133,11 +138,11 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
||||
|
||||
// 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) {
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
|
||||
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
mid := (lowIndex + highIndex) / 2
|
||||
mergeSort(slice, lowIndex, mid, comparator)
|
||||
@@ -146,7 +151,7 @@ func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
}
|
||||
}
|
||||
|
||||
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator constraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := midIndex + 1
|
||||
temp := []T{}
|
||||
@@ -175,7 +180,7 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
|
||||
|
||||
// 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 {
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/v2/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
@@ -70,7 +70,7 @@ func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind)
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
||||
if bytes.Equal(bytesObj1, bytesObj2) {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package lancetconstraints contain some comstomer constraints.
|
||||
package lancetconstraints
|
||||
// Package constraints contain some custom interface.
|
||||
package constraints
|
||||
|
||||
// Comparator is for comparing two values
|
||||
type Comparator interface {
|
||||
@@ -508,14 +508,14 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
}
|
||||
|
||||
// GenerateRsaKeyPair create rsa private and public key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey) {
|
||||
privateKey, _ := rsa.GenerateKey(rand.Reader, keySize)
|
||||
return privateKey, &privateKey.PublicKey
|
||||
}
|
||||
|
||||
// RsaEncryptOAEP encrypts the given data with RSA-OAEP.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error) {
|
||||
encryptedBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &key, data, label)
|
||||
if err != nil {
|
||||
@@ -526,7 +526,7 @@ func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error
|
||||
}
|
||||
|
||||
// RsaDecryptOAEP decrypts the data with RSA-OAEP.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error) {
|
||||
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, &key, ciphertext, label)
|
||||
if err != nil {
|
||||
|
||||
@@ -7,18 +7,18 @@ package datastructure
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
)
|
||||
|
||||
// MaxHeap implements a binary max heap
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
// type T should implements Compare function in constraints.Comparator interface.
|
||||
type MaxHeap[T any] struct {
|
||||
data []T
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
// NewMaxHeap returns a MaxHeap instance with the given comparator.
|
||||
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T] {
|
||||
return &MaxHeap[T]{
|
||||
data: make([]T, 0),
|
||||
comparator: comparator,
|
||||
@@ -26,7 +26,7 @@ func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
}
|
||||
|
||||
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
|
||||
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
func BuildMaxHeap[T any](data []T, comparator constraints.Comparator) *MaxHeap[T] {
|
||||
heap := &MaxHeap[T]{
|
||||
data: make([]T, 0, len(data)),
|
||||
comparator: comparator,
|
||||
|
||||
@@ -8,20 +8,20 @@ package datastructure
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
)
|
||||
|
||||
// PriorityQueue is a priority queue implemented by binary heap tree
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
// type T should implements Compare function in constraints.Comparator interface.
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
// NewPriorityQueue return a pointer of PriorityQueue
|
||||
// param `comparator` is used to compare values in the queue
|
||||
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T] {
|
||||
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T] {
|
||||
return &PriorityQueue[T]{
|
||||
items: make([]T, capacity+1),
|
||||
size: 0,
|
||||
|
||||
@@ -7,22 +7,22 @@ package datastructure
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
// BSTree is a binary search tree data structure in which each node has at most two children,
|
||||
// which are referred to as the left child and the right child.
|
||||
// In BSTree: leftNode < rootNode < rightNode
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
// type T should implements Compare function in constraints.Comparator interface.
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
// NewBSTree create a BSTree pointer
|
||||
// param `comparator` is used to compare values in the tree
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T] {
|
||||
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T] {
|
||||
root := datastructure.NewTreeNode(rootData)
|
||||
return &BSTree[T]{root, comparator}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
|
||||
}
|
||||
|
||||
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
|
||||
comparator lancetconstraints.Comparator) bool {
|
||||
comparator constraints.Comparator) bool {
|
||||
result := false
|
||||
|
||||
if superTreeRoot != nil && subTreeRoot != nil {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
@@ -86,7 +86,7 @@ func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T)
|
||||
}
|
||||
}
|
||||
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator constraints.Comparator) {
|
||||
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
|
||||
if rootNode.Left == nil {
|
||||
rootNode.Left = newNode
|
||||
@@ -103,7 +103,7 @@ func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], compara
|
||||
}
|
||||
|
||||
// todo, delete root node failed
|
||||
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
|
||||
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator constraints.Comparator) *datastructure.TreeNode[T] {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -216,7 +216,7 @@ func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
|
||||
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
|
||||
}
|
||||
|
||||
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) bool {
|
||||
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator constraints.Comparator) bool {
|
||||
if subTreeRoot == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -381,3 +381,12 @@ func TimestampNano(timezone ...string) int64 {
|
||||
|
||||
return t.UnixNano()
|
||||
}
|
||||
|
||||
// TraceFuncTime: trace the func costed time,just call it at top of the func like `defer TraceFuncTime()()`
|
||||
func TraceFuncTime() func() {
|
||||
pre := time.Now()
|
||||
return func() {
|
||||
elapsed := time.Since(pre)
|
||||
fmt.Println("Costs Time:\t", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ import (
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
|
||||
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>冒泡排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
|
||||
@@ -91,12 +91,12 @@ func main() {
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
|
||||
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>插入排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
|
||||
@@ -117,7 +117,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
@@ -154,12 +154,12 @@ func main() {
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
|
||||
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>选择排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/oXovbkekayS)</span></b>
|
||||
@@ -202,12 +202,12 @@ func main() {
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
|
||||
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>希尔排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/3ibkszpJEu3)</span></b>
|
||||
@@ -250,12 +250,12 @@ func main() {
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
|
||||
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>快速排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
func QuickSort[T any](slice []T comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
|
||||
@@ -298,12 +298,12 @@ func main() {
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
|
||||
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>堆排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
|
||||
@@ -346,12 +346,12 @@ func main() {
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
|
||||
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>归并排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ydinn9YzUJn)</span></b>
|
||||
@@ -394,12 +394,12 @@ func main() {
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
|
||||
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>计数排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
|
||||
@@ -443,12 +443,12 @@ func main() {
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/t6MeGiUSN47)</span></b>
|
||||
@@ -494,12 +494,12 @@ func main() {
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
|
||||
|
||||
@@ -1437,7 +1437,7 @@ func main() {
|
||||
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
|
||||
```
|
||||
|
||||
<b>示例:></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1462,7 +1462,7 @@ func main() {
|
||||
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1505,7 +1505,7 @@ func main() {
|
||||
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -44,9 +44,9 @@ MaxHeap是通过slice实现的二叉堆树,根节点的key既大于等于左
|
||||
```go
|
||||
type MaxHeap[T any] struct {
|
||||
data []T
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
|
||||
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
|
||||
@@ -1100,12 +1100,12 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T]
|
||||
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T]
|
||||
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
## 文档
|
||||
|
||||
## 1. BSTree
|
||||
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现lancetconstraints.Comparator。
|
||||
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现constraints.Comparator。
|
||||
|
||||
### <span id="NewBSTree">NewBSTree</span>
|
||||
<p>返回BSTree指针实例</p>
|
||||
@@ -49,11 +49,11 @@ BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
|
||||
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T]
|
||||
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
type TreeNode[T any] struct {
|
||||
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||
- [WriteStringToFile](#WriteStringToFile)
|
||||
- [WriteBytesToFile](#WriteBytesToFile)
|
||||
- [ReadFile](#ReadFile)
|
||||
@@ -669,7 +670,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReadCsvFile(filepath string) ([][]string, error)
|
||||
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OExTkhGEd3_u)</span></b>
|
||||
@@ -701,7 +702,7 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dAXm58Q5U1o)</span></b>
|
||||
@@ -743,6 +744,59 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
|
||||
|
||||
<p>将map切片写入csv文件中。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
// filepath: CSV文件路径。
|
||||
// records: 写入文件的map切片。map值必须为基本类型。会以map键的字母顺序写入。
|
||||
// appendToExistingFile: 是否为追加写模式。
|
||||
// delimiter: CSV文件分割符。
|
||||
// headers: CSV文件表头顺序(需要与map key保持一致),不指定时按字母排序。
|
||||
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune, headers ...[]string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fpath := "./test.csv"
|
||||
fileutil.CreateFile(fpath)
|
||||
|
||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
records := []map[string]any{
|
||||
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||
}
|
||||
|
||||
headers := []string{"Name", "Age", "Gender"}
|
||||
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||
|
||||
<p>将bytes写入文件。</p>
|
||||
@@ -843,7 +897,7 @@ func main() {
|
||||
|
||||
### <span id="ReadFile">ReadFile</span>
|
||||
|
||||
<p>读取文件或者URL</p>
|
||||
<p>读取文件或者URL。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -851,7 +905,7 @@ func main() {
|
||||
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;"></span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -862,19 +916,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fn()
|
||||
reader, fn, err := fileutil.ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fn()
|
||||
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(dat))
|
||||
// Output:
|
||||
// User-agent: *
|
||||
// Disallow: /deny
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(dat))
|
||||
// Output:
|
||||
// User-agent: *
|
||||
// Disallow: /deny
|
||||
}
|
||||
```
|
||||
@@ -29,8 +29,11 @@ import (
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [RandSymbolChar](#RandSymbolChar)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
- [RandFloat](#RandFloat)
|
||||
- [RandFloats](#RandFloats)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -218,6 +221,32 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandSymbolChar">RandSymbolChar</span>
|
||||
|
||||
<p>生成给定长度的随机符号字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandSymbolChar(length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Im6ZJxAykOm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandSymbolChar(6)
|
||||
fmt.Println(randStr) // 随机特殊字符字符串,例如: @#(_")
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UUIdV4">UUIdV4</span>
|
||||
|
||||
<p>生成UUID v4字符串</p>
|
||||
@@ -272,3 +301,55 @@ func main() {
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloat">RandFloat</span>
|
||||
|
||||
<p>生成随机float64数字,可以指定范围和精度。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandFloat(min, max float64, precision int) float64
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zbD_tuobJtr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumber := random.RandFloat(1.0, 5.0, 2)
|
||||
fmt.Println(floatNumber) //2.14 (random number)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloats">RandFloats</span>
|
||||
|
||||
<p>生成随机float64数字切片,指定长度,范围和精度.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandFloats(n int, min, max float64, precision int) []float64
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/I3yndUQ-rhh)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumbers := random.RandFloats(5, 1.0, 5.0, 2)
|
||||
fmt.Println(floatNumber) //[3.42 3.99 1.3 2.38 4.23] (random)
|
||||
}
|
||||
```
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [DifferenceBy](#DifferenceBy)
|
||||
- [DifferenceWith](#DifferenceWith)
|
||||
- [DeleteAt](#DeleteAt)
|
||||
- [DeleteRange](#DeleteRange)
|
||||
- [Drop](#Drop)
|
||||
- [DropRight](#DropRight)
|
||||
- [DropWhile](#DropWhile)
|
||||
@@ -516,12 +517,12 @@ func main() {
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
|
||||
<p>删除切片中指定开始索引到结束索引的元素</p>
|
||||
<p>删除切片中指定索引的元素(不修改原切片)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DeleteAt[T any](slice []T, start int, end ...int)
|
||||
func DeleteAt[T any](slice []T, index int) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pJ-d6MUWcvK)</span></b>
|
||||
@@ -533,18 +534,66 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
|
||||
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
|
||||
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := slice.DeleteAt(chars, 0)
|
||||
result2 := slice.DeleteAt(chars, 4)
|
||||
result3 := slice.DeleteAt(chars, 5)
|
||||
result4 := slice.DeleteAt(chars, 6)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [c]
|
||||
// [b c d e]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DeleteRange">DeleteRange</span>
|
||||
|
||||
<p>删除切片中指定索引范围的元素(不修改原切片)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DeleteRange[T any](slice []T, start, end int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := DeleteRange(chars, 0, 0)
|
||||
result2 := DeleteRange(chars, 0, 1)
|
||||
result3 := DeleteRange(chars, 0, 3)
|
||||
result4 := DeleteRange(chars, 0, 4)
|
||||
result5 := DeleteRange(chars, 0, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c d e]
|
||||
// [b c d e]
|
||||
// [d e]
|
||||
// [e]
|
||||
// []
|
||||
|
||||
}
|
||||
```
|
||||
@@ -2475,17 +2524,48 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
result1 := slice.Partition(nums)
|
||||
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
|
||||
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
|
||||
result1 := slice.Partition(nums)
|
||||
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
|
||||
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [[1 2 3 4 5]]
|
||||
// [[2 4] [1 3 5]]
|
||||
// [[1 2] [3 4] [5]]
|
||||
// Output:
|
||||
// [[1 2 3 4 5]]
|
||||
// [[2 4] [1 3 5]]
|
||||
// [[1 2] [3 4] [5]]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Random">Random</span>
|
||||
|
||||
<p>随机返回切片中元素以及下标, 当切片长度为0时返回下标-1</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Random[T any](slice []T) (val T, idx int)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UzpGQptWppw)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
val, idx := slice.Random(nums)
|
||||
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
|
||||
fmt.Println("okk")
|
||||
}
|
||||
// Output:
|
||||
// okk
|
||||
}
|
||||
```
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
- [IsExported](#IsExported)
|
||||
- [IsZero](#IsZero)
|
||||
- [IsSlice](#IsSlice)
|
||||
- [IsTargetType](#IsTargetType)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -531,4 +532,45 @@ func main() {
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsTargetType">IsTargetType</span>
|
||||
|
||||
<p>判断属性是否是目标类型</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (f *Field) IsTargetType(targetType reflect.Kind) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(n.IsTargetType(reflect.String))
|
||||
fmt.Println(a.IsTargetType(reflect.Slice))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1080,13 +1080,13 @@ func main() {
|
||||
|
||||
<p>Checks if a string is not whitespace or not empty.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsNotBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/e_oJW0RAquA)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1095,11 +1095,11 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := IsNotBlank("")
|
||||
result2 := IsNotBlank(" ")
|
||||
result3 := IsNotBlank("\t\v\f\n")
|
||||
result4 := IsNotBlank(" 中文")
|
||||
result5 := IsNotBlank(" world ")
|
||||
result1 := strutil.IsNotBlank("")
|
||||
result2 := strutil.IsNotBlank(" ")
|
||||
result3 := strutil.IsNotBlank("\t\v\f\n")
|
||||
result4 := strutil.IsNotBlank(" 中文")
|
||||
result5 := strutil.IsNotBlank(" world ")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
@@ -43,12 +43,12 @@ import (
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
|
||||
@@ -91,12 +91,12 @@ func main() {
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
|
||||
@@ -117,7 +117,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
@@ -154,12 +154,12 @@ func main() {
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/oXovbkekayS)</span></b>
|
||||
@@ -202,12 +202,12 @@ func main() {
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/3ibkszpJEu3)</span></b>
|
||||
@@ -250,12 +250,12 @@ func main() {
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
func QuickSort[T any](slice []T comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
|
||||
@@ -298,12 +298,12 @@ func main() {
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
|
||||
@@ -346,12 +346,12 @@ func main() {
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ydinn9YzUJn)</span></b>
|
||||
@@ -394,12 +394,12 @@ func main() {
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
|
||||
@@ -448,7 +448,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/t6MeGiUSN47)</span></b>
|
||||
@@ -499,7 +499,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
|
||||
|
||||
@@ -1437,7 +1437,7 @@ func main() {
|
||||
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey)
|
||||
```
|
||||
|
||||
<b>Example:></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1462,7 +1462,7 @@ func main() {
|
||||
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1505,7 +1505,7 @@ func main() {
|
||||
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/sSVmkfENKMz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -44,9 +44,9 @@ MaxHeap is a binary heap tree implemented by slice, The key of the root node is
|
||||
```go
|
||||
type MaxHeap[T any] struct {
|
||||
data []T
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
|
||||
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
|
||||
@@ -1100,12 +1100,12 @@ Common queue implemented by slice.
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T]
|
||||
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T]
|
||||
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
## Documentation
|
||||
|
||||
## 1. BSTree
|
||||
BSTree is a binary search tree data structure in which each node has at two children, which are referred to as the left child and the right child. In BSTree: leftNode < rootNode < rightNode. Type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
BSTree is a binary search tree data structure in which each node has at two children, which are referred to as the left child and the right child. In BSTree: leftNode < rootNode < rightNode. Type T should implements Compare function in constraints.Comparator interface.
|
||||
|
||||
### <span id="NewBSTree">NewBSTree</span>
|
||||
<p>Make a BSTree pointer instance</p>
|
||||
@@ -49,11 +49,11 @@ BSTree is a binary search tree data structure in which each node has at two chil
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
|
||||
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T]
|
||||
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
type TreeNode[T any] struct {
|
||||
|
||||
@@ -45,6 +45,8 @@ import (
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||
- [WriteStringToFile](#WriteStringToFile)
|
||||
- [WriteBytesToFile](#WriteBytesToFile)
|
||||
- [ReadFile](#ReadFile)
|
||||
@@ -669,7 +671,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ReadCsvFile(filepath string) ([][]string, error)
|
||||
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/OExTkhGEd3_u)</span></b>
|
||||
@@ -701,7 +703,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dAXm58Q5U1o)</span></b>
|
||||
@@ -743,6 +745,59 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
|
||||
|
||||
<p>Write slice of map to csv file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
// filepath: path of the CSV file.
|
||||
// records: slice of maps to be written. the value of map should be basic type. The maps will be sorted by key in alphabeta order, then be written into csv file.
|
||||
// appendToExistingFile: If true, data will be appended to the file if it exists.
|
||||
// delimiter: Delimiter to use in the CSV file.
|
||||
// headers: order of the csv column headers, needs to be consistent with the key of the map.
|
||||
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune, headers ...[]string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fpath := "./test.csv"
|
||||
fileutil.CreateFile(fpath)
|
||||
|
||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
records := []map[string]any{
|
||||
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||
}
|
||||
|
||||
headers := []string{"Name", "Age", "Gender"}
|
||||
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||
|
||||
<p>Writes bytes to target file.</p>
|
||||
@@ -843,7 +898,7 @@ func main() {
|
||||
|
||||
### <span id="ReadFile">ReadFile</span>
|
||||
|
||||
<p>Read File/URL</p>
|
||||
<p>Read File or URL.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -851,7 +906,7 @@ func main() {
|
||||
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;"> </span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -862,19 +917,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
reader, fn, err := ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fn()
|
||||
reader, fn, err := fileutil.ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fn()
|
||||
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(dat))
|
||||
// Output:
|
||||
// User-agent: *
|
||||
// Disallow: /deny
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(dat))
|
||||
// Output:
|
||||
// User-agent: *
|
||||
// Disallow: /deny
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,8 +29,11 @@ import (
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [RandSymbolChar](#RandSymbolChar)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
- [RandFloat](#RandFloat)
|
||||
- [RandFloats](#RandFloats)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -218,6 +221,32 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandSymbolChar">RandSymbolChar</span>
|
||||
|
||||
<p>Generate a random symbol char of specified length.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandSymbolChar(length int) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Im6ZJxAykOm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandSymbolChar(6)
|
||||
fmt.Println(randStr) // random string like: @#(_")
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UUIdV4">UUIdV4</span>
|
||||
|
||||
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
|
||||
@@ -273,3 +302,55 @@ func main() {
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloat">RandFloat</span>
|
||||
|
||||
<p>Generate a random float64 number between [min, max) with specific precision.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandFloat(min, max float64, precision int) float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/zbD_tuobJtr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumber := random.RandFloat(1.0, 5.0, 2)
|
||||
fmt.Println(floatNumber) //2.14 (random number)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloats">RandFloats</span>
|
||||
|
||||
<p>Generate a slice of random float64 numbers of length n that do not repeat.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandFloats(n int, min, max float64, precision int) []float64
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/I3yndUQ-rhh)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumbers := random.RandFloats(5, 1.0, 5.0, 2)
|
||||
fmt.Println(floatNumbers) //[3.42 3.99 1.3 2.38 4.23] (random)
|
||||
}
|
||||
```
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [DifferenceBy](#DifferenceBy)
|
||||
- [DifferenceWith](#DifferenceWith)
|
||||
- [DeleteAt](#DeleteAt)
|
||||
- [DeleteRange](#DeleteRange)
|
||||
- [Drop](#Drop)
|
||||
- [DropRight](#DropRight)
|
||||
- [DropWhile](#DropWhile)
|
||||
@@ -515,12 +516,12 @@ func main() {
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
|
||||
<p>Delete the element of slice from start index to end index - 1.</p>
|
||||
<p>Delete delete the element of slice at index.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DeleteAt[T any](slice []T, start int, end ...int)
|
||||
func DeleteAt[T any](slice []T, index int)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/pJ-d6MUWcvK)</span></b>
|
||||
@@ -532,18 +533,66 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := slice.DeleteAt([]string{"a", "b", "c"}, -1)
|
||||
result2 := slice.DeleteAt([]string{"a", "b", "c"}, 0)
|
||||
result3 := slice.DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := slice.DeleteAt(chars, 0)
|
||||
result2 := slice.DeleteAt(chars, 4)
|
||||
result3 := slice.DeleteAt(chars, 5)
|
||||
result4 := slice.DeleteAt(chars, 6)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [c]
|
||||
// [b c d e]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DeleteRange">DeleteRange</span>
|
||||
|
||||
<p>Delete the element of slice from start index to end index(exclude)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DeleteRange[T any](slice []T, start, end int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := DeleteRange(chars, 0, 0)
|
||||
result2 := DeleteRange(chars, 0, 1)
|
||||
result3 := DeleteRange(chars, 0, 3)
|
||||
result4 := DeleteRange(chars, 0, 4)
|
||||
result5 := DeleteRange(chars, 0, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c d e]
|
||||
// [b c d e]
|
||||
// [d e]
|
||||
// [e]
|
||||
// []
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2473,17 +2522,47 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
result1 := slice.Partition(nums)
|
||||
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
|
||||
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
|
||||
result1 := slice.Partition(nums)
|
||||
result2 := slice.Partition(nums, func(n int) bool { return n%2 == 0 })
|
||||
result3 := slice.Partition(nums, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [[1 2 3 4 5]]
|
||||
// [[2 4] [1 3 5]]
|
||||
// [[1 2] [3 4] [5]]
|
||||
// Output:
|
||||
// [[1 2 3 4 5]]
|
||||
// [[2 4] [1 3 5]]
|
||||
// [[1 2] [3 4] [5]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Random">Random</span>
|
||||
|
||||
<p>Random get a random item of slice, return idx=-1 when slice is empty. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Random[T any](slice []T) (val T, idx int)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UzpGQptWppw)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
val, idx := slice.Random(nums)
|
||||
if idx >= 0 && idx < len(nums) && slice.Contain(nums, val) {
|
||||
fmt.Println("okk")
|
||||
}
|
||||
// Output:
|
||||
// okk
|
||||
}
|
||||
```
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
- [IsExported](#IsExported)
|
||||
- [IsZero](#IsZero)
|
||||
- [IsSlice](#IsSlice)
|
||||
- [IsTargetType](#IsTargetType)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -533,3 +534,44 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsTargetType">IsTargetType</span>
|
||||
|
||||
<p>check if a struct field type is target type or not</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (f *Field) IsTargetType(targetType reflect.Kind) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(n.IsTargetType(reflect.String))
|
||||
fmt.Println(a.IsTargetType(reflect.Slice))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1087,7 +1087,7 @@ func main() {
|
||||
func IsNotBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/e_oJW0RAquA)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1096,11 +1096,11 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := IsNotBlank("")
|
||||
result2 := IsNotBlank(" ")
|
||||
result3 := IsNotBlank("\t\v\f\n")
|
||||
result4 := IsNotBlank(" 中文")
|
||||
result5 := IsNotBlank(" world ")
|
||||
result1 := strutil.IsNotBlank("")
|
||||
result2 := strutil.IsNotBlank(" ")
|
||||
result3 := strutil.IsNotBlank("\t\v\f\n")
|
||||
result4 := strutil.IsNotBlank(" 中文")
|
||||
result5 := strutil.IsNotBlank(" world ")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
175
fileutil/file.go
175
fileutil/file.go
@@ -20,11 +20,67 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
// FileReader is a reader supporting offset seeking and reading one
|
||||
// line at a time, this is especially useful for large files
|
||||
type FileReader struct {
|
||||
*bufio.Reader
|
||||
file *os.File
|
||||
offset int64
|
||||
}
|
||||
|
||||
// NewFileReader creates the FileReader struct for reading
|
||||
func NewFileReader(path string) (*FileReader, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FileReader{
|
||||
file: f,
|
||||
Reader: bufio.NewReader(f),
|
||||
offset: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReadLine reads and returns one line at a time excluding the trailing '\r' and '\n'
|
||||
func (f *FileReader) ReadLine() (string, error) {
|
||||
data, err := f.Reader.ReadBytes('\n')
|
||||
f.offset += int64(len(data))
|
||||
if err == nil || err == io.EOF {
|
||||
for len(data) > 0 && (data[len(data)-1] == '\r' || data[len(data)-1] == '\n') {
|
||||
data = data[:len(data)-1]
|
||||
}
|
||||
return string(data), err
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Offset returns the current offset of the file
|
||||
func (f *FileReader) Offset() int64 {
|
||||
return f.offset
|
||||
}
|
||||
|
||||
// Seek sets the current offset of the reading
|
||||
func (f *FileReader) Seek(offset int64) error {
|
||||
_, err := f.file.Seek(offset, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Reader = bufio.NewReader(f.file)
|
||||
f.offset = offset
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close takes care of the opened file
|
||||
func (f *FileReader) Close() error {
|
||||
return f.file.Close()
|
||||
}
|
||||
|
||||
// IsExist checks if a file or directory exists.
|
||||
// Play: https://go.dev/play/p/nKKXt8ZQbmh
|
||||
func IsExist(path string) bool {
|
||||
@@ -508,6 +564,25 @@ func FileSize(path string) (int64, error) {
|
||||
return f.Size(), nil
|
||||
}
|
||||
|
||||
// DirSize walks the folder recursively and returns folder size in bytes.
|
||||
func DirSize(path string) (int64, error) {
|
||||
var size int64
|
||||
err := filepath.WalkDir(path, func(_ string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
size += info.Size()
|
||||
}
|
||||
return err
|
||||
})
|
||||
return size, err
|
||||
}
|
||||
|
||||
// MTime returns file modified time.
|
||||
// Play: https://go.dev/play/p/s_Tl7lZoAaY
|
||||
func MTime(filepath string) (int64, error) {
|
||||
@@ -536,7 +611,7 @@ func Sha(filepath string, shaType ...int) (string, error) {
|
||||
} else if shaType[0] == 512 {
|
||||
h = sha512.New()
|
||||
} else {
|
||||
return "", errors.New("param `shaType` should be 1, 256 or 512.")
|
||||
return "", errors.New("param `shaType` should be 1, 256 or 512")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,15 +629,19 @@ func Sha(filepath string, shaType ...int) (string, error) {
|
||||
|
||||
// ReadCsvFile read file content into slice.
|
||||
// Play: https://go.dev/play/p/OExTkhGEd3_u
|
||||
func ReadCsvFile(filepath string) ([][]string, error) {
|
||||
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
csvReader := csv.NewReader(f)
|
||||
records, err := csvReader.ReadAll()
|
||||
reader := csv.NewReader(f)
|
||||
if len(delimiter) > 0 {
|
||||
reader.Comma = delimiter[0]
|
||||
}
|
||||
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -571,8 +650,10 @@ func ReadCsvFile(filepath string) ([][]string, error) {
|
||||
}
|
||||
|
||||
// WriteCsvFile write content to target csv file.
|
||||
// append: append to existing csv file
|
||||
// delimiter: specifies csv delimiter
|
||||
// Play: https://go.dev/play/p/dAXm58Q5U1o
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error {
|
||||
flag := os.O_RDWR | os.O_CREATE
|
||||
|
||||
if append {
|
||||
@@ -587,7 +668,19 @@ func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
||||
defer f.Close()
|
||||
|
||||
writer := csv.NewWriter(f)
|
||||
writer.Comma = ','
|
||||
// 设置默认分隔符为逗号,除非另外指定
|
||||
if len(delimiter) > 0 {
|
||||
writer.Comma = delimiter[0]
|
||||
} else {
|
||||
writer.Comma = ','
|
||||
}
|
||||
|
||||
// 遍历所有记录并处理包含分隔符或双引号的单元格
|
||||
for i := range records {
|
||||
for j := range records[i] {
|
||||
records[i][j] = escapeCSVField(records[i][j], writer.Comma)
|
||||
}
|
||||
}
|
||||
|
||||
return writer.WriteAll(records)
|
||||
}
|
||||
@@ -627,7 +720,7 @@ func WriteBytesToFile(filepath string, content []byte) error {
|
||||
}
|
||||
|
||||
// ReadFile get file reader by a url or a local file
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/uNep3Tr8fqF
|
||||
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
|
||||
switch {
|
||||
case validator.IsUrl(path):
|
||||
@@ -646,3 +739,71 @@ func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
|
||||
return nil, func() {}, errors.New("unknown file type")
|
||||
}
|
||||
}
|
||||
|
||||
// escapeCSVField 处理单元格内容,如果包含分隔符,则用双引号包裹
|
||||
func escapeCSVField(field string, delimiter rune) string {
|
||||
// 替换所有的双引号为两个双引号
|
||||
escapedField := strings.ReplaceAll(field, "\"", "\"\"")
|
||||
|
||||
// 如果字段包含分隔符、双引号或换行符,用双引号包裹整个字段
|
||||
if strings.ContainsAny(escapedField, string(delimiter)+"\"\n") {
|
||||
escapedField = fmt.Sprintf("\"%s\"", escapedField)
|
||||
}
|
||||
|
||||
return escapedField
|
||||
}
|
||||
|
||||
// WriteMapsToCsv write slice of map to csv file.
|
||||
// Play: todo
|
||||
// filepath: Path to the CSV file.
|
||||
// records: Slice of maps to be written. the value of map should be basic type.
|
||||
// the maps will be sorted by key in alphabeta order, then be written into csv file.
|
||||
// appendToExistingFile: If true, data will be appended to the file if it exists.
|
||||
// delimiter: Delimiter to use in the CSV file.
|
||||
// headers: order of the csv column headers, needs to be consistent with the key of the map.
|
||||
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune,
|
||||
headers ...[]string) error {
|
||||
for _, record := range records {
|
||||
for _, value := range record {
|
||||
if !isCsvSupportedType(value) {
|
||||
return errors.New("unsupported value type detected; only basic types are supported: \nbool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var columnHeaders []string
|
||||
if len(headers) > 0 {
|
||||
columnHeaders = headers[0]
|
||||
} else {
|
||||
for key := range records[0] {
|
||||
columnHeaders = append(columnHeaders, key)
|
||||
}
|
||||
// sort keys in alphabeta order
|
||||
sort.Strings(columnHeaders)
|
||||
}
|
||||
|
||||
var datasToWrite [][]string
|
||||
if !appendToExistingFile {
|
||||
datasToWrite = append(datasToWrite, columnHeaders)
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
var row []string
|
||||
for _, h := range columnHeaders {
|
||||
row = append(row, fmt.Sprintf("%v", record[h]))
|
||||
}
|
||||
datasToWrite = append(datasToWrite, row)
|
||||
}
|
||||
|
||||
return WriteCsvFile(filepath, datasToWrite, appendToExistingFile, delimiter)
|
||||
}
|
||||
|
||||
// check if the value of map which to be written into csv is basic type.
|
||||
func isCsvSupportedType(v interface{}) bool {
|
||||
switch v.(type) {
|
||||
case bool, rune, string, int, int64, float32, float64, uint, byte, complex128, complex64, uintptr:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package fileutil
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
@@ -331,6 +332,28 @@ func ExampleWriteCsvFile() {
|
||||
// [[Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
|
||||
func ExampleWriteMapsToCsv() {
|
||||
csvFilePath := "./testdata/test3.csv"
|
||||
records := []map[string]any{
|
||||
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||
}
|
||||
|
||||
headers := []string{"Name", "Age", "Gender"}
|
||||
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := ReadCsvFile(csvFilePath, ';')
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
|
||||
func ExampleWriteStringToFile() {
|
||||
filepath := "./test.txt"
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestCreateFile(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestCreateFile")
|
||||
|
||||
f := "./text.txt"
|
||||
f := "./testdata/text.txt"
|
||||
if CreateFile(f) {
|
||||
file, err := os.Open(f)
|
||||
assert.IsNil(err)
|
||||
@@ -340,10 +340,14 @@ func TestSha(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSha")
|
||||
|
||||
sha1, err := Sha("./testdata/test.txt", 1)
|
||||
sha256, err := Sha("./testdata/test.txt", 256)
|
||||
sha512, err := Sha("./testdata/test.txt", 512)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
sha256, err := Sha("./testdata/test.txt", 256)
|
||||
assert.IsNil(err)
|
||||
|
||||
sha512, err := Sha("./testdata/test.txt", 512)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
|
||||
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
|
||||
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
|
||||
@@ -379,11 +383,36 @@ func TestWriteCsvFile(t *testing.T) {
|
||||
|
||||
assert.Equal(2, len(readContent))
|
||||
assert.Equal(3, len(readContent[0]))
|
||||
assert.Equal("Lili", content[0][0])
|
||||
assert.Equal("Lili", readContent[0][0])
|
||||
|
||||
// RemoveFile(csvFilePath)
|
||||
}
|
||||
|
||||
func TestWriteMapsToCsv(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteMapsToCSV")
|
||||
|
||||
csvFilePath := "./testdata/test4.csv"
|
||||
records := []map[string]any{
|
||||
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||
}
|
||||
|
||||
headers := []string{"Name", "Age", "Gender"}
|
||||
err := WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
content, err := ReadCsvFile(csvFilePath, ';')
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, len(content))
|
||||
assert.Equal(3, len(content[0]))
|
||||
assert.Equal("Lili", content[1][0])
|
||||
assert.Equal("22", content[1][1])
|
||||
assert.Equal("female", content[1][2])
|
||||
}
|
||||
|
||||
func TestWriteStringToFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
||||
|
||||
@@ -476,3 +505,42 @@ Disallow: /deny
|
||||
`
|
||||
internal.NewAssert(t, "TestReadFile").Equal(want, string(dat))
|
||||
}
|
||||
|
||||
func TestReadlineFile(t *testing.T) {
|
||||
path := "./testdata/demo.csv"
|
||||
reader, err := NewFileReader(path)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
indexMap := make(map[string]int64)
|
||||
defer reader.Close()
|
||||
for {
|
||||
offset := reader.Offset()
|
||||
line, err := reader.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
indexMap[line] = offset
|
||||
}
|
||||
|
||||
lines, err := ReadFileByLine(path)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
for _, line := range lines {
|
||||
offset, ok := indexMap[line]
|
||||
if !ok {
|
||||
t.Fail()
|
||||
}
|
||||
if err = reader.Seek(offset); err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
lineRead, err := reader.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
internal.NewAssert(t, "TestReadlineFile").Equal(line, lineRead)
|
||||
}
|
||||
}
|
||||
|
||||
2
fileutil/testdata/test1.csv
vendored
2
fileutil/testdata/test1.csv
vendored
@@ -1,3 +1,5 @@
|
||||
Lili,22,female
|
||||
Jim,21,male
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
fileutil/testdata/test2.csv
vendored
2
fileutil/testdata/test2.csv
vendored
@@ -1,3 +1,5 @@
|
||||
Lili,22,female
|
||||
Jim,21,male
|
||||
|
||||
|
||||
|
||||
|
||||
|
3
fileutil/testdata/test3.csv
vendored
Normal file
3
fileutil/testdata/test3.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name;Age;Gender
|
||||
Lili;22;female
|
||||
Jim;21;male
|
||||
|
3
fileutil/testdata/test4.csv
vendored
Normal file
3
fileutil/testdata/test4.csv
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name;Age;Gender
|
||||
Lili;22;female
|
||||
Jim;21;male
|
||||
|
@@ -6,12 +6,11 @@ package formatter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@@ -20,31 +19,24 @@ import (
|
||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||
// Play: https://go.dev/play/p/eRD5k2vzUVX
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
|
||||
if validator.IsInt(value) {
|
||||
v, err := convertor.ToInt(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaInt(v)
|
||||
}
|
||||
numString := convertor.ToString(value)
|
||||
|
||||
if validator.IsFloat(value) {
|
||||
v, err := convertor.ToFloat(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaFloat(v)
|
||||
}
|
||||
|
||||
if strutil.IsString(value) {
|
||||
v := fmt.Sprintf("%v", value)
|
||||
if validator.IsNumberStr(v) {
|
||||
return symbol + commaStr(v)
|
||||
}
|
||||
_, err := strconv.ParseFloat(numString, 64)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return ""
|
||||
index := strings.Index(numString, ".")
|
||||
if index == -1 {
|
||||
index = len(numString)
|
||||
}
|
||||
|
||||
for index > 3 {
|
||||
index = index - 3
|
||||
numString = numString[:index] + "," + numString[index:]
|
||||
}
|
||||
|
||||
return symbol + numString
|
||||
}
|
||||
|
||||
// Pretty data to JSON string.
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// see https://github.com/dustin/go-humanize/blob/master/comma.go
|
||||
func commaInt(v int64) string {
|
||||
sign := ""
|
||||
|
||||
// Min int64 can't be negated to a usable value, so it has to be special cased.
|
||||
if v == math.MinInt64 {
|
||||
return "-9,223,372,036,854,775,808"
|
||||
}
|
||||
|
||||
if v < 0 {
|
||||
sign = "-"
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
parts := []string{"", "", "", "", "", "", ""}
|
||||
j := len(parts) - 1
|
||||
|
||||
for v > 999 {
|
||||
parts[j] = strconv.FormatInt(v%1000, 10)
|
||||
switch len(parts[j]) {
|
||||
case 2:
|
||||
parts[j] = "0" + parts[j]
|
||||
case 1:
|
||||
parts[j] = "00" + parts[j]
|
||||
}
|
||||
v = v / 1000
|
||||
j--
|
||||
}
|
||||
parts[j] = strconv.Itoa(int(v))
|
||||
return sign + strings.Join(parts[j:], ",")
|
||||
}
|
||||
|
||||
func commaFloat(v float64) string {
|
||||
buf := &bytes.Buffer{}
|
||||
if v < 0 {
|
||||
buf.Write([]byte{'-'})
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
comma := []byte{','}
|
||||
|
||||
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
|
||||
pos := 0
|
||||
if len(parts[0])%3 != 0 {
|
||||
pos += len(parts[0]) % 3
|
||||
buf.WriteString(parts[0][:pos])
|
||||
buf.Write(comma)
|
||||
}
|
||||
for ; pos < len(parts[0]); pos += 3 {
|
||||
buf.WriteString(parts[0][pos : pos+3])
|
||||
buf.Write(comma)
|
||||
}
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
|
||||
if len(parts) > 1 {
|
||||
buf.Write([]byte{'.'})
|
||||
buf.WriteString(parts[1])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func commaStr(s string) string {
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return commaStrRecursive(s)
|
||||
}
|
||||
|
||||
func commaStrRecursive(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
|
||||
}
|
||||
@@ -330,10 +330,10 @@ func Cos(radian float64, precision ...int) float64 {
|
||||
return TruncRound(radian, 3)
|
||||
}
|
||||
|
||||
// Cos returns the sine of the radian argument.
|
||||
// Sin returns the sine of the radian argument.
|
||||
// Play: https://go.dev/play/p/TWMQlMywDsP
|
||||
func Sin(radian float64, precision ...int) float64 {
|
||||
return Cos((math.Pi / 2) - radian)
|
||||
return Cos((math.Pi/2)-radian, precision...)
|
||||
}
|
||||
|
||||
// Log returns the logarithm of base n.
|
||||
|
||||
@@ -14,6 +14,7 @@ package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -110,22 +111,23 @@ type HttpClientConfig struct {
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
// defaultHttpClientConfig defalut client config
|
||||
// defaultHttpClientConfig defalut client config.
|
||||
var defaultHttpClientConfig = &HttpClientConfig{
|
||||
Compressed: false,
|
||||
HandshakeTimeout: 20 * time.Second,
|
||||
ResponseTimeout: 40 * time.Second,
|
||||
}
|
||||
|
||||
// HttpClient is used for sending http request
|
||||
// HttpClient is used for sending http request.
|
||||
type HttpClient struct {
|
||||
*http.Client
|
||||
TLS *tls.Config
|
||||
Request *http.Request
|
||||
Config HttpClientConfig
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// NewHttpClient make a HttpClient instance
|
||||
// NewHttpClient make a HttpClient instance.
|
||||
func NewHttpClient() *HttpClient {
|
||||
client := &HttpClient{
|
||||
Client: &http.Client{
|
||||
@@ -141,7 +143,7 @@ func NewHttpClient() *HttpClient {
|
||||
return client
|
||||
}
|
||||
|
||||
// NewHttpClientWithConfig make a HttpClient instance with pass config
|
||||
// NewHttpClientWithConfig make a HttpClient instance with pass config.
|
||||
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
|
||||
if config == nil {
|
||||
config = defaultHttpClientConfig
|
||||
@@ -176,6 +178,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
rawUrl := request.RawURL
|
||||
|
||||
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
|
||||
|
||||
if client.Context != nil {
|
||||
req, err = http.NewRequestWithContext(client.Context, request.Method, rawUrl, bytes.NewBuffer(request.Body))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -230,7 +230,6 @@ func UploadFile(filepath string, server string) (bool, error) {
|
||||
}
|
||||
|
||||
// DownloadFile will download the file exist in url to a local file.
|
||||
// Play: todo
|
||||
func DownloadFile(filepath string, url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
// Package pointer contains some util functions to operate go pointer.
|
||||
package pointer
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Of returns a pointer to the value `v`.
|
||||
// Play: https://go.dev/play/p/HFd70x4DrMj
|
||||
@@ -47,5 +49,10 @@ func ExtractPointer(value any) any {
|
||||
if t.Kind() != reflect.Pointer {
|
||||
return value
|
||||
}
|
||||
return ExtractPointer(v.Elem().Interface())
|
||||
|
||||
if v.Elem().IsValid() {
|
||||
return ExtractPointer(v.Elem().Interface())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"io"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,13 +19,14 @@ const (
|
||||
LowwerLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
SymbolChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// RandInt generate random int between min and max, maybe min, not be max.
|
||||
// RandInt generate random int between [min, max).
|
||||
// Play: https://go.dev/play/p/pXyyAAI5YxD
|
||||
func RandInt(min, max int) int {
|
||||
if min == max {
|
||||
@@ -37,6 +40,22 @@ func RandInt(min, max int) int {
|
||||
return rand.Intn(max-min) + min
|
||||
}
|
||||
|
||||
// RandFloat generate random float64 number between [min, max) with specific precision.
|
||||
// Play: https://go.dev/play/p/zbD_tuobJtr
|
||||
func RandFloat(min, max float64, precision int) float64 {
|
||||
if min == max {
|
||||
return min
|
||||
}
|
||||
|
||||
if max < min {
|
||||
min, max = max, min
|
||||
}
|
||||
|
||||
n := rand.Float64()*(max-min) + min
|
||||
|
||||
return mathutil.RoundToFloat(n, precision)
|
||||
}
|
||||
|
||||
// RandBytes generate random byte slice.
|
||||
// Play: https://go.dev/play/p/EkiLESeXf8d
|
||||
func RandBytes(length int) []byte {
|
||||
@@ -52,19 +71,19 @@ func RandBytes(length int) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// RandString generate random string of specified length.
|
||||
// RandString generate random alpha string of specified length.
|
||||
// Play: https://go.dev/play/p/W2xvRUXA7Mi
|
||||
func RandString(length int) string {
|
||||
return random(Letters, length)
|
||||
}
|
||||
|
||||
// RandUpper generate a random upper case string.
|
||||
// RandUpper generate a random upper case string of specified length.
|
||||
// Play: https://go.dev/play/p/29QfOh0DVuh
|
||||
func RandUpper(length int) string {
|
||||
return random(UpperLetters, length)
|
||||
}
|
||||
|
||||
// RandLower generate a random lower case string.
|
||||
// RandLower generate a random lower case string of specified length.
|
||||
// Play: https://go.dev/play/p/XJtZ471cmtI
|
||||
func RandLower(length int) string {
|
||||
return random(LowwerLetters, length)
|
||||
@@ -76,12 +95,19 @@ func RandNumeral(length int) string {
|
||||
return random(Numeral, length)
|
||||
}
|
||||
|
||||
// RandNumeralOrLetter generate a random numeral or letter string.
|
||||
// RandNumeralOrLetter generate a random numeral or alpha string of specified length.
|
||||
// Play: https://go.dev/play/p/19CEQvpx2jD
|
||||
func RandNumeralOrLetter(length int) string {
|
||||
return random(Numeral+Letters, length)
|
||||
}
|
||||
|
||||
// RandSymbolChar generate a random symbol char of specified length.
|
||||
// symbol chars: !@#$%^&*()_+-=[]{}|;':\",./<>?.
|
||||
// Play: https://go.dev/play/p/Im6ZJxAykOm
|
||||
func RandSymbolChar(length int) string {
|
||||
return random(SymbolChars, length)
|
||||
}
|
||||
|
||||
// random generate a random string based on given string range.
|
||||
func random(s string, length int) string {
|
||||
b := make([]byte, length)
|
||||
@@ -136,3 +162,21 @@ func RandUniqueIntSlice(n, min, max int) []int {
|
||||
|
||||
return nums
|
||||
}
|
||||
|
||||
// RandFloats generate a slice of random float64 numbers of length n that do not repeat.
|
||||
// Play: https://go.dev/play/p/I3yndUQ-rhh
|
||||
func RandFloats(n int, min, max float64, precision int) []float64 {
|
||||
nums := make([]float64, n)
|
||||
used := make(map[float64]struct{}, n)
|
||||
for i := 0; i < n; {
|
||||
r := RandFloat(min, max, precision)
|
||||
if _, use := used[r]; use {
|
||||
continue
|
||||
}
|
||||
used[r] = struct{}{}
|
||||
nums[i] = r
|
||||
i++
|
||||
}
|
||||
|
||||
return nums
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package random
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ExampleRandInt() {
|
||||
@@ -134,3 +135,53 @@ func ExampleRandUniqueIntSlice() {
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRandSymbolChar() {
|
||||
pattern := `^[\W|_]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandSymbolChar(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandFloat() {
|
||||
pattern := `^[\d{1}.\d{2}]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
num := RandFloat(1.0, 5.0, 2)
|
||||
|
||||
// check num is a random float in [1.0, 5.0)
|
||||
result1 := num >= 1.0 && num < 5.0
|
||||
result2 := reg.MatchString(strconv.FormatFloat(num, 'f', -1, 64))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleRandFloats() {
|
||||
isInRange := true
|
||||
numbers := RandFloats(5, 1.0, 5.0, 2)
|
||||
for _, n := range numbers {
|
||||
isInRange = (n >= 1.0 && n < 5.0)
|
||||
}
|
||||
|
||||
fmt.Println(isInRange)
|
||||
fmt.Println(len(numbers))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 5
|
||||
}
|
||||
|
||||
@@ -154,3 +154,45 @@ func hasDuplicate(arr []int) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestRandSymbolChar(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pattern := `^[\W|_]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
symbolChars := RandSymbolChar(10)
|
||||
|
||||
assert := internal.NewAssert(t, "TestRandSymbolChar")
|
||||
assert.Equal(10, len(symbolChars))
|
||||
assert.Equal(true, reg.MatchString(symbolChars))
|
||||
}
|
||||
|
||||
func TestRandFloat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestRandFloat")
|
||||
|
||||
r1 := RandFloat(1.1, 10.1, 2)
|
||||
assert.GreaterOrEqual(r1, 1.1)
|
||||
assert.Less(r1, 10.1)
|
||||
|
||||
r2 := RandFloat(1.1, 1.1, 2)
|
||||
assert.Equal(1.1, r2)
|
||||
|
||||
r3 := RandFloat(10.1, 1.1, 2)
|
||||
assert.GreaterOrEqual(r1, 1.1)
|
||||
assert.Less(r3, 10.1)
|
||||
}
|
||||
|
||||
func TestRandFloats(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestRandFloats")
|
||||
|
||||
numbers := RandFloats(5, 1.0, 5.0, 2)
|
||||
for _, n := range numbers {
|
||||
assert.Equal(true, (n >= 1.0 && n < 5.0))
|
||||
}
|
||||
|
||||
assert.Equal(len(numbers), 5)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@@ -497,20 +498,13 @@ func FlatMap[T any, U any](slice []T, iteratee func(index int, item T) []U) []U
|
||||
// Reduce creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/_RfXJJWIsIm
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
||||
if len(slice) == 0 {
|
||||
return initial
|
||||
accumulator := initial
|
||||
|
||||
for i, v := range slice {
|
||||
accumulator = iteratee(i, v, accumulator)
|
||||
}
|
||||
|
||||
result := iteratee(0, initial, slice[0])
|
||||
|
||||
tmp := make([]T, 2)
|
||||
for i := 1; i < len(slice); i++ {
|
||||
tmp[0] = result
|
||||
tmp[1] = slice[i]
|
||||
result = iteratee(i, tmp[0], tmp[1])
|
||||
}
|
||||
|
||||
return result
|
||||
return accumulator
|
||||
}
|
||||
|
||||
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
|
||||
@@ -624,35 +618,34 @@ func IntSlice(slice any) []int {
|
||||
return result
|
||||
}
|
||||
|
||||
// DeleteAt delete the element of slice from start index to end index - 1.
|
||||
// DeleteAt delete the element of slice at index.
|
||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||
func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
||||
size := len(slice)
|
||||
|
||||
if start < 0 || start >= size {
|
||||
return slice
|
||||
func DeleteAt[T any](slice []T, index int) []T {
|
||||
if index >= len(slice) {
|
||||
index = len(slice) - 1
|
||||
}
|
||||
|
||||
if len(end) > 0 {
|
||||
end := end[0]
|
||||
if end <= start {
|
||||
return slice
|
||||
}
|
||||
if end > size {
|
||||
end = size
|
||||
}
|
||||
result := make([]T, len(slice)-1)
|
||||
copy(result, slice[:index])
|
||||
copy(result[index:], slice[index+1:])
|
||||
|
||||
slice = append(slice[:start], slice[end:]...)
|
||||
return slice
|
||||
return result
|
||||
}
|
||||
|
||||
// DeleteRange delete the element of slice from start index to end index(exclude).
|
||||
// Play: todo
|
||||
func DeleteRange[T any](slice []T, start, end int) []T {
|
||||
result := make([]T, 0, len(slice)-(end-start))
|
||||
|
||||
for i := 0; i < start; i++ {
|
||||
result = append(result, slice[i])
|
||||
}
|
||||
|
||||
if start == size-1 {
|
||||
slice = slice[:start]
|
||||
} else {
|
||||
slice = append(slice[:start], slice[start+1:]...)
|
||||
for i := end; i < len(slice); i++ {
|
||||
result = append(result, slice[i])
|
||||
}
|
||||
|
||||
return slice
|
||||
return result
|
||||
}
|
||||
|
||||
// Drop drop n elements from the start of a slice.
|
||||
@@ -1229,3 +1222,14 @@ func Partition[T any](slice []T, predicates ...func(item T) bool) [][]T {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Random get a random item of slice, return idx=-1 when slice is empty
|
||||
// Play: https://go.dev/play/p/UzpGQptWppw
|
||||
func Random[T any](slice []T) (val T, idx int) {
|
||||
if len(slice) == 0 {
|
||||
return val, -1
|
||||
}
|
||||
|
||||
idx = random.RandInt(0, len(slice))
|
||||
return slice[idx], idx
|
||||
}
|
||||
|
||||
@@ -594,18 +594,46 @@ func ExampleIntSlice() {
|
||||
}
|
||||
|
||||
func ExampleDeleteAt() {
|
||||
result1 := DeleteAt([]string{"a", "b", "c"}, -1)
|
||||
result2 := DeleteAt([]string{"a", "b", "c"}, 0)
|
||||
result3 := DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := DeleteAt(chars, 0)
|
||||
result2 := DeleteAt(chars, 4)
|
||||
result3 := DeleteAt(chars, 5)
|
||||
result4 := DeleteAt(chars, 6)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [c]
|
||||
// [b c d e]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleDeleteRange() {
|
||||
chars := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := DeleteRange(chars, 0, 0)
|
||||
result2 := DeleteRange(chars, 0, 1)
|
||||
result3 := DeleteRange(chars, 0, 3)
|
||||
result4 := DeleteRange(chars, 0, 4)
|
||||
result5 := DeleteRange(chars, 0, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c d e]
|
||||
// [b c d e]
|
||||
// [d e]
|
||||
// [e]
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleDrop() {
|
||||
@@ -1063,3 +1091,14 @@ func ExamplePartition() {
|
||||
// [[2 4] [1 3 5]]
|
||||
// [[1 2] [3 4] [5]]
|
||||
}
|
||||
|
||||
func ExampleRandom() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
val, idx := Random(nums)
|
||||
if idx >= 0 && idx < len(nums) && Contain(nums, val) {
|
||||
fmt.Println("okk")
|
||||
}
|
||||
// Output:
|
||||
// okk
|
||||
}
|
||||
|
||||
@@ -572,19 +572,27 @@ func TestDeleteAt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestDeleteAt")
|
||||
arr := []int{1, 2, 3, 4, 5}
|
||||
|
||||
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, -1))
|
||||
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, 3))
|
||||
assert.Equal([]string{"b", "c"}, DeleteAt([]string{"a", "b", "c"}, 0))
|
||||
assert.Equal([]string{"a", "c"}, DeleteAt([]string{"a", "b", "c"}, 1))
|
||||
assert.Equal([]string{"a", "b"}, DeleteAt([]string{"a", "b", "c"}, 2))
|
||||
assert.Equal([]int{2, 3, 4, 5}, DeleteAt(arr, 0))
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 4))
|
||||
|
||||
assert.Equal([]string{"b", "c"}, DeleteAt([]string{"a", "b", "c"}, 0, 1))
|
||||
assert.Equal([]string{"c"}, DeleteAt([]string{"a", "b", "c"}, 0, 2))
|
||||
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 3))
|
||||
assert.Equal([]string{}, DeleteAt([]string{"a", "b", "c"}, 0, 4))
|
||||
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 3))
|
||||
assert.Equal([]string{"a"}, DeleteAt([]string{"a", "b", "c"}, 1, 4))
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 5))
|
||||
assert.Equal([]int{1, 2, 3, 4}, DeleteAt(arr, 6))
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, arr)
|
||||
}
|
||||
|
||||
func TestDeleteRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestDeleteRange")
|
||||
|
||||
arr := []int{1, 2, 3, 4, 5}
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, DeleteRange(arr, 0, 0))
|
||||
assert.Equal([]int{2, 3, 4, 5}, DeleteRange(arr, 0, 1))
|
||||
assert.Equal([]int{4, 5}, DeleteRange(arr, 0, 3))
|
||||
}
|
||||
|
||||
func TestDrop(t *testing.T) {
|
||||
@@ -1185,3 +1193,28 @@ func TestPartition(t *testing.T) {
|
||||
assert.Equal([][]int{{2, 4}, {1, 3, 5}}, Partition([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 }))
|
||||
assert.Equal([][]int{{1, 2}, {3, 4}, {5}}, Partition([]int{1, 2, 3, 4, 5}, func(n int) bool { return n == 1 || n == 2 }, func(n int) bool { return n == 2 || n == 3 || n == 4 }))
|
||||
}
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestRandom")
|
||||
|
||||
var arr []int
|
||||
var val, idx int
|
||||
|
||||
_, idx = Random(arr)
|
||||
assert.Equal(-1, idx)
|
||||
|
||||
arr = []int{}
|
||||
_, idx = Random(arr)
|
||||
assert.Equal(-1, idx)
|
||||
|
||||
arr = []int{1}
|
||||
val, idx = Random(arr)
|
||||
assert.Equal(0, idx)
|
||||
assert.Equal(arr[idx], val)
|
||||
|
||||
arr = []int{1, 2, 3}
|
||||
val, idx = Random(arr)
|
||||
assert.Greater(len(arr), idx)
|
||||
assert.Equal(arr[idx], val)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,16 @@ func (f *Field) IsZero() bool {
|
||||
return reflect.DeepEqual(z, v)
|
||||
}
|
||||
|
||||
// IsNil returns true if the given field is nil value.
|
||||
func (f *Field) IsNil() bool {
|
||||
v := f.Value()
|
||||
if v == nil || (reflect.ValueOf(v)).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Name returns the name of the given field
|
||||
func (f *Field) Name() string {
|
||||
return f.field.Name
|
||||
@@ -68,6 +78,11 @@ func (f *Field) IsSlice() bool {
|
||||
return k == reflect.Slice
|
||||
}
|
||||
|
||||
// IsTargetType check if a struct field type is target type or not
|
||||
func (f *Field) IsTargetType(targetType reflect.Kind) bool {
|
||||
return f.rvalue.Kind() == targetType
|
||||
}
|
||||
|
||||
// mapValue covert field value to map
|
||||
func (f *Field) mapValue(value any) any {
|
||||
val := pointer.ExtractPointer(value)
|
||||
@@ -106,7 +121,9 @@ func (f *Field) mapValue(value any) any {
|
||||
ret = v.Interface()
|
||||
}
|
||||
default:
|
||||
ret = v.Interface()
|
||||
if v.Kind().String() != "invalid" {
|
||||
ret = v.Interface()
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -154,6 +154,25 @@ func TestField_IsSlice(t *testing.T) {
|
||||
assert.Equal(true, a.IsSlice())
|
||||
}
|
||||
|
||||
func TestField_IsTargetType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestField_IsTargetType")
|
||||
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{Name: "test", arr: []int{1, 2, 3}}
|
||||
s := New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
assert.Equal(true, n.IsTargetType(reflect.String))
|
||||
assert.Equal(true, a.IsTargetType(reflect.Slice))
|
||||
}
|
||||
|
||||
func TestField_MapValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package structs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
@@ -61,7 +62,7 @@ func New(value any, tagName ...string) *Struct {
|
||||
// ToMap convert the exported fields of a struct to map.
|
||||
func (s *Struct) ToMap() (map[string]any, error) {
|
||||
if !s.IsStruct() {
|
||||
return nil, errInvalidStruct(s)
|
||||
return nil, fmt.Errorf("invalid struct %v", s)
|
||||
}
|
||||
|
||||
result := make(map[string]any)
|
||||
@@ -70,9 +71,15 @@ func (s *Struct) ToMap() (map[string]any, error) {
|
||||
if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.IsZero() && f.tag.HasOption("omitempty") {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.IsNil() {
|
||||
continue
|
||||
}
|
||||
|
||||
result[f.tag.Name] = f.mapValue(f.Value())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package structs
|
||||
|
||||
import "fmt"
|
||||
|
||||
func errInvalidStruct(v any) error {
|
||||
return fmt.Errorf("invalid struct %v", v)
|
||||
}
|
||||
@@ -65,6 +65,45 @@ func TestStruct_ToMap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ToMap2(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestStruct_ToMap")
|
||||
|
||||
type M struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type S struct {
|
||||
ID int `json:"id"`
|
||||
M *M `json:"m"`
|
||||
}
|
||||
|
||||
s1 := &S{
|
||||
ID: 1,
|
||||
}
|
||||
var expect1 = map[string]any{"id": 1}
|
||||
map1, err := ToMap(s1)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(expect1, map1)
|
||||
|
||||
s2 := &S{
|
||||
ID: 1,
|
||||
M: &M{
|
||||
Name: "test",
|
||||
},
|
||||
}
|
||||
var expect2 = map[string]any{
|
||||
"id": 1,
|
||||
"m": map[string]any{
|
||||
"name": "test",
|
||||
}}
|
||||
map2, err := ToMap(s2)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(expect2, map2)
|
||||
}
|
||||
|
||||
func TestStruct_Fields(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -409,6 +409,7 @@ func IsBlank(str string) bool {
|
||||
}
|
||||
|
||||
// IsNotBlank checks if a string is not whitespace, not empty.
|
||||
// Play: https://go.dev/play/p/e_oJW0RAquA
|
||||
func IsNotBlank(str string) bool {
|
||||
return !IsBlank(str)
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@ func splitIntoStrings(s string, upperCase bool) []string {
|
||||
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
if isUpper(runes[i][0]) && isLower(runes[i+1][0]) {
|
||||
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
length := len(runes[i]) - 1
|
||||
temp := runes[i][length]
|
||||
runes[i+1] = append([]rune{temp}, runes[i+1]...)
|
||||
runes[i] = runes[i][:length]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,14 @@ package validator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
@@ -21,10 +23,10 @@ var (
|
||||
numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`)
|
||||
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
||||
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
||||
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
||||
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`)
|
||||
emailMatcher *regexp.Regexp = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
|
||||
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
|
||||
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^[1-9]\d{5}(18|19|20|21|22)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$`)
|
||||
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`^(\d{17})([0-9]|X|x)$`)
|
||||
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
|
||||
chinesePhoneMatcher *regexp.Regexp = regexp.MustCompile(`\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8}`)
|
||||
creditCardMatcher *regexp.Regexp = regexp.MustCompile(`^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11}|6[27][0-9]{14})$`)
|
||||
@@ -39,6 +41,52 @@ var (
|
||||
chinaUnionPay *regexp.Regexp = regexp.MustCompile(`^62[0-9]{14,17}$`)
|
||||
)
|
||||
|
||||
var (
|
||||
// Identity card formula
|
||||
factor = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
// ID verification bit
|
||||
verifyStr = [11]string{"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}
|
||||
// Starting year of ID card
|
||||
birthStartYear = 1900
|
||||
// Province code
|
||||
provinceKv = map[string]struct{}{
|
||||
"11": {},
|
||||
"12": {},
|
||||
"13": {},
|
||||
"14": {},
|
||||
"15": {},
|
||||
"21": {},
|
||||
"22": {},
|
||||
"23": {},
|
||||
"31": {},
|
||||
"32": {},
|
||||
"33": {},
|
||||
"34": {},
|
||||
"35": {},
|
||||
"36": {},
|
||||
"37": {},
|
||||
"41": {},
|
||||
"42": {},
|
||||
"43": {},
|
||||
"44": {},
|
||||
"45": {},
|
||||
"46": {},
|
||||
"50": {},
|
||||
"51": {},
|
||||
"52": {},
|
||||
"53": {},
|
||||
"54": {},
|
||||
"61": {},
|
||||
"62": {},
|
||||
"63": {},
|
||||
"64": {},
|
||||
"65": {},
|
||||
//"71": {},
|
||||
//"81": {},
|
||||
//"82": {},
|
||||
}
|
||||
)
|
||||
|
||||
// IsAlpha checks if the string contains only letters (a-zA-Z).
|
||||
// Play: https://go.dev/play/p/7Q5sGOz2izQ
|
||||
func IsAlpha(str string) bool {
|
||||
@@ -120,7 +168,7 @@ func ContainLetter(str string) bool {
|
||||
return letterRegexMatcher.MatchString(str)
|
||||
}
|
||||
|
||||
// ContainLetter check if the string contain at least one number.
|
||||
// ContainNumber check if the string contain at least one number.
|
||||
func ContainNumber(input string) bool {
|
||||
return numberRegexMatcher.MatchString(input)
|
||||
}
|
||||
@@ -228,7 +276,32 @@ func IsChineseMobile(mobileNum string) bool {
|
||||
// IsChineseIdNum check if the string is chinese id card.
|
||||
// Play: https://go.dev/play/p/d8EWhl2UGDF
|
||||
func IsChineseIdNum(id string) bool {
|
||||
return chineseIdMatcher.MatchString(id)
|
||||
// All characters should be numbers, and the last digit can be either x or X
|
||||
if !chineseIdMatcher.MatchString(id) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify province codes and complete all province codes according to GB/T2260
|
||||
_, ok := provinceKv[id[0:2]]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify birthday, must be greater than birthStartYear and less than the current year
|
||||
birthStr := fmt.Sprintf("%s-%s-%s", id[6:10], id[10:12], id[12:14])
|
||||
birthday, err := time.Parse("2006-01-02", birthStr)
|
||||
if err != nil || birthday.After(time.Now()) || birthday.Year() < birthStartYear {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verification code
|
||||
sum := 0
|
||||
for i, c := range id[:17] {
|
||||
v, _ := strconv.Atoi(string(c))
|
||||
sum += v * factor[i]
|
||||
}
|
||||
|
||||
return verifyStr[sum%11] == strings.ToUpper(id[17:18])
|
||||
}
|
||||
|
||||
// ContainChinese check if the string contain mandarin chinese.
|
||||
@@ -384,7 +457,7 @@ func IsGBK(data []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsNumberStr check if the value is number(integer, float) or not.
|
||||
// IsNumber check if the value is number(integer, float) or not.
|
||||
// Play: https://go.dev/play/p/mdJHOAvtsvF
|
||||
func IsNumber(v any) bool {
|
||||
return IsInt(v) || IsFloat(v)
|
||||
|
||||
@@ -154,7 +154,7 @@ func ExampleIsChineseMobile() {
|
||||
}
|
||||
|
||||
func ExampleIsChineseIdNum() {
|
||||
result1 := IsChineseIdNum("210911192105130715")
|
||||
result1 := IsChineseIdNum("210911192105130714")
|
||||
result2 := IsChineseIdNum("123456")
|
||||
|
||||
fmt.Println(result1)
|
||||
@@ -200,7 +200,7 @@ func ExampleIsDns() {
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,11 @@ func TestIsDns(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsDns")
|
||||
|
||||
assert.Equal(true, IsDns("abc.com"))
|
||||
assert.Equal(false, IsDns("a.b.com"))
|
||||
assert.Equal(true, IsDns("123.cn"))
|
||||
assert.Equal(true, IsDns("a.b.com"))
|
||||
|
||||
assert.Equal(false, IsDns("a.b.c"))
|
||||
assert.Equal(false, IsDns("a@b.com"))
|
||||
assert.Equal(false, IsDns("http://abc.com"))
|
||||
}
|
||||
|
||||
@@ -320,10 +324,13 @@ func TestIsChineseIdNum(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestIsChineseIdNum")
|
||||
|
||||
assert.Equal(true, IsChineseIdNum("210911192105130715"))
|
||||
assert.Equal(true, IsChineseIdNum("21091119210513071X"))
|
||||
assert.Equal(true, IsChineseIdNum("21091119210513071x"))
|
||||
assert.Equal(true, IsChineseIdNum("210911192105130714"))
|
||||
assert.Equal(true, IsChineseIdNum("11010519491231002X"))
|
||||
assert.Equal(true, IsChineseIdNum("11010519491231002x"))
|
||||
assert.Equal(false, IsChineseIdNum("123456"))
|
||||
assert.Equal(false, IsChineseIdNum("990911192105130714"))
|
||||
assert.Equal(false, IsChineseIdNum("990911189905130714"))
|
||||
assert.Equal(false, IsChineseIdNum("210911222205130714"))
|
||||
}
|
||||
|
||||
func TestIsCreditCard(t *testing.T) {
|
||||
|
||||
@@ -14,12 +14,6 @@ func TestTryUnwrap(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryUnwrap")
|
||||
assert.Equal(42, TryUnwrap(strconv.Atoi("42")))
|
||||
}
|
||||
|
||||
func TestTryUnwrapFail(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryUnwrapFail")
|
||||
|
||||
_, err := strconv.Atoi("4o2")
|
||||
defer func() {
|
||||
@@ -76,8 +70,6 @@ func TestXError_Unwrap(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestXError_StackTrace(t *testing.T) {
|
||||
// t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestXError_StackTrace")
|
||||
|
||||
err := New("error")
|
||||
@@ -86,7 +78,7 @@ func TestXError_StackTrace(t *testing.T) {
|
||||
|
||||
assert.Equal(3, len(stacks))
|
||||
assert.Equal("github.com/duke-git/lancet/v2/xerror.TestXError_StackTrace", stacks[0].Func)
|
||||
assert.Equal(83, stacks[0].Line)
|
||||
assert.Equal(75, stacks[0].Line)
|
||||
assert.Equal(true, strings.Contains(stacks[0].File, "xerror_test.go"))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user