1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-14 17:52:28 +08:00

Compare commits

..

12 Commits

Author SHA1 Message Date
dudaodong
921f218ef7 test: run test cases on rc branch 2024-10-18 16:40:20 +08:00
dudaodong
0a2cc9c928 doc: update doc for RandNumberOfLength and GetExeOrDllVersion 2024-10-18 16:38:39 +08:00
今晚打打
ed93aae970 feat:add GetExeDllVersion for fileutil,random,package (#257)
* 增加GetExeDllVersion函数获取exe,dll版本号

* 多打文字

* 定位忘记...

* 单独剥离出来一个为windows的,增加RandNumLen为取指定长度随机数.

* ....

* 增加test测试
2024-10-18 16:17:14 +08:00
BoWen Qiu
1671f7856a feat(netutil): add async http request for http client (#256)
* fix(algorithm): fix bug of lrucache in issue #251

* feat(netutil): add async send request for HttpClient
2024-10-18 15:14:52 +08:00
燕归来
1008dd4956 fix: fix compile error (#255) (#258) 2024-10-18 15:09:28 +08:00
BoWen Qiu
a254ebdc8e fix(algorithm): fix bug of lrucache in issue #251 (#254) 2024-10-16 09:55:38 +08:00
dudaodong
0bc11001a4 fix: add rsa public and private key example file 2024-10-12 15:16:39 +08:00
dudaodong
85d98ad915 Merge branch 'rc' into v2 2024-10-12 14:06:15 +08:00
77
cb08613ac3 fix(orderedmap): fix set bug (#252)
set : when the key is present, the value of the data map should be set,
not the value of the list

Co-authored-by: congziqi <congziqi@lixiang.com>
2024-10-12 14:05:13 +08:00
dudaodong
bad1b05224 doc: add doc for RsaSign and RsaVerifySign 2024-10-11 15:38:42 +08:00
dudaodong
527328739a feat: add RsaSign and RsaVerifySign 2024-10-10 15:40:32 +08:00
dudaodong
213e2b4ead doc: add play ground demo 2024-10-09 16:56:56 +08:00
47 changed files with 1109 additions and 325 deletions

2
.gitignore vendored
View File

@@ -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
View File

@@ -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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>

View File

@@ -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。&nbsp; &nbsp; &nbsp; &nbsp;<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 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<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。&nbsp; &nbsp; &nbsp; &nbsp;<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 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<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 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<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)]

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
})
}

View File

@@ -0,0 +1,51 @@
-----BEGIN rsa private key-----
MIIJKgIBAAKCAgEAsZoYOi7lxZ3zk4zTa/nvlQzPeXNBthaUpAJmC1b2/ldmglZ8
ARGoVv45VCjG1yKO47SiN8ijcA///o/EawGZ8mJHv8WsPUBxzUF2OQHSZ/kHlbi1
vZsbGXLcM9siBU79uqudbyqUm/9OkgnTPCUUzOlaFtKGeyoDM4TBAX7ec8G8LWBd
BAgNAaK/vP+iXuPHxLdKNMDDel67nLNYJ30KC/fUbwHixn5yQLx4zVLF+rv3pUbQ
uTeEvS+N19Cg1/+5/xzGK+YYdO1ZH4qgubNBu9C90wH0FhIuDDfswh8liZbjHcXs
J82QPdaxjbz1bSb8OToackMMocvJVI9ToxSBdGvGoBk1mnLJRSab6nOD56+iRoGJ
my6GTpD2I1ie1PHV1Y2TIjUESnxjgPigaYA5i/MkXlD/1CtrDW6hsc0/WgCSD7ZG
jNTduUwdwmd2es1XIqnamht+QJE1JTbBFLd9r5zXQY/5W5nRQHBmWP5fVHy7a/wm
F9N2ZpI/DYMarCRIVBsiMdsE62mq63haB6ywjkVk+78TXtmXTTE8ts6XImt+m+0R
Y4lAd+UfHvyOe3dH2y5nGSHG4C8CXB264YdApZZjjvVZy5K3lsmmBB+4Kje1Rux3
6F76qEOvjZ2QvpJDTXSXOk1POu6aZc8N+XRuvG7hmEPdF3xD68VPSZ5/gfcCAwEA
AQKCAgBNUUto0Q/g12G6A53rLPT7S4drVRzvW6c8O3sXRrXihkQvS91STdCehrCI
jfP6pqXURcg1Rti4KY8F0Kru9tSBa/3WZAUW6V5hwDTqnntuHkEKEk60i7jhfFqX
DLgj3X6ibKHuSnhF7YDUHQjj7zS9/Hzm4KIBLooUPKAVuZi4hkgY7RGxdpvK8YJN
knCqpLlMT4szqhOvy1wb3QvsrQfZq/vEk+qZBWVR/3sL0BQ2kuw9/LVTXPMhtXkn
0kCjqEXd5TX02IgfJ1EcZSqRjZN5Y2ewW/JaRXHcieA9pneeDZ00Ufz8WwaHlVbY
4MFr0oQNmdj3k28FZQVyFa+QmJW+UgKqvkCaenDcAMFvMILpdBwReZH6H5ZYBaEt
lYSQS/UVpeonrUTJmfroo48bC8aNB9ILTx80oeG7Uh50hhS+WL8yED1wlwXhCE6X
fMCY8C9wWfbOmuiZPJhKQOa2R46Gv09mKPjCw2l+tbM/Mg6GnakEW33GeS7V8hBA
DUSETJSBuI9xJDXp4nseVK/B9SQVsJhiHxEq6DIG6WFNvTVkaHuZ6J58HdhSRXCU
FeItZNXNqXh5LaOV7DeAe0kHQ3LZ+LcX75JI20GDuL1rSTFKdz0aDkla2sFn1w7J
tIJ2sJOYwJZ/v93Lj5wCuVaKqlMq6oMQ8RTCB1CBZHhG2bkdcQKCAQEA51yhKsri
SM5SEVn8mJYK+vsBh/WVgzJ9Cxuabi+h9D0/bGgsAvjMCPa/07h7SPDdBXhPmn1x
P0cHkvjZt1zBMGcMw84jo7I+m5pAN6DZygIXakJZh+aBMR8M1L26/00anKj+IZY0
t2/8fJzfoNjMCoEk/Z9dpgOvssPs5cY0sxKVfp1uTubj5JbiUEsC1QV3iuAunodR
e/+IqNNaf/iu4bQKzkyVQltQfuocawKieBMcw+46mwZ+70oBHKUWWOvvzC7iAwVi
2GoRkND0hX4MBH4Zx0FOJnO16R6kRo/lmBv+2YtXHzG76KGfW9lEoHmNK33fL5Q5
Z5u1z6lnXP6BzwKCAQEAxIPdxyY0z/H5DadbYqiA5ZhDB/UXbhyKikQ0UJ+ChRko
5V3XLpqsJFW75BSePAHWLj0r9mGezi/ELeMpLQhE+hMZ2byx1LO2EbNKPS9it7Bh
lIB/FTgv4dqLeVMP8Y3QiTgqQB/y4s7tu135H/UWqWm711LI3b/1igg/uiwMZ/Ot
CIWAllPmjPTNsjguC8W68Na7x2RLX2WeS+psOqK1M5l2+xJlIcVqm1zYFnBDWaPb
cvfTuzCmcreWJ3c7c7mGCDcqBSAjqPkkMGD0OvDXTVIsLD6D3B+8xg2m69mQNU7W
ej+809qebJQSVoSN6iF7DKyYWr/6o9/csL/m2ZLPWQKCAQEAybqbkEtcaKz1I8n5
lDXnlxT7Lcf1OHLyUpgb3A1OQj6RKX3fOiwjA4HamsmVPXE+1gEkL4lHECxnrz+p
3dZTYFfJ6oS30IifTF9/tMFchGW0cuMtW3Chnun67xgLj4V0Obqj8zcb+gH7/c9u
sbm2l0YpsbaeGh3GubFZwrNCygzfKoosX0G03WCuLeJpssHUjNOR8on8g4i4aLP4
ifKU0ZmBfoWJ81TZZ//LDYc7kETh5Pi4Qum0DgLR218akCgQa1FJoea1XAuIC2QW
gLr50YT+Bx2q/Z4QtBYSmK/pOerXGGoFad6cgGdEIvrbeqzhaVWUH9E3CF7ddRa5
WH1VQwKCAQEAvl479tNFL/hpWte4CH/RthjlPo0oMGwHrV/bCgsrxkIUQvXAIY6G
mgBPruhmTR0+Xba2osv4qibNteIsHkq3f0YHsc1AvBuHkegMT+9agzWjoddExMqU
YAd1O4fCly7ZSESXcV1BzoPE+tBTKKklVeJurG2u1lpBw4CwM2q+bek5w1qIsZf/
bKctqKsRuCfJK8vpRoQbHAP17/bc94RtYtoUz64HOErlNjIfxsTkCa9ZRCtd+iVr
6Q99ryeq+TVM6SJ/W03CHcuUSiVyErMC7w1ea1H4LMK1/Wp2PF2bfHit/ulFxDkx
ZV+f0B5C1/+tEx8TzD3T0PJo+PQ97qFwqQKCAQEAkVYt7fQgU0LA1kktM/qQRKK0
2nyw9OpRiAmMeNZnTf4Gs7sBOJOifyfQzxweZ7FLnTJL3A9Mgw8sQtGSP3nGyaVb
eeS62XdnbS6RVj9wbeegng205N4+Fowxmm27DeaNdfHJdAvKf7Qm/F3IC2dSQyPq
DtTDExCSq21BQpGjkKuo8YzDX9zZWkHtFUKitKf3o9k+vPvhHxfsP+dqpmyGP00S
XuBmSwDUiCZ6nLyGnV42HTH6BvsMYrlXsDcQC311Dsow12nSjY4cJLdmQaAZntbD
o0TDI4pZONqPOr/65emUHuIZ3mryt9XFO02rf4MU2WTpdYh0gBZm0ggw5lmO+g==
-----END rsa private key-----

View File

@@ -0,0 +1,14 @@
-----BEGIN rsa public key-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsZoYOi7lxZ3zk4zTa/nv
lQzPeXNBthaUpAJmC1b2/ldmglZ8ARGoVv45VCjG1yKO47SiN8ijcA///o/EawGZ
8mJHv8WsPUBxzUF2OQHSZ/kHlbi1vZsbGXLcM9siBU79uqudbyqUm/9OkgnTPCUU
zOlaFtKGeyoDM4TBAX7ec8G8LWBdBAgNAaK/vP+iXuPHxLdKNMDDel67nLNYJ30K
C/fUbwHixn5yQLx4zVLF+rv3pUbQuTeEvS+N19Cg1/+5/xzGK+YYdO1ZH4qgubNB
u9C90wH0FhIuDDfswh8liZbjHcXsJ82QPdaxjbz1bSb8OToackMMocvJVI9ToxSB
dGvGoBk1mnLJRSab6nOD56+iRoGJmy6GTpD2I1ie1PHV1Y2TIjUESnxjgPigaYA5
i/MkXlD/1CtrDW6hsc0/WgCSD7ZGjNTduUwdwmd2es1XIqnamht+QJE1JTbBFLd9
r5zXQY/5W5nRQHBmWP5fVHy7a/wmF9N2ZpI/DYMarCRIVBsiMdsE62mq63haB6yw
jkVk+78TXtmXTTE8ts6XImt+m+0RY4lAd+UfHvyOe3dH2y5nGSHG4C8CXB264YdA
pZZjjvVZy5K3lsmmBB+4Kje1Rux36F76qEOvjZ2QvpJDTXSXOk1POu6aZc8N+XRu
vG7hmEPdF3xD68VPSZ5/gfcCAwEAAQ==
-----END rsa public key-----

View File

@@ -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

View File

@@ -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
}
}
```

View File

@@ -1479,7 +1479,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 +1511,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 +1544,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

View File

@@ -52,6 +52,7 @@ import (
- [ReadFile](#ReadFile)
- [ChunkRead](#ChunkRead)
- [ParallelChunkRead](#ParallelChunkRead)
- [GetExeOrDllVersion](#GetExeOrDllVersion)
<div STYLE="page-break-after: always;"></div>
@@ -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
}
```

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
```

View File

@@ -915,7 +915,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 +1192,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 +1570,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 +1771,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 +2449,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 +2480,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 +2516,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 +2967,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 (

View File

@@ -1547,7 +1547,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 +1556,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 +1581,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 +1615,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 +1639,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 +1648,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 +1673,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 +1707,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 (

View File

@@ -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 (

View File

@@ -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
}
}
```

View File

@@ -1480,7 +1480,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 +1512,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 +1545,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

View File

@@ -52,6 +52,7 @@ import (
- [ReadFile](#ReadFile)
- [ChunkRead](#ChunkRead)
- [ParallelChunkRead](#ParallelChunkRead)
- [GetExeOrDllVersion](#GetExeOrDllVersion)
<div STYLE="page-break-after: always;"></div>
@@ -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
}
```

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
```

View File

@@ -913,7 +913,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 +1190,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 +1567,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 +1766,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 +2445,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 +2476,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 +2512,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 +2962,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 (

View File

@@ -1549,7 +1549,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 +1561,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 +1583,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 +1617,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 +1641,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 +1674,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 +1708,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 (

View File

@@ -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 (

View File

@@ -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

View File

@@ -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

View File

@@ -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

83
fileutil/file_windows.go Normal file
View 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
}

View 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)
}

View File

@@ -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
View File

@@ -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=

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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)))
}

View File

@@ -789,7 +789,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 +810,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))
@@ -1388,7 +1388,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)

View File

@@ -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
@@ -154,7 +154,7 @@ func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool,
// 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)
}

View File

@@ -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)

View File

@@ -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,7 +729,7 @@ 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)

View File

@@ -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