mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
22 Commits
v2.3.3
...
de877e5278
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de877e5278 | ||
|
|
08f14d2b08 | ||
|
|
0ed2b11ba1 | ||
|
|
643edc1468 | ||
|
|
e2ff83649a | ||
|
|
a7fecfc73b | ||
|
|
8bbae69175 | ||
|
|
840ea8f3c5 | ||
|
|
a4e89bd7c1 | ||
|
|
2015d36b08 | ||
|
|
921f218ef7 | ||
|
|
0a2cc9c928 | ||
|
|
ed93aae970 | ||
|
|
1671f7856a | ||
|
|
1008dd4956 | ||
|
|
a254ebdc8e | ||
|
|
0bc11001a4 | ||
|
|
85d98ad915 | ||
|
|
cb08613ac3 | ||
|
|
bad1b05224 | ||
|
|
527328739a | ||
|
|
213e2b4ead |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,7 +8,7 @@ fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
fileutil/tempdir/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
# cryptor/*.pem
|
||||
test
|
||||
docs/node_modules
|
||||
docs/.vitepress/cache
|
||||
|
||||
104
README.md
104
README.md
@@ -364,10 +364,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>AesGcmEncrypt</big>** : encrypt byte slice data with key use AES GCM algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#AesGcmEncrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>AesGcmDecrypt</big>** : decrypt byte slice data with key use AES GCM algorithm.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#AesGcmDecrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>Base64StdEncode</big>** : encode string with base64 encoding.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Base64StdEncode)]
|
||||
[[play](https://go.dev/play/p/VOaUyQUreoK)]
|
||||
@@ -611,13 +611,13 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
- **<big>TrackFuncTime</big>** : tracks function execution time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#TrackFuncTime)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QBSEdfXHPTp)]
|
||||
- **<big>DaysBetween</big>** : returns the number of days between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#DaysBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/qD6qGb3TbOy)]
|
||||
- **<big>GenerateDatetimesBetween</big>** : returns a slice of strings between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
|
||||
|
||||
<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>
|
||||
@@ -813,10 +813,10 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Debounce</big>** : creates a debounced version of the provided function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Debounce)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/-dGFrYn_1Zi)]
|
||||
- **<big>Throttle</big>** : creates a throttled version of the provided function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Throttle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/HpoMov-tJSN)]
|
||||
- **<big>Schedule</big>** : invoke function every duration time, util close the returned bool channel.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
@@ -937,58 +937,58 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewOrderedMap</big>** : creates a new OrderedMap.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewOrderedMap)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Set</big>** : sets the given key-value pair for ordered map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Set)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Get</big>** : returns the value for the given key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Get)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Delete</big>** : deletes the key-value pair for the given key.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Delete)]
|
||||
[[play](todo)]
|
||||
[[play](ttps://go.dev/play/p/5bIi4yaZ3K-)]
|
||||
- **<big>OrderedMap_Clear</big>** : clears the ordered map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Clear)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8LwoJyEfuFr)]
|
||||
- **<big>OrderedMap_Front</big>** : returns the first key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Front)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/ty57XSimpoe)]
|
||||
- **<big>OrderedMap_Back</big>** : returns the last key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Back)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rQMjp1yQmpa)]
|
||||
- **<big>OrderedMap_Range</big>** : calls the given function for each key-value pair.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Range)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/U-KpORhc7LZ)]
|
||||
- **<big>OrderedMap_Keys</big>** : returns the keys in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Keys)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Vv_y9ExKclA)]
|
||||
- **<big>OrderedMap_Values</big>** : returns the values in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Values)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/TWj5n1-PUfx)]
|
||||
- **<big>OrderedMap_Elements</big>** : returns the key-value pairs in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Elements)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/4BHG4kKz6bB)]
|
||||
- **<big>OrderedMap_Len</big>** : returns the number of key-value pairs.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Len)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cLe6z2VX5N-)]
|
||||
- **<big>OrderedMap_Contains</big>** : returns true if the given key exists.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Contains)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QuwqqnzwDNX)]
|
||||
- **<big>OrderedMap_Iter</big>** : returns a channel that yields key-value pairs in order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_Iter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/tlq2tdvicPt)]
|
||||
- **<big>OrderedMap_ReverseIter</big>** : returns a channel that yields key-value pairs in reverse order.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_ReverseIter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8Q0ssg6hZzO)]
|
||||
- **<big>OrderedMap_SortByKey</big>** : sorts the map by key given less function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/N7hjD_alZPq)]
|
||||
- **<big>OrderedMap_MarshalJSON</big>** : implements the json.Marshaler interface.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_MarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/C-wAwydIAC7)]
|
||||
- **<big>OrderedMap_UnmarshalJSON</big>** : implements the json.Unmarshaler interface.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#OrderedMap_UnmarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>NewConcurrentMap</big>** : creates a ConcurrentMap with specific shard count.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1015,10 +1015,10 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
- **<big>SortByKey</big>** : sorts the map by its keys and returns a new map with sorted keys.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/PVdmBSnm6P_W)]
|
||||
- **<big>GetOrDefault</big>** : returns the value of the given key or a default value if the key is not present.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#GetOrDefault)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
||||
|
||||
|
||||
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. <a href="#index">index</a></h3>
|
||||
@@ -1264,22 +1264,22 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[play](https://go.dev/play/p/I3yndUQ-rhh)]
|
||||
- **<big>RandStringSlice</big>** : generate a slice of random string of length strLen based on charset.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandStringSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/2_-PiDv3tGn)]
|
||||
- **<big>RandBool</big>** : generate a random boolean value (true or false).
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandBool)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/to6BLc26wBv)]
|
||||
- **<big>RandBoolSlice</big>** : generate a random boolean slice of specified length.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandBoolSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/o-VSjPjnILI)]
|
||||
- **<big>RandIntSlice</big>** : generate a slice of random int. Number range in [min, max)
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandIntSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/GATTQ5xTEG8)]
|
||||
- **<big>RandFromGivenSlice</big>** : generate a random element from given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/UrkWueF6yYo)]
|
||||
- **<big>RandSliceFromGivenSlice</big>** : generate a random slice of length num from given slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
|
||||
|
||||
<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>
|
||||
@@ -1424,7 +1424,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||
- **<big>ForEachConcurrent</big>** : applies the iteratee function to each item in the slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ForEachConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/kT4XW7DKVoV)]
|
||||
- **<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)]
|
||||
@@ -1454,7 +1454,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>MapConcurrent</big>** : applies the iteratee function to each item in the slice by concrrent.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#MapConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/H1ehfPkPen0)]
|
||||
- **<big>Merge</big>** : merge all given slices into one slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
@@ -1472,7 +1472,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qT9dZC03A1K)]
|
||||
- **<big>ReduceConcurrent</big>** : reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ReduceConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Tjwe6OtaG07)]
|
||||
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
@@ -1526,16 +1526,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : remove duplicate elements from the input slice based on the values returned by the iteratee function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
[[play](https://go.dev/play/p/GY7JE4yikrl)]
|
||||
- **<big>UniqueByComparator</big>** : remove duplicate elements from the input slice using the provided comparator function.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByComparator)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rwSacr-ZHsR)]
|
||||
- **<big>UniqueByField</big>** : remove duplicate elements in struct slice by struct field.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByField)]
|
||||
[[play](https://go.dev/play/p/6cifcZSPIGu)]
|
||||
- **<big>UniqueByConcurrent</big>** : remove duplicate elements from the slice by concurrent.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/wXZ7LcYRMGL)]
|
||||
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
@@ -1573,7 +1573,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
- **<big>Frequency</big>** : counts the frequency of each element in the slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Frequency)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
|
||||
|
||||
<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>
|
||||
@@ -1610,7 +1610,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>FilterConcurrent</big>** : Applies the provided filter function `predicate` to each element of the input slice concurrently.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#FilterConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>Map</big>** : returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
@@ -1830,19 +1830,23 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/glNdQEA9HUi)]
|
||||
- **<big>Concat</big>** : concatenates strings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Concat)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/gD52SZHr4Kp)]
|
||||
- **<big>Ellipsis</big>** : truncates a string to a specified length and appends an ellipsis.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Ellipsis)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/i1vbdQiQVRR)]
|
||||
- **<big>Shuffle</big>** : shuffle the order of characters of given string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Shuffle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/iStFwBwyGY7)]
|
||||
- **<big>Rotate</big>** : rotates the string by the specified number of characters.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#Rotate)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Kf03iOeT5bd)]
|
||||
- **<big>TemplateReplace</big>** : replaces the placeholders in the template string with the corresponding values in the data map.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#TemplateReplace)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cXSuFvyZqv9)]
|
||||
- **<big>RegexMatchAllGroups</big>** : matches all subgroups in a string using a regular expression and returns the result.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
|
||||
|
||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -1881,16 +1885,16 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
- **<big>StartProcess</big>** : start a new process with the specified name and arguments.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#StartProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/5GVol6ryS_X)]
|
||||
- **<big>StopProcess</big>** : stop a process by pid.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#StopProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/jJZhRYGGcmD)]
|
||||
- **<big>KillProcess</big>** : kill a new process with the specified name and arguments.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#KillProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/XKmvV-ExBWa)]
|
||||
- **<big>GetProcessInfo</big>** : retrieves detailed process information by pid.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#GetProcessInfo)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||
|
||||
|
||||
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. <a href="#index">index</a></h3>
|
||||
|
||||
103
README_zh-CN.md
103
README_zh-CN.md
@@ -365,10 +365,10 @@ import "github.com/duke-git/lancet/v2/cryptor"
|
||||
[[play](https://go.dev/play/p/VtHxtkUj-3F)]
|
||||
- **<big>AesGcmEncrypt</big>** : 使用 AES GCM 算法模式加密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesGcmEncrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>AesGcmDecrypt</big>** : 使用 AES GCM 算法模式解密数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#AesGcmDecrypt)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rUt0-DmsPCs)]
|
||||
- **<big>Base64StdEncode</big>** : 将字符串 base64 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Base64StdEncode)]
|
||||
[[play](https://go.dev/play/p/VOaUyQUreoK)]
|
||||
@@ -614,13 +614,13 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
|
||||
- **<big>TrackFuncTime</big>** : 测试函数执行时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#TrackFuncTime)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QBSEdfXHPTp)]
|
||||
- **<big>DaysBetween</big>** : 返回两个日期之间的天数差。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#DaysBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/qD6qGb3TbOy)]
|
||||
- **<big>GenerateDatetimesBetween</big>** : 生成从start到end的所有日期时间的字符串列表。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/datetime.md#GenerateDatetimesBetween)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/6kHBpAxD9ZC)]
|
||||
|
||||
|
||||
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph。 <a href="#index">回到目录</a></h3>
|
||||
@@ -814,10 +814,10 @@ import "github.com/duke-git/lancet/v2/function"
|
||||
[[play](https://go.dev/play/p/absuEGB_GN7)]
|
||||
- **<big>Debounce</big>** : 创建一个函数的去抖动版本。该去抖动函数仅在上次调用后的指定延迟时间过去之后才会调用原始函数。支持取消去抖动。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Debounce)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/-dGFrYn_1Zi)]
|
||||
- **<big>Throttle</big>** : 创建一个函数的节流版本。返回的函数保证在每个时间间隔内最多只会被调用一次。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Throttle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/HpoMov-tJSN)]
|
||||
- **<big>Schedule</big>** : 每次持续时间调用函数,直到关闭返回的 channel。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Schedule)]
|
||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||
@@ -939,58 +939,58 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewOrderedMap</big>** : 创建有序映射。有序映射是键值对的集合,其中键是唯一的,并且保留键插入的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewOrderedMap)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Set</big>** : 设置给定的键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Set)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Get</big>** : 返回给定键的值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Get)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Y4ZJ_oOc1FU)]
|
||||
- **<big>OrderedMap_Delete</big>** : 删除给定键的键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Delete)]
|
||||
[[play](todo)]
|
||||
[[play](ttps://go.dev/play/p/5bIi4yaZ3K-)]
|
||||
- **<big>OrderedMap_Clear</big>** : 清空map数据。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Clear)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8LwoJyEfuFr)]
|
||||
- **<big>OrderedMap_Front</big>** : 返回第一个键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Front)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/ty57XSimpoe)]
|
||||
- **<big>OrderedMap_Back</big>** : 返回最后一个键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Back)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rQMjp1yQmpa)]
|
||||
- **<big>OrderedMap_Range</big>** : 为每个键值对调用给定的函数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Range)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/U-KpORhc7LZ)]
|
||||
- **<big>OrderedMap_Keys</big>** : 按顺序返回键的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Keys)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Vv_y9ExKclA)]
|
||||
- **<big>OrderedMap_Values</big>** : 按顺序返回值的切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Values)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/TWj5n1-PUfx)]
|
||||
- **<big>OrderedMap_Elements</big>** : 按顺序返回键值对。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Elements)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/4BHG4kKz6bB)]
|
||||
- **<big>OrderedMap_Len</big>** : 返回键值对的数量。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Len)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cLe6z2VX5N-)]
|
||||
- **<big>OrderedMap_Contains</big>** : 如果给定的键存在则返回true。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Contains)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/QuwqqnzwDNX)]
|
||||
- **<big>OrderedMap_Iter</big>** : 返回按顺序产生键值对的通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_Iter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/tlq2tdvicPt)]
|
||||
- **<big>OrderedMap_ReverseIter</big>** : 返回以相反顺序产生键值对的通道。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_ReverseIter)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8Q0ssg6hZzO)]
|
||||
- **<big>OrderedMap_SortByKey</big>** : 使用传入的比较函数排序map key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/N7hjD_alZPq)]
|
||||
- **<big>OrderedMap_MarshalJSON</big>** : 实现json.Marshaler接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_MarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/C-wAwydIAC7)]
|
||||
- **<big>OrderedMap_UnmarshalJSON</big>** : 实现json.Unmarshaler接口。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#OrderedMap_UnmarshalJSON)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/8C3MvJ3-mut)]
|
||||
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1017,10 +1017,10 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
|
||||
- **<big>SortByKey</big>** : 对传入的map根据key进行排序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#SortByKey)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/PVdmBSnm6P_W)]
|
||||
- **<big>GetOrDefault</big>** : 返回给定键的值,如果键不存在,则返回默认值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#GetOrDefault)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/99QjSYSBdiM)]
|
||||
|
||||
<h3 id="mathutil"> 13. mathutil 包实现了一些数学计算的函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1265,22 +1265,22 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
- **<big>RandStringSlice</big>** : 生成随机字符串slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandStringSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/2_-PiDv3tGn)]
|
||||
- **<big>RandBool</big>** : 生成随机bool值(true or false)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandBool)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/to6BLc26wBv)]
|
||||
- **<big>RandBoolSlice</big>** : 生成特定长度的随机bool slice。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandBoolSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/o-VSjPjnILI)]
|
||||
- **<big>RandIntSlice</big>** : 生成一个特定长度的随机int切片,数值范围[min, max)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandIntSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/GATTQ5xTEG8)]
|
||||
- **<big>RandFromGivenSlice</big>** : 从给定切片中随机生成元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/UrkWueF6yYo)]
|
||||
- **<big>RandSliceFromGivenSlice</big>** : 从给定切片中生成长度为 num 的随机切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandSliceFromGivenSlice)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/68UikN9d6VT)]
|
||||
|
||||
|
||||
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。 <a href="#index">回到目录</a></h3>
|
||||
@@ -1420,7 +1420,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||
- **<big>ForEachConcurrent</big>** : 对slice并发执行foreach操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ForEachConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/kT4XW7DKVoV)]
|
||||
- **<big>ForEachWithBreak</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数,当 iteratee 函数返回 false 时,终止遍历。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ForEachWithBreak)]
|
||||
[[play](https://go.dev/play/p/qScs39f3D9W)]
|
||||
@@ -1453,7 +1453,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/biaTefqPquw)]
|
||||
- **<big>MapConcurrent</big>** : 对slice并发执行map操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#MapConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/H1ehfPkPen0)]
|
||||
- **<big>Merge</big>** : 合并多个切片(不会消除重复元素)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Merge)]
|
||||
[[play](https://go.dev/play/p/lbjFp784r9N)]
|
||||
@@ -1471,7 +1471,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/qT9dZC03A1K)]
|
||||
- **<big>ReduceConcurrent</big>** : 对切片元素执行并发reduce操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ReduceConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Tjwe6OtaG07)]
|
||||
- **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Replace)]
|
||||
[[play](https://go.dev/play/p/P5mZp7IhOFo)]
|
||||
@@ -1525,16 +1525,16 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/AXw0R3ZTE6a)]
|
||||
- **<big>UniqueBy</big>** : 根据迭代函数返回的值,从输入切片中移除重复元素。此函数保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueBy)]
|
||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||
[[play](https://go.dev/play/p/GY7JE4yikrl)]
|
||||
- **<big>UniqueByComparator</big>** : 使用提供的比较器函数从输入切片中移除重复元素。此函数保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByComparator)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/rwSacr-ZHsR)]
|
||||
- **<big>UniqueByField</big>** : 根据struct字段对struct切片去重复。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByField)]
|
||||
[[play](https://go.dev/play/p/6cifcZSPIGu)]
|
||||
- **<big>UniqueByConcurrent</big>** : 并发的从输入切片中移除重复元素,结果保持元素的顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/wXZ7LcYRMGL)]
|
||||
- **<big>Union</big>** : 合并多个切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Union)]
|
||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||
@@ -1571,7 +1571,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
- **<big>Frequency</big>** : 计算切片中每个元素出现的频率。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Frequency)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/CW3UVNdUZOq)]
|
||||
|
||||
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
@@ -1608,7 +1608,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[play](https://go.dev/play/p/MFlSANo-buc)]
|
||||
- **<big>FilterConcurrent</big>** : 对slice并发执行filter操作。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#FilterConcurrent)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/t_pkwerIRVx)]
|
||||
- **<big>Map</big>** : 返回一个 stream,该 stream 由将给定函数应用于源 stream 元素的元素组成。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#Map)]
|
||||
[[play](https://go.dev/play/p/OtNQUImdYko)]
|
||||
@@ -1832,19 +1832,22 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/glNdQEA9HUi)]
|
||||
- **<big>Concat</big>** : 拼接字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Concat)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/gD52SZHr4Kp)]
|
||||
- **<big>Ellipsis</big>** : 将字符串截断到指定长度,并在末尾添加省略号。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Ellipsis)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/i1vbdQiQVRR)]
|
||||
- **<big>Shuffle</big>** : 打乱给定字符串中的字符顺序。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Shuffle)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/iStFwBwyGY7)]
|
||||
- **<big>Rotate</big>** : 按指定的字符数旋转字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#Rotate)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/Kf03iOeT5bd)]
|
||||
- **<big>TemplateReplace</big>** : 将模板字符串中的占位符替换为map中的相应值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#TemplateReplace)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/cXSuFvyZqv9)]
|
||||
- **<big>RegexMatchAllGroups</big>** : 使用正则表达式匹配字符串中的所有子组并返回结果。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#RegexMatchAllGroups)]
|
||||
[[play](https://go.dev/play/p/JZiu0RXpgN-)]
|
||||
|
||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -1883,16 +1886,16 @@ import "github.com/duke-git/lancet/v2/system"
|
||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||
- **<big>StartProcess</big>** :创建进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#StartProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/5GVol6ryS_X)]
|
||||
- **<big>StopProcess</big>** : 停止进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#StopProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/jJZhRYGGcmD)]
|
||||
- **<big>KillProcess</big>** : 杀掉进程。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#KillProcess)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/XKmvV-ExBWa)]
|
||||
- **<big>GetProcessInfo</big>** : 根据进程id获取进程信息。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#GetProcessInfo)]
|
||||
[[play](todo)]
|
||||
[[play](https://go.dev/play/p/NQDVywEYYx7)]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
return node.value, true
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
}
|
||||
} else {
|
||||
node.value = value
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
}
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
l.length = len(l.cache)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
|
||||
return node.key
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
|
||||
func (l *LRUCache[K, V]) moveToTail(node *lruNode[K, V]) {
|
||||
if l.tail == node {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,10 +72,17 @@ func Nand[T, U any](a T, b U) bool {
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
} else {
|
||||
return elseValue
|
||||
}
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
// Deprecated: Use Ternary instead.
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
return Ternary(isTrue, ifValue, elseValue)
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ func ExampleNand() {
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
func ExampleTernary() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
result1 := Ternary(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
result2 := Ternary(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
|
||||
@@ -124,13 +124,13 @@ func TestNand(t *testing.T) {
|
||||
assert.Equal(false, Nand(1, 1))
|
||||
}
|
||||
|
||||
func TestTernaryOperator(t *testing.T) {
|
||||
func TestTernary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TernaryOperator")
|
||||
assert := internal.NewAssert(t, "TestTernary")
|
||||
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
|
||||
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
|
||||
assert.Equal(trueValue, Ternary(true, trueValue, falseValue))
|
||||
}
|
||||
|
||||
@@ -8,16 +8,20 @@ package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
@@ -245,7 +249,7 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
// AesGcmEncrypt encrypt data with key use AES GCM algorithm
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
@@ -268,7 +272,7 @@ func AesGcmEncrypt(data, key []byte) []byte {
|
||||
}
|
||||
|
||||
// AesGcmDecrypt decrypt data with key use AES GCM algorithm
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
@@ -591,6 +595,7 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return cipherText
|
||||
}
|
||||
|
||||
@@ -624,6 +629,7 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return plainText
|
||||
}
|
||||
|
||||
@@ -655,3 +661,150 @@ func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte
|
||||
|
||||
return decryptedBytes, nil
|
||||
}
|
||||
|
||||
// RsaSign signs the data with RSA.
|
||||
// Play: todo
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
|
||||
privateKey, err := loadRasPrivateKey(privateKeyFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
|
||||
}
|
||||
|
||||
// RsaVerifySign verifies the signature of the data with RSA.
|
||||
// Play: todo
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
|
||||
publicKey, err := loadRsaPublicKey(pubKeyFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rsa.VerifyPKCS1v15(publicKey, hash, hashed, signature)
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRsaPublicKey(filename string) (*rsa.PublicKey, error) {
|
||||
pubKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(pubKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the public key")
|
||||
}
|
||||
|
||||
var pubKey *rsa.PublicKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
if blockType == "RSA PUBLIC KEY" {
|
||||
pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
// todo: here should be a bug, should return nil, err
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
}
|
||||
} else if blockType == "PUBLIC KEY" {
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRasPrivateKey(filename string) (*rsa.PrivateKey, error) {
|
||||
priKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(priKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the private key")
|
||||
}
|
||||
|
||||
var privateKey *rsa.PrivateKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
// PKCS#1 format
|
||||
if blockType == "RSA PRIVATE KEY" {
|
||||
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if blockType == "PRIVATE KEY" { // PKCS#8 format
|
||||
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ok bool
|
||||
privateKey, ok = priKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
// hashData returns the hash value of the data, using the specified hash function
|
||||
func hashData(hash crypto.Hash, data []byte) ([]byte, error) {
|
||||
if !hash.Available() {
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
var hashed []byte
|
||||
|
||||
switch hash {
|
||||
case crypto.SHA224:
|
||||
h := sha256.Sum224(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA256:
|
||||
h := sha256.Sum256(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA384:
|
||||
h := sha512.Sum384(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA512:
|
||||
h := sha512.Sum512(data)
|
||||
hashed = h[:]
|
||||
default:
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
return hashed, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -284,7 +285,7 @@ func ExampleDesOfbDecrypt() {
|
||||
|
||||
func ExampleGenerateRsaKey() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -297,14 +298,14 @@ func ExampleGenerateRsaKey() {
|
||||
|
||||
func ExampleRsaEncrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -314,14 +315,14 @@ func ExampleRsaEncrypt() {
|
||||
|
||||
func ExampleRsaDecrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -536,3 +537,49 @@ func ExampleRsaEncryptOAEP() {
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleRsaSign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRsaVerifySign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -139,13 +140,13 @@ func TestDesOfbEncrypt(t *testing.T) {
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "./rsa_private_example.pem", "./rsa_public_example.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "./rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "./rsa_private_example.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
@@ -170,7 +171,6 @@ func TestRsaEncryptOAEP(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAesGcmEncrypt(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
|
||||
data := "hello world"
|
||||
@@ -182,3 +182,53 @@ func TestAesGcmEncrypt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAesGcmEncrypt")
|
||||
assert.Equal(data, string(decrypted))
|
||||
}
|
||||
|
||||
func TestRsaSignAndVerify(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
t.Run("RSA Sign and Verify", func(t *testing.T) {
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify Invalid Signature", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
invalidSig := []byte("InvalidSignature")
|
||||
|
||||
err := RsaVerifySign(hash, data, invalidSig, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify With Different Hash", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
hashSign := crypto.SHA256
|
||||
hashVerify := crypto.SHA512
|
||||
|
||||
signature, err := RsaSign(hashSign, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hashVerify, data, signature, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
51
cryptor/rsa_private_example.pem
Normal file
51
cryptor/rsa_private_example.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
MIIJKAIBAAKCAgEAm1rBCE+U+7M46S21q0yoygTXHlhnZZ6IfQwRCK24EFQ6yBxt
|
||||
emHKjNuHEIQ/DlSh+B5DRX/bCHQ/m5c0yrNPiMKv9N3K4e8Wv/pBVqAsSmF2nSjx
|
||||
pXSraIACqrNSAig8MzUJ8pZq5d/9Le1AXNRa0aqHbw9YoLQJKACrdY4YbDi1NXU2
|
||||
ADImpnaSON0VJt5sdqA8OrEVOhm02DA4KEshJXAp2pR4h3KT82Fuj0dMKB1iKAIn
|
||||
Xo8OeYwKgcjBxNZK4mPo6JT0ejYnFwhgtPaLlUm0BpXAqI2eclvhn+LmM9Q/S1mv
|
||||
DCeLdNgQ8rh1+qPBXkCesskyu2hyuY3/H+WjQ4PHjF++lCnuRv/GJYIgbUnLxKP4
|
||||
cxsB+jj7SU+ltgADZoLyNeUpQ9QxY8FNbKDxJKnA7khtmvHjE4PKdy2e4M4mVcMh
|
||||
eOtJdjvxhA2SEh9xnzP5G2JSHzE3877evInpQCJb+bfEG533B5Yrgm85C+sPcxrK
|
||||
684+Dmn+Y3wdQQNJgYgQGZDGDIRY8stWpRX9G2dnWQfVtZLmSM5WwVPeI4wa6dxi
|
||||
zk/ukylsgk9E5zJjZlPx8Fx2hnTsrNSARl0gCdbhGhRjHlVFjKI80z+evPXLCYn8
|
||||
B4CwWsg6ExBZSOAvcrN7XZFcalDCT5CqsNpbCg/7SXO87v8KL/54fKUc4qsCAwEA
|
||||
AQKCAgBjnDQrBQPsw0SZVmKmnDeZmLLp1Rsu8BBpxWPioahkZ+1sw7V6g9tgp52Z
|
||||
fIIFyUQ1GApgNJOXfxoNxEzoL0Ku2M4DfnaImUmH/IkKZxce9hEcwdT3FrCVB4cu
|
||||
Nl493diDqN1g+ws9q3nlibr8CnjU+LdwAXH9UJKSYKOPc3W7ZjziMu5V/9ICaAJn
|
||||
jXHzgygeg606oLKQl0z6VSicxVdSbvGXIh2KE3BD3FQMcFWnXvfB2Weu3KEWVDGk
|
||||
d7muYQyQzijXgDKlbbVwskF3pqFnLmPM2RY3vN48SyeG4fBiiROwV6fCblSfra5o
|
||||
Qtf6xibFLT/UOOdbfKQaz64moJImRyTNYJ7dq8wojOM7IiIqr6iDaDvq71qf2vUx
|
||||
SMJ4I2DIM4WJmxODr/ZBBar8prSY7z2RZzaqoLFt29yCzGLL+jv5UEiSFI3M9wWx
|
||||
RSPNnmcvC+JN3rSmAgmxp9IOtFYJfYQm3qDpPCFarKJniovcdkJWsnzOzO5yHFW8
|
||||
3zSWt7SBotrbq5zd8hEWibW7Ir8bC6ssonuHeOfVL8ed4zBVtTohk0vMEVeb+cqn
|
||||
Fa6EnPyuuFS1AHETTM8cx2K9KF9jLd1On5RdV96fUS4zSRBn9Fvc61o64+NTuf+6
|
||||
kcJvJLfIeBqnryJTnDvRJ7TGk/TC83C3q0jEJcg34WK4XzNuKQKCAQEAwMwufhSP
|
||||
5Fj5KP2zJ2SaU8Ie4ydYACaMZmcigbQVPAFrlACGn04PJXgSDkVj83K1YdAXD69/
|
||||
E/GUGd0Tf6q0kITaiqZ294IMexhu0jAkutmeB0wDoOnyoot5sMvdESr5Dh8TJsz4
|
||||
C0XKw/PAQtgabkhuoFROd/k0Lm/CbBQdLNYRuzxVA/qr2NnT03Nqk8QL5wFABJ47
|
||||
aaPjV8ACAWLEK4B4+iqeSDVe9uzUTJ4MWhMXwbvZKGvoo8xk/c93Yggzh8a2cIuW
|
||||
QZbmjZ4vmgiJkJGQDduOcHSnzfARPyOQzFhrFUxcOK1V+cSsxkrxVmKwPTC+Z2Yy
|
||||
j2TlEGRqvo9vDQKCAQEAzkhNRYgtyso/ykVd8YBdiP+YTyvMn6a+ELywA1sJJORx
|
||||
FWAOXkXmWKEgjEqEG340k+B8P48xoEcgTopnz4Y034mEdG85HcXt9gdgL2rBoagx
|
||||
5LNrAVdhLv9n0vHU75RCx9st9kYWqEX8WPoDV4JKuy/h9gjG1q290ethquopYsoP
|
||||
PJXhTWCmtMZXUoNvlLkxW3RVU82gKV+NkgwtJ0ZVppqCWO3+o9HO7i7kVRf/TC3m
|
||||
ZpIAYxpqQ/Yee1dXY/LXjN5tSN4Gu2zCs+72Quzw97M/6x6dAbIm525U1SIYwOna
|
||||
fmTQEvVtc/ZuvFNqcI7uoUtNDEZ2EWWxOGZEauNqlwKCAQBxOvnLPpRLzh13f5iq
|
||||
eCFTM90kF8VNQVaQBd50Qql99m+SGsT15shqfxxLmWFcZ3AzpB0HL1D5C5apofeD
|
||||
sWQexIf9ikqwjoZ5/R2JAJFx08FGE9TFuuCvqi6sMO8C2DQxoPqEfTjolfLCJvQx
|
||||
ze2n+45NR3ZWa9vDsguDokSIQqljR8m+bohi8XvA4jYj1q4O2+MXUz8dig1JShFj
|
||||
cvg3fFqQwlr3mbDOYMVGwkQK2s/HDmY5oTaejLp7fk9lGd/5zDD15GU43EFHxzG5
|
||||
y23PpE3wdZQwY7Lx9h6K8H5oJT2u4ov/FX47FNFMHFOlIozTQz9wRstHAECv4en3
|
||||
RRI5AoIBAHzwkczBdGrVINnUNdgmFYD6vjeFocQ46/mbL0h5BQrRSiTWLx2uXJvl
|
||||
y57tKyKzyAig+OBOTJJ1Qf4QGlw5PyD9W7ph+0grL7vKL9nIYUsWYlHQ0cjYMcaT
|
||||
b0D2tC//ror6F9aIEQUOjo8drpR8F+NUVxn7quMwDD5uwJMSjMqG87+QUAvbtFzd
|
||||
nNofPZ/ooxpvVZcSfiVQ+KAyu86D7TCheL2AOLDkTN86i5V2mWx8iIYrfAyKXT6Y
|
||||
fVHbTtT8qs1pkuuFfrJaZ3swCvvyIukEKnyv6Ay06JdX3g3RPwjpGyteyCATgp2v
|
||||
7tYl99wA1kvfHeWHb8+Ntk8gsePDpjUCggEBAJjXXxWlRUOVoeV3/1El/uICdp8F
|
||||
jmFJUmd/7Se/XUODTHBNcDQgC0fVaDtIAGUMwDHfEuDA5mQhCJBNs8eXALeTG0KL
|
||||
NvCmDHeVccX+z3Ue6w3mWPpW0fGXJKNBbcDuEl6qDNymGjDOSPjXhID/nSjvF4Nb
|
||||
RwIXPgB1OL1+4mUskO5xSguQhNHlMkMy3JytK+lXGclMsckWmsexRaaznsHOkn53
|
||||
bdDhoWuomSFA1QCurPFcF37HNknKrrZCZywnR5wRLG3zWgkFnAb1ePhmyrUSaSAJ
|
||||
d0tKGJgdQkjetmIJzwsaIpviSKue5cGQWqSQI4oOV6BPmPw6MoApfK0wlOw=
|
||||
-----END rsa private key-----
|
||||
14
cryptor/rsa_public_example.pem
Normal file
14
cryptor/rsa_public_example.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm1rBCE+U+7M46S21q0yo
|
||||
ygTXHlhnZZ6IfQwRCK24EFQ6yBxtemHKjNuHEIQ/DlSh+B5DRX/bCHQ/m5c0yrNP
|
||||
iMKv9N3K4e8Wv/pBVqAsSmF2nSjxpXSraIACqrNSAig8MzUJ8pZq5d/9Le1AXNRa
|
||||
0aqHbw9YoLQJKACrdY4YbDi1NXU2ADImpnaSON0VJt5sdqA8OrEVOhm02DA4KEsh
|
||||
JXAp2pR4h3KT82Fuj0dMKB1iKAInXo8OeYwKgcjBxNZK4mPo6JT0ejYnFwhgtPaL
|
||||
lUm0BpXAqI2eclvhn+LmM9Q/S1mvDCeLdNgQ8rh1+qPBXkCesskyu2hyuY3/H+Wj
|
||||
Q4PHjF++lCnuRv/GJYIgbUnLxKP4cxsB+jj7SU+ltgADZoLyNeUpQ9QxY8FNbKDx
|
||||
JKnA7khtmvHjE4PKdy2e4M4mVcMheOtJdjvxhA2SEh9xnzP5G2JSHzE3877evInp
|
||||
QCJb+bfEG533B5Yrgm85C+sPcxrK684+Dmn+Y3wdQQNJgYgQGZDGDIRY8stWpRX9
|
||||
G2dnWQfVtZLmSM5WwVPeI4wa6dxizk/ukylsgk9E5zJjZlPx8Fx2hnTsrNSARl0g
|
||||
CdbhGhRjHlVFjKI80z+evPXLCYn8B4CwWsg6ExBZSOAvcrN7XZFcalDCT5CqsNpb
|
||||
Cg/7SXO87v8KL/54fKUc4qsCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
@@ -385,7 +385,7 @@ func TimestampNano(timezone ...string) int64 {
|
||||
|
||||
// TrackFuncTime track the time of function execution.
|
||||
// call it at top of the func like `defer TrackFuncTime(time.Now())()`
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/QBSEdfXHPTp
|
||||
func TrackFuncTime(pre time.Time) func() {
|
||||
callerName := getCallerName()
|
||||
return func() {
|
||||
@@ -413,7 +413,7 @@ func getCallerName() string {
|
||||
}
|
||||
|
||||
// DaysBetween returns the number of days between two times.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/qD6qGb3TbOy
|
||||
func DaysBetween(start, end time.Time) int {
|
||||
duration := end.Sub(start)
|
||||
days := int(duration.Hours() / 24)
|
||||
@@ -424,7 +424,7 @@ func DaysBetween(start, end time.Time) int {
|
||||
// GenerateDatetimesBetween returns a slice of strings between two times.
|
||||
// layout: the format of the datetime string
|
||||
// interval: the interval between two datetimes
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/6kHBpAxD9ZC
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error) {
|
||||
var result []string
|
||||
|
||||
@@ -443,3 +443,50 @@ func GenerateDatetimesBetween(start, end time.Time, layout string, interval stri
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Min returns the earliest time among the given times.
|
||||
// Play: todo
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time {
|
||||
minTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return minTime
|
||||
}
|
||||
|
||||
// Max returns the latest time among the given times.
|
||||
// Play: todo
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time {
|
||||
maxTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime
|
||||
}
|
||||
|
||||
// MaxMin returns the latest and earliest time among the given times.
|
||||
// Play: todo
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
||||
maxTime = t1
|
||||
minTime = t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime, minTime
|
||||
}
|
||||
|
||||
@@ -437,3 +437,32 @@ func ExampleGenerateDatetimesBetween() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result := Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result := Max(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMaxMin() {
|
||||
max, min := MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
@@ -521,3 +521,60 @@ func TestGenerateDatetimesBetween(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(zeroTime, Min(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(zeroTime, Min(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAgo, Min(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(now, Max(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMaxMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMinMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
max, min := MaxMin(zeroTime, now, oneMinuteAgo, oneMinuteAfter)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
|
||||
max, min = MaxMin(now, zeroTime)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(now, max)
|
||||
|
||||
max, min = MaxMin(oneMinuteAgo, now, oneMinuteAfter)
|
||||
assert.Equal(oneMinuteAgo, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -257,9 +258,45 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>三元运算符。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>三元运算符</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`Ternary`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
|
||||
@@ -70,6 +70,9 @@ import (
|
||||
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||
- [RsaSign](#RsaSign)
|
||||
- [RsaVerifySign](#RsaVerifySign)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -391,7 +394,7 @@ func main() {
|
||||
func AesGcmEncrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -425,7 +428,7 @@ func main() {
|
||||
func AesGcmDecrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1607,3 +1610,81 @@ func main() {
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaSign">RsaSign</span>
|
||||
|
||||
<p>应用RSA算法签名数据。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaVerifySign">RsaVerifySign</span>
|
||||
|
||||
<p>验证数据的签名是否符合RSA算法。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -67,6 +67,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1479,7 +1482,7 @@ func main() {
|
||||
func TrackFuncTime(pre time.Time) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QBSEdfXHPTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1511,7 +1514,7 @@ func main() {
|
||||
func DaysBetween(start, end time.Time) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qD6qGb3TbOy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1544,7 +1547,7 @@ func main() {
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6kHBpAxD9ZC)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1570,4 +1573,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>返回最早时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>返回最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>返回最早和最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1076,4 +1077,34 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>返回exe,dll文件版本号(仅Window平台).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -205,7 +205,7 @@ func main() {
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func())
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/-dGFrYn_1Zi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -753,7 +753,7 @@ func main() {
|
||||
func Throttle(fn func(), interval time.Duration) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HpoMov-tJSN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -1191,7 +1191,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1230,7 +1230,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1270,7 +1270,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Delete(key K)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/5bIi4yaZ3K-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1306,7 +1306,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Clear()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8LwoJyEfuFr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1345,7 +1345,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ty57XSimpoe)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1385,7 +1385,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rQMjp1yQmpa)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1402,12 +1402,12 @@ func main() {
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
frontElement, ok := om.Front()
|
||||
fmt.Println(frontElement)
|
||||
backElement, ok := om.Back()
|
||||
fmt.Println(backElement)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// {a 1}
|
||||
// {c 3}
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1422,7 +1422,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/U-KpORhc7LZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1461,7 +1461,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Keys() []K
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Vv_y9ExKclA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1497,7 +1497,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Values() []V
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TWj5n1-PUfx)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1533,7 +1533,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Elements() []struct
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4BHG4kKz6bB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1569,7 +1569,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cLe6z2VX5N-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1605,7 +1605,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QuwqqnzwDNX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1647,7 +1647,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tlq2tdvicPt)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1688,7 +1688,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8Q0ssg6hZzO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1726,7 +1726,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/N7hjD_alZPq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1737,7 +1737,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1765,7 +1765,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/C-wAwydIAC7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1776,7 +1776,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1802,7 +1802,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8C3MvJ3-mut)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1822,6 +1822,7 @@ func main() {
|
||||
fmt.Println(om.Elements())
|
||||
|
||||
// Output:
|
||||
// [{a 1} {b 2} {c 3}]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2239,7 +2240,7 @@ func main() {
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/PVdmBSnm6P_W)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -2257,7 +2258,9 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKey(m)
|
||||
result := maputil.SortByKey(m, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
@@ -2276,7 +2279,7 @@ func main() {
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -134,7 +135,7 @@ func main() {
|
||||
func RandFromGivenSlice[T any](slice []T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UrkWueF6yYo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -161,7 +162,7 @@ func main() {
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/68UikN9d6VT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -172,9 +173,11 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
fmt.Println(chosen3goods)
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
|
||||
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
|
||||
fmt.Println(chosen3goods)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -347,7 +350,7 @@ func main() {
|
||||
func RandIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GATTQ5xTEG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -451,7 +454,7 @@ func main() {
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2_-PiDv3tGn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -480,7 +483,7 @@ func main() {
|
||||
func RandBool() bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/to6BLc26wBv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -506,7 +509,7 @@ func main() {
|
||||
func RandBoolSlice(length int) []bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/o-VSjPjnILI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -520,4 +523,29 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>生成指定长度的随机数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -106,6 +106,9 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -915,7 +918,7 @@ func main() {
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/t_pkwerIRVx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1192,7 +1195,7 @@ func main() {
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/kT4XW7DKVoV)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1570,7 +1573,7 @@ func main() {
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/H1ehfPkPen0)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1771,7 +1774,7 @@ func main() {
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Tjwe6OtaG07)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2449,7 +2452,7 @@ func main() {
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UR323iZLDpv)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GY7JE4yikrl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2480,7 +2483,7 @@ func main() {
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rwSacr-ZHsR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2516,7 +2519,7 @@ func main() {
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wXZ7LcYRMGL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2967,7 +2970,7 @@ func main() {
|
||||
func Frequency[T comparable](slice []T) map[T]int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CW3UVNdUZOq)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2984,4 +2987,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>将切片元素用给定的分隔符连接成一个单一的字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>将切片中的元素连接成一个值,使用指定的分隔符和连接器函数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,7 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#ExtractContent)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1547,7 +1548,7 @@ func main() {
|
||||
func Concat(length int, str ...string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gD52SZHr4Kp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1556,10 +1557,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result2 := strutil.Concat(11, "Go", " ", "Language")
|
||||
result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
@@ -1581,7 +1582,7 @@ func main() {
|
||||
func Ellipsis(str string, length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/i1vbdQiQVRR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1615,7 +1616,7 @@ func main() {
|
||||
func Shuffle(str string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iStFwBwyGY7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1639,7 +1640,7 @@ func main() {
|
||||
func Rotate(str string, shift int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Kf03iOeT5bd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1648,9 +1649,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Rotate("Hello", 0)
|
||||
result2 := Rotate("Hello", 1)
|
||||
result3 := Rotate("Hello", 2)
|
||||
result1 := strutil.Rotate("Hello", 0)
|
||||
result2 := strutil.Rotate("Hello", 1)
|
||||
result3 := strutil.Rotate("Hello", 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -1673,7 +1674,7 @@ func main() {
|
||||
func TemplateReplace(template string, data map[string]string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cXSuFvyZqv9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1707,7 +1708,7 @@ func main() {
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1728,4 +1729,34 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>提取两个标记之间的内容。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
@@ -324,7 +324,7 @@ func main() {
|
||||
func StartProcess(command string, args ...string) (int, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/5GVol6ryS_X)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -352,7 +352,7 @@ func main() {
|
||||
func StopProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/jJZhRYGGcmD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -386,7 +386,7 @@ func main() {
|
||||
func KillProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/XKmvV-ExBWa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -420,7 +420,7 @@ func main() {
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/NQDVywEYYx7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -167,12 +168,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -489,3 +490,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>简单实现的java风格异常处理(try-catch-finally)。try catch不符合go错误处理风格,谨慎使用。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error in try block")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -269,9 +270,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
|
||||
|
||||
> ⚠️ This function is deprecated. use `Ternary` instead.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
@@ -307,4 +344,3 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ import (
|
||||
- [GenerateRsaKeyPair](#GenerateRsaKeyPair)
|
||||
- [RsaEncryptOAEP](#RsaEncryptOAEP)
|
||||
- [RsaDecryptOAEP](#RsaDecryptOAEP)
|
||||
- [RsaSign](#RsaSign)
|
||||
- [RsaVerifySign](#RsaVerifySign)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -391,7 +393,7 @@ func main() {
|
||||
func AesGcmEncrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -425,7 +427,7 @@ func main() {
|
||||
func AesGcmDecrypt(data, key []byte) []byte
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rUt0-DmsPCs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1061,13 +1063,13 @@ import (
|
||||
|
||||
func main() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
hms := cryptor.HmacSha512WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||
// Output:
|
||||
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1124,10 +1126,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5StringWithBase64("hello")
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1153,10 +1155,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1182,10 +1184,10 @@ import (
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
|
||||
fmt.Println(md5Str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1268,10 +1270,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha1WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
// Output:
|
||||
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1328,10 +1330,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha256WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||
// Output:
|
||||
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1388,10 +1390,10 @@ import (
|
||||
|
||||
func main() {
|
||||
result := cryptor.Sha512WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||
// Output:
|
||||
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1607,3 +1609,81 @@ func main() {
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaSign">RsaSign</span>
|
||||
|
||||
<p>Signs the data with RSA algorithm.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RsaVerifySign">RsaVerifySign</span>
|
||||
|
||||
<p>Verifies the signature of the data with RSA algorithm.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private.pem"
|
||||
publicKey := "./rsa_public.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -68,6 +68,9 @@ import (
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -1480,7 +1483,7 @@ func main() {
|
||||
func TrackFuncTime(pre time.Time) func()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/QBSEdfXHPTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1512,7 +1515,7 @@ func main() {
|
||||
func DaysBetween(start, end time.Time) int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qD6qGb3TbOy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1545,7 +1548,7 @@ func main() {
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/6kHBpAxD9ZC)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1571,4 +1574,96 @@ func main() {
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>Returns the earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>Returns the latest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>Returns the latest and earliest time among the given times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
@@ -52,6 +52,7 @@ import (
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -559,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1074,4 +1075,37 @@ func main() {
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>Get the version of exe or dll file on windows.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(v)
|
||||
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -204,7 +204,7 @@ func main() {
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func())
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/-dGFrYn_1Zi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -752,7 +752,7 @@ func main() {
|
||||
func Throttle(fn func(), interval time.Duration) func()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/HpoMov-tJSN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -1167,7 +1167,7 @@ func main() {
|
||||
func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V]
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1206,7 +1206,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1245,7 +1245,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Y4ZJ_oOc1FU)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1285,7 +1285,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Delete(key K)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/5bIi4yaZ3K-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1321,7 +1321,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Clear()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8LwoJyEfuFr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1360,7 +1360,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ty57XSimpoe)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1400,7 +1400,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}, bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rQMjp1yQmpa)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1417,12 +1417,12 @@ func main() {
|
||||
om.Set("b", 2)
|
||||
om.Set("c", 3)
|
||||
|
||||
frontElement, ok := om.Front()
|
||||
fmt.Println(frontElement)
|
||||
backElement, ok := om.Back()
|
||||
fmt.Println(backElement)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// {a 1}
|
||||
// {c 3}
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1437,7 +1437,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/U-KpORhc7LZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1476,7 +1476,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Keys() []K
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Vv_y9ExKclA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1512,7 +1512,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Values() []V
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/TWj5n1-PUfx)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1548,7 +1548,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Elements() []struct
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/4BHG4kKz6bB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1584,7 +1584,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/cLe6z2VX5N-)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1620,7 +1620,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/QuwqqnzwDNX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1662,7 +1662,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tlq2tdvicPt)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1703,7 +1703,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8Q0ssg6hZzO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1741,7 +1741,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/N7hjD_alZPq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1752,7 +1752,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1780,7 +1780,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/C-wAwydIAC7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1791,7 +1791,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
om := maputil.NewOrderedMap[string, int]()
|
||||
om := maputil.NewOrderedMap[int, string]()
|
||||
|
||||
om.Set(3, "c")
|
||||
om.Set(1, "a")
|
||||
@@ -1817,7 +1817,7 @@ func main() {
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8C3MvJ3-mut)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1837,6 +1837,7 @@ func main() {
|
||||
fmt.Println(om.Elements())
|
||||
|
||||
// Output:
|
||||
// [{a 1} {b 2} {c 3}]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2256,7 +2257,7 @@ func main() {
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V) (sortedKeysMap map[K]V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/PVdmBSnm6P_W)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -2274,7 +2275,9 @@ func main() {
|
||||
2: "b",
|
||||
}
|
||||
|
||||
result := maputil.SortByKey(m)
|
||||
result := maputil.SortByKey(m, func(a, b int) bool {
|
||||
return a < b
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
@@ -2293,7 +2296,7 @@ func main() {
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/99QjSYSBdiM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -133,7 +134,7 @@ func main() {
|
||||
func RandFromGivenSlice[T any](slice []T) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UrkWueF6yYo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -160,7 +161,7 @@ func main() {
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/68UikN9d6VT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -171,8 +172,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange"}
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange"}
|
||||
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
|
||||
fmt.Println(chosen3goods)
|
||||
}
|
||||
```
|
||||
@@ -346,7 +349,7 @@ func main() {
|
||||
func RandIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GATTQ5xTEG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -452,7 +455,7 @@ func main() {
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/2_-PiDv3tGn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -481,7 +484,7 @@ func main() {
|
||||
func RandBool() bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/to6BLc26wBv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -507,7 +510,7 @@ func main() {
|
||||
func RandBoolSlice(length int) []bool
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/o-VSjPjnILI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -521,4 +524,30 @@ func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>Generates a random int number of specified length.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>Signature:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
@@ -106,6 +106,10 @@ import (
|
||||
- [RightPadding](#RightPadding)
|
||||
- [LeftPadding](#LeftPadding)
|
||||
- [Frequency](#Frequency)
|
||||
- [JoinFunc](#JoinFunc)
|
||||
- [ConcatBy](#ConcatBy)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -913,7 +917,7 @@ func main() {
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/t_pkwerIRVx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1190,7 +1194,7 @@ func main() {
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/kT4XW7DKVoV)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1567,7 +1571,7 @@ func main() {
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/H1ehfPkPen0)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1766,7 +1770,7 @@ func main() {
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Tjwe6OtaG07)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2445,7 +2449,7 @@ func main() {
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/UR323iZLDpv)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GY7JE4yikrl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2476,7 +2480,7 @@ func main() {
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/rwSacr-ZHsR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2512,7 +2516,7 @@ func main() {
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Runs](https://go.dev/play/p/wXZ7LcYRMGL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2962,7 +2966,7 @@ func main() {
|
||||
func Frequency[T comparable](slice []T) map[T]int
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/CW3UVNdUZOq)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2979,4 +2983,81 @@ func main() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="JoinFunc">JoinFunc</span>
|
||||
|
||||
<p>Joins the slice elements into a single string with the given separator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := slice.JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ConcatBy">ConcatBy</span>
|
||||
|
||||
<p>Concats the elements of a slice into a single value using the provided separator and connector function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := slice.ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
```
|
||||
@@ -68,6 +68,8 @@ import (
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#RegexMatchAllGroups)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -1549,7 +1551,7 @@ func main() {
|
||||
func Concat(length int, str ...string) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/gD52SZHr4Kp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1561,6 +1563,7 @@ func main() {
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result2 := strutil.Concat(11, "Go", " ", "Language")
|
||||
result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
@@ -1582,7 +1585,7 @@ func main() {
|
||||
func Ellipsis(str string, length int) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/i1vbdQiQVRR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1616,7 +1619,7 @@ func main() {
|
||||
func Shuffle(str string) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/iStFwBwyGY7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1640,7 +1643,7 @@ func main() {
|
||||
func Rotate(str string, shift int) string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Kf03iOeT5bd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1673,7 +1676,7 @@ func main() {
|
||||
func TemplateReplace(template string, data map[string]string string
|
||||
```
|
||||
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/cXSuFvyZqv9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1707,7 +1710,7 @@ func main() {
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1728,4 +1731,34 @@ func main() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>Extracts the content between the start and end strings in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
@@ -325,7 +325,7 @@ func main() {
|
||||
func StartProcess(command string, args ...string) (int, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/5GVol6ryS_X)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -353,7 +353,7 @@ func main() {
|
||||
func StopProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/jJZhRYGGcmD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -387,7 +387,7 @@ func main() {
|
||||
func KillProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/XKmvV-ExBWa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -421,7 +421,7 @@ func main() {
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/NQDVywEYYx7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -166,12 +167,12 @@ import (
|
||||
|
||||
func main() {
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(err2.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: invalid username
|
||||
// Output:
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -487,3 +488,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>Simple simulation of Java-style try-catch. It does not align with Go's error-handling philosophy. It is recommended to use it with caution.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error message ")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.1. </b>
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.4. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -10,7 +10,7 @@ outline: deep
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.1。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.4。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
@@ -23,8 +24,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
// FileReader is a reader supporting offset seeking and reading one
|
||||
|
||||
@@ -192,6 +192,27 @@ func ExampleListFileNames() {
|
||||
// [assert.go assert_test.go error_join.go]
|
||||
}
|
||||
|
||||
func ExampleMiMeType() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
@@ -214,24 +235,20 @@ func ExampleZip() {
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
zipFile := "./testdata/file.go.zip"
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
err := UnZip(zipFile, "./testdata")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
exist := IsExist("./testdata/file.go")
|
||||
fmt.Println(exist)
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
os.Remove("./testdata/file.go")
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleZipAppendEntry() {
|
||||
|
||||
83
fileutil/file_windows.go
Normal file
83
fileutil/file_windows.go
Normal file
@@ -0,0 +1,83 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// tagVS_FIXEDFILEINFO 参考结构体https://learn.microsoft.com/zh-cn/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||
type tagVS_FIXEDFILEINFO struct {
|
||||
Signature uint32
|
||||
StructVersion uint32
|
||||
FileVersionMS uint32
|
||||
FileVersionLS uint32
|
||||
ProductVersionMS uint32
|
||||
ProductVersionLS uint32
|
||||
FileFlagsMask uint32
|
||||
FileFlags uint32
|
||||
FileOS uint32
|
||||
FileType uint32
|
||||
FileSubtype uint32
|
||||
FileDateMS uint32
|
||||
FileDateLS uint32
|
||||
}
|
||||
|
||||
// GetExeOrDllVersion get the version of exe or dll file on windows.
|
||||
// Play: todo
|
||||
func GetExeOrDllVersion(filePath string) (string, error) {
|
||||
// 加载系统dll
|
||||
versionDLL := syscall.NewLazyDLL("version.dll")
|
||||
getFileVersionInfoSize := versionDLL.NewProc("GetFileVersionInfoSizeW")
|
||||
getFileVersionInfo := versionDLL.NewProc("GetFileVersionInfoW")
|
||||
verQueryValue := versionDLL.NewProc("VerQueryValueW")
|
||||
|
||||
// 转换路径为UTF-16
|
||||
filePathPtr, err := syscall.UTF16PtrFromString(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
|
||||
// 获取version信息大小
|
||||
size, _, err := getFileVersionInfoSize.Call(
|
||||
uintptr(unsafe.Pointer(filePathPtr)),
|
||||
0,
|
||||
)
|
||||
if size == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information size: %v", err)
|
||||
}
|
||||
|
||||
// 加载version信息
|
||||
data := make([]byte, size)
|
||||
ret, _, err := getFileVersionInfo.Call(uintptr(unsafe.Pointer(filePathPtr)), 0, size, uintptr(unsafe.Pointer(&data[0])))
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to obtain version information: %v", err)
|
||||
}
|
||||
|
||||
// 查询version信息
|
||||
var fixedInfo *tagVS_FIXEDFILEINFO
|
||||
var fixedInfoLen uint32
|
||||
u16, err := syscall.UTF16PtrFromString(`\`)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
|
||||
}
|
||||
ret, _, err = verQueryValue.Call(
|
||||
uintptr(unsafe.Pointer(&data[0])),
|
||||
uintptr(unsafe.Pointer(u16)),
|
||||
uintptr(unsafe.Pointer(&fixedInfo)),
|
||||
uintptr(unsafe.Pointer(&fixedInfoLen)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return "", fmt.Errorf("unable to query version information: %v", err)
|
||||
}
|
||||
|
||||
// 转换结构体
|
||||
major := fixedInfo.FileVersionMS >> 16
|
||||
minor := fixedInfo.FileVersionMS & 0xFFFF
|
||||
build := fixedInfo.FileVersionLS >> 16
|
||||
revision := fixedInfo.FileVersionLS & 0xFFFF
|
||||
|
||||
return fmt.Sprintf("%d.%d.%d.%d", major, minor, build, revision), nil
|
||||
}
|
||||
13
fileutil/file_windows_test.go
Normal file
13
fileutil/file_windows_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetExeOrDllVersion(t *testing.T) {
|
||||
v, err := GetExeOrDllVersion(`C:\Windows\System32\cmd.exe`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(v)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ func Debounced(fn func(), delay time.Duration) func() {
|
||||
}
|
||||
|
||||
// Debounce creates a debounced version of the provided function.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/-dGFrYn_1Zi
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func()) {
|
||||
var (
|
||||
timer *time.Timer
|
||||
@@ -127,7 +127,7 @@ func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func
|
||||
|
||||
// Throttle creates a throttled version of the provided function.
|
||||
// The returned function guarantees that it will only be invoked at most once per interval.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/HpoMov-tJSN
|
||||
func Throttle(fn func(), interval time.Duration) func() {
|
||||
var (
|
||||
timer *time.Timer
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1,6 +1,4 @@
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
|
||||
@@ -455,7 +455,7 @@ func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V {
|
||||
}
|
||||
|
||||
// SortByKey sorts the map by its keys and returns a new map with sorted keys.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/PVdmBSnm6P_W
|
||||
func SortByKey[K constraints.Ordered, V any](m map[K]V, less func(a, b K) bool) (sortedKeysMap map[K]V) {
|
||||
keys := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
@@ -659,7 +659,7 @@ func convertMap(src reflect.Value, dst reflect.Value) error {
|
||||
}
|
||||
|
||||
// GetOrDefault returns the value of the given key or a default value if the key is not present.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/99QjSYSBdiM
|
||||
func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V {
|
||||
if v, ok := m[key]; ok {
|
||||
return v
|
||||
|
||||
@@ -29,13 +29,13 @@ func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
|
||||
}
|
||||
|
||||
// Sets the given key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Y4ZJ_oOc1FU
|
||||
func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
if elem, ok := om.index[key]; ok {
|
||||
elem.Value = value
|
||||
om.data[key] = value
|
||||
om.order.MoveToBack(elem)
|
||||
|
||||
return
|
||||
@@ -48,7 +48,7 @@ func (om *OrderedMap[K, V]) Set(key K, value V) {
|
||||
}
|
||||
|
||||
// Get returns the value for the given key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Y4ZJ_oOc1FU
|
||||
func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -59,7 +59,7 @@ func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
|
||||
}
|
||||
|
||||
// Delete deletes the given key.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/5bIi4yaZ3K-
|
||||
func (om *OrderedMap[K, V]) Delete(key K) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -72,7 +72,7 @@ func (om *OrderedMap[K, V]) Delete(key K) {
|
||||
}
|
||||
|
||||
// Clear clears the map.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8LwoJyEfuFr
|
||||
func (om *OrderedMap[K, V]) Clear() {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -83,7 +83,7 @@ func (om *OrderedMap[K, V]) Clear() {
|
||||
}
|
||||
|
||||
// Front returns the first key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/ty57XSimpoe
|
||||
func (om *OrderedMap[K, V]) Front() (struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -111,7 +111,7 @@ func (om *OrderedMap[K, V]) Front() (struct {
|
||||
}
|
||||
|
||||
// Back returns the last key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rQMjp1yQmpa
|
||||
func (om *OrderedMap[K, V]) Back() (struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -139,7 +139,7 @@ func (om *OrderedMap[K, V]) Back() (struct {
|
||||
}
|
||||
|
||||
// Range calls the given function for each key-value pair.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/U-KpORhc7LZ
|
||||
func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -155,7 +155,7 @@ func (om *OrderedMap[K, V]) Range(iteratee func(key K, value V) bool) {
|
||||
}
|
||||
|
||||
// Keys returns the keys in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Vv_y9ExKclA
|
||||
func (om *OrderedMap[K, V]) Keys() []K {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -170,7 +170,7 @@ func (om *OrderedMap[K, V]) Keys() []K {
|
||||
}
|
||||
|
||||
// Values returns the values in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/TWj5n1-PUfx
|
||||
func (om *OrderedMap[K, V]) Values() []V {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -186,7 +186,7 @@ func (om *OrderedMap[K, V]) Values() []V {
|
||||
}
|
||||
|
||||
// Len returns the number of key-value pairs.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/cLe6z2VX5N-
|
||||
func (om *OrderedMap[K, V]) Len() int {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -195,7 +195,7 @@ func (om *OrderedMap[K, V]) Len() int {
|
||||
}
|
||||
|
||||
// Contains returns true if the given key exists.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/QuwqqnzwDNX
|
||||
func (om *OrderedMap[K, V]) Contains(key K) bool {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -206,7 +206,7 @@ func (om *OrderedMap[K, V]) Contains(key K) bool {
|
||||
}
|
||||
|
||||
// Elements returns the key-value pairs in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/4BHG4kKz6bB
|
||||
func (om *OrderedMap[K, V]) Elements() []struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -232,7 +232,7 @@ func (om *OrderedMap[K, V]) Elements() []struct {
|
||||
}
|
||||
|
||||
// Iter returns a channel that yields key-value pairs in order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/tlq2tdvicPt
|
||||
func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -262,7 +262,7 @@ func (om *OrderedMap[K, V]) Iter() <-chan struct {
|
||||
}
|
||||
|
||||
// ReverseIter returns a channel that yields key-value pairs in reverse order.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8Q0ssg6hZzO
|
||||
func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
Key K
|
||||
Value V
|
||||
@@ -292,7 +292,7 @@ func (om *OrderedMap[K, V]) ReverseIter() <-chan struct {
|
||||
}
|
||||
|
||||
// SortByValue sorts the map by key given less function.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/N7hjD_alZPq
|
||||
func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool) {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
@@ -315,7 +315,7 @@ func (om *OrderedMap[K, V]) SortByKey(less func(a, b K) bool) {
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/C-wAwydIAC7
|
||||
func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error) {
|
||||
om.mu.RLock()
|
||||
defer om.mu.RUnlock()
|
||||
@@ -334,7 +334,7 @@ func (om *OrderedMap[K, V]) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/8C3MvJ3-mut
|
||||
func (om *OrderedMap[K, V]) UnmarshalJSON(data []byte) error {
|
||||
om.mu.Lock()
|
||||
defer om.mu.Unlock()
|
||||
|
||||
@@ -19,6 +19,10 @@ func TestOrderedMap_Set_Get(t *testing.T) {
|
||||
assert.Equal(1, val)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
om.Set("a", 2)
|
||||
val, _ = om.Get("a")
|
||||
assert.Equal(2, val)
|
||||
|
||||
val, ok = om.Get("d")
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(0, val)
|
||||
|
||||
@@ -221,6 +221,22 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AsyncSendRequest send http request with goroutine, pop response and error to channels
|
||||
func (client *HttpClient) AsyncSendRequest(request *HttpRequest, respChan chan *http.Response, errChan chan error) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
errChan <- fmt.Errorf("%v", err)
|
||||
}
|
||||
}()
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
respChan <- resp
|
||||
}()
|
||||
}
|
||||
|
||||
// DecodeResponse decode response into target object.
|
||||
// Play: https://go.dev/play/p/jUSgynekH7G
|
||||
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
|
||||
|
||||
@@ -373,6 +373,45 @@ func TestSendRequestWithFilePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpClient_AsyncSendRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHttpClient_Get")
|
||||
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
respCh := make(chan *http.Response, 20)
|
||||
errCh := make(chan error, 20)
|
||||
for i := 0; i < 50; i++ {
|
||||
httpClient.AsyncSendRequest(request, respCh, errCh)
|
||||
}
|
||||
for i := 0; i < 50; i++ {
|
||||
select {
|
||||
case resp := <-respCh:
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Id int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
var todo Todo
|
||||
err := httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
assert.Equal(1, todo.Id)
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Log("net error: ", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy(t *testing.T) {
|
||||
config := &HttpClientConfig{
|
||||
HandshakeTimeout: 20 * time.Second,
|
||||
|
||||
@@ -33,13 +33,13 @@ func init() {
|
||||
}
|
||||
|
||||
// RandBool generates a random boolean value (true or false).
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/to6BLc26wBv
|
||||
func RandBool() bool {
|
||||
return rand.Intn(2) == 1
|
||||
}
|
||||
|
||||
// RandBoolSlice generates a random boolean slice of specified length.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/o-VSjPjnILI
|
||||
func RandBoolSlice(length int) []bool {
|
||||
if length <= 0 {
|
||||
return []bool{}
|
||||
@@ -73,7 +73,7 @@ func RandInt(min, max int) int {
|
||||
|
||||
// RandIntSlice generates a slice of random integers.
|
||||
// The generated integers are between min and max (exclusive).
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/GATTQ5xTEG8
|
||||
func RandIntSlice(length, min, max int) []int {
|
||||
if length <= 0 || min > max {
|
||||
return []int{}
|
||||
@@ -170,7 +170,7 @@ func RandString(length int) string {
|
||||
// RandString generate a slice of random string of length strLen based on charset.
|
||||
// chartset should be one of the following: random.Numeral, random.LowwerLetters, random.UpperLetters
|
||||
// random.Letters, random.SymbolChars, random.AllChars. or a combination of them.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/2_-PiDv3tGn
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string {
|
||||
if sliceLen <= 0 || strLen <= 0 {
|
||||
return []string{}
|
||||
@@ -186,7 +186,7 @@ func RandStringSlice(charset string, sliceLen, strLen int) []string {
|
||||
}
|
||||
|
||||
// RandFromGivenSlice generate a random element from given slice.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/UrkWueF6yYo
|
||||
func RandFromGivenSlice[T any](slice []T) T {
|
||||
if len(slice) == 0 {
|
||||
var zero T
|
||||
@@ -198,7 +198,7 @@ func RandFromGivenSlice[T any](slice []T) T {
|
||||
// RandSliceFromGivenSlice generate a random slice of length num from given slice.
|
||||
// - If repeatable is true, the generated slice may contain duplicate elements.
|
||||
//
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/68UikN9d6VT
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T {
|
||||
if num <= 0 || len(slice) == 0 {
|
||||
return slice
|
||||
@@ -327,3 +327,13 @@ func UUIdV4() (string, error) {
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
||||
|
||||
// RandNumberOfLength 生成一个长度为len的随机数
|
||||
// Play: todo
|
||||
func RandNumberOfLength(len int) int {
|
||||
m := int(math.Pow10(len) - 1)
|
||||
i := int(math.Pow10(len - 1))
|
||||
ret := rand.Intn(m-i+1) + i
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package random
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -361,3 +362,9 @@ func TestRandBoolSlice(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
func TestRandNumberOfLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
randi := RandNumberOfLength(6)
|
||||
assert := internal.NewAssert(t, "TestRandNumberOfLength")
|
||||
assert.Equal(6, len(strconv.Itoa(randi)))
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
var (
|
||||
memoryHashMap = make(map[string]map[any]int)
|
||||
memoryHashCounter = make(map[string]int)
|
||||
muForMemoryHash sync.RWMutex
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not.
|
||||
@@ -789,7 +791,7 @@ func Unique[T comparable](slice []T) []T {
|
||||
|
||||
// UniqueBy removes duplicate elements from the input slice based on the values returned by the iteratee function.
|
||||
// The function maintains the order of the elements.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/GY7JE4yikrl
|
||||
func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
||||
result := make([]T, 0, len(slice))
|
||||
seen := make(map[U]struct{}, len(slice))
|
||||
@@ -810,7 +812,7 @@ func UniqueBy[T any, U comparable](slice []T, iteratee func(item T) U) []T {
|
||||
|
||||
// UniqueByComparator removes duplicate elements from the input slice using the provided comparator function.
|
||||
// The function maintains the order of the elements.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/rwSacr-ZHsR
|
||||
func UniqueByComparator[T comparable](slice []T, comparator func(item T, other T) bool) []T {
|
||||
result := make([]T, 0, len(slice))
|
||||
seen := make([]T, 0, len(slice))
|
||||
@@ -1174,23 +1176,46 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
limit := 10
|
||||
// gets the hash value of the array as the key of the hash table.
|
||||
key := fmt.Sprintf("%p", arr)
|
||||
|
||||
muForMemoryHash.RLock()
|
||||
// determines whether the hash table is empty. If so, the hash table is created.
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
|
||||
muForMemoryHash.RUnlock()
|
||||
muForMemoryHash.Lock()
|
||||
|
||||
if memoryHashMap[key] == nil {
|
||||
memoryHashMap[key] = make(map[any]int)
|
||||
// iterate through the array, adding the value and index of each element to the hash table.
|
||||
for i := len(arr) - 1; i >= 0; i-- {
|
||||
memoryHashMap[key][arr[i]] = i
|
||||
}
|
||||
}
|
||||
|
||||
muForMemoryHash.Unlock()
|
||||
} else {
|
||||
muForMemoryHash.RUnlock()
|
||||
}
|
||||
|
||||
muForMemoryHash.Lock()
|
||||
// update the hash table counter.
|
||||
memoryHashCounter[key]++
|
||||
muForMemoryHash.Unlock()
|
||||
|
||||
// use the hash table to find the specified value. If found, the index is returned.
|
||||
if index, ok := memoryHashMap[key][val]; ok {
|
||||
muForMemoryHash.RLock()
|
||||
index, ok := memoryHashMap[key][val]
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
if ok {
|
||||
muForMemoryHash.RLock()
|
||||
// calculate the memory usage of the hash table.
|
||||
size := len(memoryHashMap)
|
||||
muForMemoryHash.RUnlock()
|
||||
|
||||
// If the memory usage of the hash table exceeds the memory limit, the hash table with the lowest counter is cleared.
|
||||
if size > limit {
|
||||
muForMemoryHash.Lock()
|
||||
var minKey string
|
||||
var minVal int
|
||||
for k, v := range memoryHashCounter {
|
||||
@@ -1204,6 +1229,7 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
}
|
||||
delete(memoryHashMap, minKey)
|
||||
delete(memoryHashCounter, minKey)
|
||||
muForMemoryHash.Unlock()
|
||||
}
|
||||
return index
|
||||
}
|
||||
@@ -1388,7 +1414,7 @@ func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||
}
|
||||
|
||||
// Frequency counts the frequency of each element in the slice.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/CW3UVNdUZOq
|
||||
func Frequency[T comparable](slice []T) map[T]int {
|
||||
result := make(map[T]int)
|
||||
|
||||
@@ -1398,3 +1424,35 @@ func Frequency[T comparable](slice []T) map[T]int {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// JoinFunc joins the slice elements into a single string with the given separator.
|
||||
// Play: todo
|
||||
func JoinFunc[T any](slice []T, sep string, transform func(T) T) string {
|
||||
var buf strings.Builder
|
||||
for i, v := range slice {
|
||||
if i > 0 {
|
||||
buf.WriteString(sep)
|
||||
}
|
||||
buf.WriteString(fmt.Sprint(transform(v)))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ConcatBy concats the elements of a slice into a single value using the provided separator and connector function.
|
||||
// Play: todo
|
||||
func ConcatBy[T any](slice []T, sep T, connector func(T, T) T) T {
|
||||
var result T
|
||||
|
||||
if len(slice) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
for i, v := range slice {
|
||||
result = connector(result, v)
|
||||
if i < len(slice)-1 {
|
||||
result = connector(result, sep)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// ForEachConcurrent applies the iteratee function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/kT4XW7DKVoV
|
||||
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int) {
|
||||
sliceLen := len(slice)
|
||||
if sliceLen == 0 {
|
||||
@@ -50,7 +50,7 @@ func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numTh
|
||||
}
|
||||
|
||||
// MapConcurrent applies the iteratee function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/H1ehfPkPen0
|
||||
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U {
|
||||
result := make([]U, len(slice))
|
||||
var wg sync.WaitGroup
|
||||
@@ -77,7 +77,7 @@ func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U,
|
||||
}
|
||||
|
||||
// ReduceConcurrent reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Tjwe6OtaG07
|
||||
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T {
|
||||
if numThreads <= 0 {
|
||||
numThreads = 1
|
||||
@@ -121,7 +121,7 @@ func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item
|
||||
}
|
||||
|
||||
// FilterConcurrent applies the provided filter function `predicate` to each element of the input slice concurrently.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/t_pkwerIRVx
|
||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
|
||||
result := make([]T, 0)
|
||||
var wg sync.WaitGroup
|
||||
@@ -149,12 +149,12 @@ func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool,
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqueByParallel removes duplicate elements from the slice by parallel
|
||||
// UniqueByConcurrent removes duplicate elements from the slice by parallel
|
||||
// The comparator function is used to compare the elements
|
||||
// The numThreads parameter specifies the number of threads to use
|
||||
// If numThreads is less than or equal to 0, it will be set to 1
|
||||
// The comparator function should return true if the two elements are equal
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/wXZ7LcYRMGL
|
||||
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T {
|
||||
if numThreads <= 0 {
|
||||
numThreads = 1
|
||||
@@ -195,18 +195,14 @@ func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T
|
||||
chunks = append(chunks, slice[i:end])
|
||||
}
|
||||
|
||||
type resultChunk struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
resultCh := make(chan resultChunk, numThreads)
|
||||
resultCh := make(chan resultChunk[T], numThreads)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i, chunk := range chunks {
|
||||
wg.Add(1)
|
||||
go func(index int, chunk []T) {
|
||||
defer wg.Done()
|
||||
resultCh <- resultChunk{index, removeDuplicate(chunk, comparator)}
|
||||
resultCh <- resultChunk[T]{index, removeDuplicate(chunk, comparator)}
|
||||
}(i, chunk)
|
||||
}
|
||||
|
||||
|
||||
@@ -1261,3 +1261,42 @@ func ExampleFrequency() {
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
}
|
||||
|
||||
func ExampleJoinFunc() {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// A, B, C
|
||||
}
|
||||
|
||||
func ExampleConcatBy() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
fmt.Println(result.Name)
|
||||
fmt.Println(result.Age)
|
||||
|
||||
// Output:
|
||||
// Alice | Bob | Charlie
|
||||
// 90
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ import (
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// resultChunk is used to store the intermediate results of UniqueByConcurrent.
|
||||
// It is defined separately to be compatible with versions of go up to 1.20.
|
||||
type resultChunk[T comparable] struct {
|
||||
index int
|
||||
data []T
|
||||
}
|
||||
|
||||
// sliceValue return the reflect value of a slice
|
||||
func sliceValue(slice any) reflect.Value {
|
||||
v := reflect.ValueOf(slice)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -1367,6 +1368,37 @@ func TestIndexOf(t *testing.T) {
|
||||
assert.Equal(-1, IndexOf(arr3, "r"))
|
||||
assert.Equal(2, memoryHashCounter[key3])
|
||||
assert.Equal(0, memoryHashCounter[minKey])
|
||||
|
||||
arr4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
const numGoroutines = 100
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
index := IndexOf(arr4, i%10+1)
|
||||
assert.Equal(i%10, index)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkIndexOfDifferentSizes(b *testing.B) {
|
||||
sizes := []int{10, 100, 1000, 10000, 100000}
|
||||
for _, size := range sizes {
|
||||
arr := make([]int, size)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arr[i] = i
|
||||
}
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_ = IndexOf(arr, size/2) // 查找数组中间的元素
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastIndexOf(t *testing.T) {
|
||||
@@ -1816,3 +1848,81 @@ func TestFrequency(t *testing.T) {
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestJoinFunc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestJoinFunc")
|
||||
|
||||
t.Run("basic case", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1, 2, 3}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
expected := "2, 4, 6"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("empty slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("", result)
|
||||
})
|
||||
|
||||
t.Run("single element slice", func(t *testing.T) {
|
||||
result := JoinFunc([]int{1}, ", ", func(i int) int {
|
||||
return i * 2
|
||||
})
|
||||
|
||||
assert.Equal("2", result)
|
||||
})
|
||||
|
||||
t.Run("string slice", func(t *testing.T) {
|
||||
result := JoinFunc([]string{"a", "b", "c"}, ", ", func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
})
|
||||
|
||||
expected := "A, B, C"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConcatBy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestConcatBy")
|
||||
|
||||
t.Run("Join strings", func(t *testing.T) {
|
||||
result := ConcatBy([]string{"Hello", "World"}, ", ", func(a, b string) string {
|
||||
return a + b
|
||||
})
|
||||
|
||||
expected := "Hello, World"
|
||||
assert.Equal(expected, result)
|
||||
})
|
||||
|
||||
t.Run("Join Person struct", func(t *testing.T) {
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
people := []Person{
|
||||
{Name: "Alice", Age: 30},
|
||||
{Name: "Bob", Age: 25},
|
||||
{Name: "Charlie", Age: 35},
|
||||
}
|
||||
sep := Person{Name: " | ", Age: 0}
|
||||
|
||||
personConnector := func(a, b Person) Person {
|
||||
return Person{Name: a.Name + b.Name, Age: a.Age + b.Age}
|
||||
}
|
||||
|
||||
result := ConcatBy(people, sep, personConnector)
|
||||
|
||||
assert.Equal("Alice | Bob | Charlie", result.Name)
|
||||
assert.Equal(90, result.Age)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -627,7 +627,7 @@ func HammingDistance(a, b string) (int, error) {
|
||||
// - `length` is the expected length of the concatenated string.
|
||||
// - if you are unsure about the length of the string to be concatenated, please pass 0 or a negative number.
|
||||
//
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/gD52SZHr4Kp
|
||||
func Concat(length int, str ...string) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
@@ -647,7 +647,7 @@ func Concat(length int, str ...string) string {
|
||||
}
|
||||
|
||||
// Ellipsis truncates a string to a specified length and appends an ellipsis.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/i1vbdQiQVRR
|
||||
func Ellipsis(str string, length int) string {
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
@@ -665,7 +665,7 @@ func Ellipsis(str string, length int) string {
|
||||
}
|
||||
|
||||
// Shuffle the order of characters of given string.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/iStFwBwyGY7
|
||||
func Shuffle(str string) string {
|
||||
runes := []rune(str)
|
||||
|
||||
@@ -678,7 +678,7 @@ func Shuffle(str string) string {
|
||||
}
|
||||
|
||||
// Rotate rotates the string by the specified number of characters.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/Kf03iOeT5bd
|
||||
func Rotate(str string, shift int) string {
|
||||
if shift == 0 {
|
||||
return str
|
||||
@@ -709,7 +709,7 @@ func Rotate(str string, shift int) string {
|
||||
// The placeholders are enclosed in curly braces, e.g. {key}.
|
||||
// for example, the template string is "Hello, {name}!", and the data map is {"name": "world"},
|
||||
// the result will be "Hello, world!".
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/cXSuFvyZqv9
|
||||
func TemplateReplace(template string, data map[string]string) string {
|
||||
re := regexp.MustCompile(`\{(\w+)\}`)
|
||||
|
||||
@@ -729,9 +729,30 @@ func TemplateReplace(template string, data map[string]string) string {
|
||||
}
|
||||
|
||||
// RegexMatchAllGroups Matches all subgroups in a string using a regular expression and returns the result.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/JZiu0RXpgN-
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string {
|
||||
re := regexp.MustCompile(pattern)
|
||||
matches := re.FindAllStringSubmatch(str, -1)
|
||||
return matches
|
||||
}
|
||||
|
||||
// ExtractContent extracts the content between the start and end strings in the source string.
|
||||
// Play: todo
|
||||
func ExtractContent(s, start, end string) []string {
|
||||
result := []string{}
|
||||
|
||||
for {
|
||||
if _, after, ok := strings.Cut(s, start); ok {
|
||||
if before, _, ok := strings.Cut(after, end); ok {
|
||||
result = append(result, before)
|
||||
s = after
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -753,3 +753,15 @@ func ExampleRegexMatchAllGroups() {
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
|
||||
func ExampleExtractContent() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
|
||||
}
|
||||
|
||||
@@ -853,3 +853,87 @@ func TestRegexMatchAllGroups(t *testing.T) {
|
||||
assert.Equal(tt.expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestExtractContent")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
start string
|
||||
end string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "Extract content between <tag> and </tag>",
|
||||
input: "This is <tag>content1</tag> and <tag>content2</tag> and <tag>content3</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content1", "content2", "content3"},
|
||||
},
|
||||
{
|
||||
name: "No tags in the string",
|
||||
input: "This string has no tags",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Single tag pair",
|
||||
input: "<tag>onlyContent</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"onlyContent"},
|
||||
},
|
||||
{
|
||||
name: "Tags without end tag",
|
||||
input: "This <tag>content without end tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Tags with nested content",
|
||||
input: "<tag>content <nested>inner</nested> end</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content <nested>inner</nested> end"},
|
||||
},
|
||||
{
|
||||
name: "Edge case with empty string",
|
||||
input: "",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Edge case with no start tag",
|
||||
input: "content without start tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Edge case with no end tag",
|
||||
input: "<tag>content without end tag",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "Multiple consecutive tags",
|
||||
input: "<tag>content1</tag><tag>content2</tag><tag>content3</tag>",
|
||||
start: "<tag>",
|
||||
end: "</tag>",
|
||||
expected: []string{"content1", "content2", "content3"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := ExtractContent(tt.input, tt.start, tt.end)
|
||||
assert.Equal(tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ func GetOsBits() int {
|
||||
}
|
||||
|
||||
// StartProcess start a new process with the specified name and arguments.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/5GVol6ryS_X
|
||||
func StartProcess(command string, args ...string) (int, error) {
|
||||
cmd := exec.Command(command, args...)
|
||||
|
||||
@@ -149,7 +149,7 @@ func StartProcess(command string, args ...string) (int, error) {
|
||||
}
|
||||
|
||||
// StopProcess stop a process by pid.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/jJZhRYGGcmD
|
||||
func StopProcess(pid int) error {
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
@@ -160,7 +160,7 @@ func StopProcess(pid int) error {
|
||||
}
|
||||
|
||||
// KillProcess kill a process by pid.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/XKmvV-ExBWa
|
||||
func KillProcess(pid int) error {
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
@@ -186,7 +186,7 @@ type ProcessInfo struct {
|
||||
}
|
||||
|
||||
// GetProcessInfo retrieves detailed process information by pid.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/NQDVywEYYx7
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
|
||||
100
xerror/trycatch.go
Normal file
100
xerror/trycatch.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// TryCatch is a struct to handle try-catch-finally block.
|
||||
// This implementation is merely a simulation of Java-style try-catch and does not align with Go's error-handling philosophy. It is recommended to use it with caution.
|
||||
type TryCatch struct {
|
||||
ctx context.Context
|
||||
tryFunc func(ctx context.Context) error
|
||||
catchFunc func(ctx context.Context, err error)
|
||||
finallyFunc func(ctx context.Context)
|
||||
}
|
||||
|
||||
// NewTryCatch creates a new TryCatch instance.
|
||||
func NewTryCatch(ctx context.Context) *TryCatch {
|
||||
return &TryCatch{
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// Try sets the try function.
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch {
|
||||
tc.tryFunc = tryFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Catch sets the catch function.
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch {
|
||||
tc.catchFunc = catchFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Finally sets the finally function.
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch {
|
||||
tc.finallyFunc = finallyFunc
|
||||
return tc
|
||||
}
|
||||
|
||||
// Do executes the try-catch-finally block.
|
||||
func (tc *TryCatch) Do() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if tc.catchFunc != nil {
|
||||
err := fmt.Errorf("panic: %v", r)
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(err, "Recovered from panic"))
|
||||
}
|
||||
}
|
||||
|
||||
if tc.finallyFunc != nil {
|
||||
tc.finallyFunc(tc.ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
if tc.ctx.Err() != nil {
|
||||
if tc.catchFunc != nil {
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(tc.ctx.Err(), "Context cancelled or timed out"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if tc.tryFunc != nil {
|
||||
if err := tc.tryFunc(tc.ctx); err != nil {
|
||||
if tc.catchFunc != nil {
|
||||
tc.catchFunc(tc.ctx, WrapCatchError(err, "Error in try block"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CatchError is an error type to handle try-catch-finally block.
|
||||
type CatchError struct {
|
||||
Msg string
|
||||
File string
|
||||
Line int
|
||||
Cause error
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (e *CatchError) Error() string {
|
||||
return fmt.Sprintf("%s at %s:%d - Cause: %v", e.Msg, e.File, e.Line, e.Cause)
|
||||
}
|
||||
|
||||
// WrapCatchError wraps an error with message, file, and line.
|
||||
func WrapCatchError(err error, msg string) *CatchError {
|
||||
_, file, line, ok := runtime.Caller(2)
|
||||
if !ok {
|
||||
file = "unknown"
|
||||
line = 0
|
||||
}
|
||||
return &CatchError{
|
||||
Msg: msg,
|
||||
File: file,
|
||||
Line: line,
|
||||
Cause: err,
|
||||
}
|
||||
}
|
||||
172
xerror/trycatch_test.go
Normal file
172
xerror/trycatch_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestTryCatchSuccess(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchSuccess")
|
||||
|
||||
counter := 0
|
||||
calledCatch := false
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
counter++
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
t.Errorf("Catch should not be called")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal(1, counter)
|
||||
assert.Equal(false, calledCatch)
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchError")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchPanic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchPanic")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
panic("panic info")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextCancelled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextCancelled")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextTimeout")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 0)
|
||||
defer cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return nil
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchContextError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchContextError")
|
||||
|
||||
var catchedError error
|
||||
calledFinally := false
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 0)
|
||||
defer cancel()
|
||||
|
||||
tc := NewTryCatch(ctx)
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
catchedError = errors.New("catched error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal("catched error", catchedError.Error())
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
|
||||
func TestTryCatchNoCatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestTryCatchNoCatch")
|
||||
|
||||
calledFinally := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error")
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
assert.Equal(true, calledFinally)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package xerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -61,7 +62,7 @@ func ExampleXError_StackTrace() {
|
||||
|
||||
// Output:
|
||||
// github.com/duke-git/lancet/v2/xerror.ExampleXError_StackTrace
|
||||
// 52
|
||||
// 53
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -154,3 +155,27 @@ func ExampleTryUnwrap() {
|
||||
// 42
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleTryCatch() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error message")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:174 - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user