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

Compare commits

...

376 Commits

Author SHA1 Message Date
dudaodong
c949059fb1 release: v2.0.7 2022-05-18 15:29:55 +08:00
dudaodong
9c6d489db7 docs: add some new funcs documentation 2022-05-18 15:28:18 +08:00
dudaodong
45436798af fix: fix TestMinBy test function 2022-05-18 15:23:57 +08:00
dudaodong
bd0eb0682c docs: add doc for func MaxBy and MinBy 2022-05-18 15:22:44 +08:00
dudaodong
bdbc06b095 docs: add doc for funcs IndexOf and LastIndexOf 2022-05-18 15:00:09 +08:00
dudaodong
2f504ce851 test: add unit test for func LastIndexOf 2022-05-16 11:11:40 +08:00
dudaodong
02a24b461c test: add unit test for func LastIndexOf 2022-05-16 11:05:52 +08:00
dudaodong
3f7a81c005 test: add unit test for func IndexOf 2022-05-16 11:04:40 +08:00
dudaodong
cc6e10ee5a add func IndexOf and LastIndexOf 2022-05-16 10:40:33 +08:00
dudaodong
eff2f22440 test: add unit test for MinBy function 2022-05-15 18:28:40 +08:00
dudaodong
47b6747bb0 feat: add MinBy function 2022-05-15 18:25:46 +08:00
dudaodong
298219aee7 test: add unit test for MaxBy function 2022-05-15 18:21:01 +08:00
dudaodong
d5607b0a5a feat: add MaxBy function 2022-05-15 18:15:05 +08:00
IHIDCHAOS
f47873fbc7 Update system_zh-CN.md (#32)
fix typo
2022-05-15 17:28:37 +08:00
dudaodong
f24ad26692 release: v2.0.6 2022-05-12 10:13:13 +08:00
dudaodong
88de9bfac2 docs: add doc for SplitEx function 2022-05-12 10:12:19 +08:00
dudaodong
e4777a0986 docs: add doc for SplitEx function 2022-05-12 10:11:12 +08:00
franktz
84a69d1fa5 feat: strutil.SplitEx. Split a given string whether the result contains empty string (#31)
Co-authored-by: Frank.Town <tangzhi21@sfmail.sf-express.com>
2022-05-11 15:19:53 +08:00
dudaodong
5eb056277d update readme file 2022-04-27 11:51:02 +08:00
dudaodong
4e6d586251 update readme file 2022-04-27 11:42:06 +08:00
dudaodong
61c7012e17 test: add unit test TestBSTree_IsSubTree 2022-04-27 11:36:51 +08:00
dudaodong
0d48778886 feat: add HasSubTree func for BSTree 2022-04-27 10:43:01 +08:00
dudaodong
e98c46c903 feat: add IsSubTree func for BSTree 2022-04-27 10:36:11 +08:00
dudaodong
155f287ab0 refactor: add param comparator in NewBSTree func 2022-04-26 11:04:04 +08:00
dudaodong
652916b7d7 test: add unit test for PriorityQueue Dequeue function 2022-04-26 10:56:24 +08:00
dudaodong
955de2bdbf feat: add Dequeue function 2022-04-26 10:50:27 +08:00
dudaodong
a4c1d40faa test: add unit test for PriorityQueue Enqueue function 2022-04-26 10:45:19 +08:00
dudaodong
f155e0caa6 test: add unit test for PriorityQueue Enqueue function 2022-04-26 10:40:48 +08:00
dudaodong
fb0332449c feat: add IsEmpty and IsFull for PriorityQueue 2022-04-26 10:24:10 +08:00
dudaodong
68f0fd1d4c feat: add PriorityQueue 2022-04-26 10:19:31 +08:00
dudaodong
70995c5098 feat: add PriorityQueue 2022-04-26 10:18:43 +08:00
dudaodong
55e62ed8ca feat: add PriorityQueue 2022-04-26 10:18:06 +08:00
dudaodong
e614274f07 release v2.0.5 2022-04-24 10:34:25 +08:00
dudaodong
c524eb04a1 docs: add doc for concurrency in readme file 2022-04-24 10:32:55 +08:00
dudaodong
985b3cddd8 fix: fix TestTee func 2022-04-24 10:26:07 +08:00
dudaodong
abadeec007 docs: add doc for channel.go 2022-04-24 10:17:34 +08:00
dudaodong
3ab05154aa docs: add doc for channel.go 2022-04-22 17:12:41 +08:00
dudaodong
9f1c89bf0e refactor: refact FanIn func in channel.go 2022-04-21 14:31:43 +08:00
dudaodong
9444582e44 fix: fix OrDone func 2022-04-21 14:19:38 +08:00
dudaodong
c27ccad2b9 refactor: refact Or func in channel.go 2022-04-21 14:13:19 +08:00
dudaodong
d1c6c57700 feat: add func Bridge 2022-04-21 11:26:02 +08:00
dudaodong
922999037f feat: add func Tee 2022-04-21 11:18:45 +08:00
dudaodong
046e90486d feat: add func in channel.go 2022-04-19 16:21:23 +08:00
dudaodong
fc6dee9e77 feat: add func in channel.go 2022-04-19 16:03:12 +08:00
dudaodong
980ff2c363 feat: add FanIn for channel 2022-04-19 15:34:26 +08:00
dudaodong
763aa8e10d refactor: replace param done channel with ctx context 2022-04-19 14:42:55 +08:00
dudaodong
83c0d1d6e6 fix: fix misspellings 2022-04-15 17:02:34 +08:00
dudaodong
dfc6b868fb feat: add RepeateFn function 2022-04-15 16:32:55 +08:00
dudaodong
f66c0938e5 feat: add Take function to generate a chan of values taken from another chan 2022-04-15 16:22:19 +08:00
dudaodong
a4900fecb4 feat: add Repeate function to generate a chan of repeate values 2022-04-15 16:08:14 +08:00
dudaodong
dc25bdab2f feat: add Generate chan function in concurrency package 2022-04-15 15:56:06 +08:00
dudaodong
bb23c9eef8 release v2.0.4 2022-04-14 11:51:34 +08:00
dudaodong
b4cd0750e4 fix: fix http post to support multipart/form-data header 2022-04-14 11:48:39 +08:00
dudaodong
c960841491 docs: update sort function doc 2022-04-12 14:45:22 +08:00
dudaodong
5d6f9443fd refactor: rewrite sort function 2022-04-12 14:30:43 +08:00
dudaodong
5483380066 refactor: rewrite arrayqueue 2022-04-08 17:39:54 +08:00
dudaodong
20b9e5353e fix: fix goreport issue 2022-04-06 11:33:48 +08:00
dudaodong
1ec3a5af87 release v2.0.3 2022-04-06 10:54:54 +08:00
dudaodong
f31dde97b1 docs: add maputil docs in read me file 2022-04-05 14:24:33 +08:00
dudaodong
1718fd1cf1 docs: add doc for maputil package 2022-04-05 14:16:58 +08:00
dudaodong
513c0f829c docs: add doc for SymmetricDifference fun in slice doc 2022-04-05 13:47:13 +08:00
dudaodong
c51a806aff feat: add SymmetricDifference func for set 2022-04-01 18:06:34 +08:00
dudaodong
3c16d50c4b refactor: rename ReverseIntersect to SymmetricDifference 2022-04-01 18:05:02 +08:00
dudaodong
21dd6ab8aa feat: add SymmetricDifference func for set 2022-04-01 18:02:12 +08:00
dudaodong
f5bf5183cc feat: add Minus func for set 2022-04-01 16:48:37 +08:00
dudaodong
f28b5b2f92 feat: add Minus func for set 2022-04-01 16:44:25 +08:00
dudaodong
79867e8a63 feat: add ReverseIntersect function 2022-03-31 19:42:27 +08:00
dudaodong
19939c2b03 feat: add Minus func 2022-03-31 18:00:11 +08:00
dudaodong
bf7ffbfa8d feat: add Intersect func 2022-03-31 16:56:12 +08:00
dudaodong
cbb46f9cb4 feat: add Filter func 2022-03-30 19:52:43 +08:00
dudaodong
3ad142d5d7 feat: add ForEach func 2022-03-30 19:41:55 +08:00
dudaodong
1a436aeb41 feat: add Merge func 2022-03-30 18:06:22 +08:00
dudaodong
1af8fe8daf test: add unit test for Keys and Values func 2022-03-30 17:45:17 +08:00
dudaodong
ae54c8db6f feat: add Values func 2022-03-30 17:34:01 +08:00
dudaodong
be942ec33e feat: add package maputil and Keys func 2022-03-30 17:27:50 +08:00
dudaodong
fafb59dad6 update readme file 2022-03-29 11:02:27 +08:00
dudaodong
e36c01cac9 release v2.0.2 2022-03-29 11:01:31 +08:00
dudaodong
aa0afa8d94 release v1.2.7 2022-03-29 11:01:06 +08:00
dudaodong
18e0031e0e fix: fix TestInsertionSort 2022-03-26 21:06:05 +08:00
dudaodong
a5018c110c fix: fix bug in ToBytes func 2022-03-26 20:54:37 +08:00
dudaodong
142deb83b2 fix: fix InsertionSort bug 2022-03-26 18:25:42 +08:00
dudaodong
ccc0188352 feat: add DeleteValue for SinglyLink 2022-03-24 17:56:45 +08:00
dudaodong
98dba83107 release v2.0.1 2022-03-22 14:47:23 +08:00
dudaodong
9c6aff9030 fix: fix lint warning 'ineffassign' 2022-03-22 14:45:16 +08:00
dudaodong
7fd9a94922 fix: fix lint warning 'ineffassign' 2022-03-22 14:36:35 +08:00
dudaodong
dd3b1f3aed docs: add doc for some new funcs 2022-03-22 14:10:58 +08:00
dudaodong
f9dce592e8 docs: add doc for Min, Max, and Average 2022-03-22 10:43:00 +08:00
dudaodong
c4b0967623 feat: add Max, Min, and Average function 2022-03-22 10:26:43 +08:00
dudaodong
41613061d5 docs: add GroupWith doc 2022-03-21 20:10:39 +08:00
dudaodong
50ef63e27d feat: add GroupWith func 2022-03-21 15:29:10 +08:00
dudaodong
3ae4a35d04 fix: format timezone issue 2022-03-19 19:24:28 +08:00
dudaodong
89ea0ee15a fix: format timezone issue 2022-03-19 19:08:34 +08:00
dudaodong
85399e23ed fix: format timezone issue 2022-03-19 18:42:22 +08:00
dudaodong
19a6f218e6 fix: format time in local timezone 2022-03-19 18:23:06 +08:00
dudaodong
ccaf290b63 docs: add doc for datetime/conversion.go 2022-03-18 18:18:28 +08:00
dudaodong
54745d512c test: add unit test and func comment for time conversion 2022-03-18 17:48:57 +08:00
dudaodong
39234d4722 Merge branch 'main' of github.com:duke-git/lancet into main 2022-03-17 19:46:31 +08:00
dudaodong
4b4310265b fix: update TestListFileNames 2022-03-17 19:46:19 +08:00
wangxudong123
d8a982bf07 增加时间转换 (#25)
Co-authored-by: wangxd01 <wangxd01@mingyuanyun.com>
2022-03-17 19:44:24 +08:00
dudaodong
0334a6f02b docs: fix some issues 2022-03-17 11:55:52 +08:00
dudaodong
ae0c613b8e add package comment 2022-03-17 11:55:08 +08:00
dudaodong
40b2560752 docs: add v2 in import path 2022-03-17 11:33:45 +08:00
dudaodong
50c6e51393 upgrade go module v2 2022-03-17 10:57:35 +08:00
dudaodong
1434e00712 docs: add func HeapSort 2022-03-17 10:11:34 +08:00
dudaodong
76c941cff0 update readme file 2022-03-16 19:39:21 +08:00
dudaodong
bb03f31a8b release v2.0.0 2022-03-16 19:16:43 +08:00
dudaodong
c939b26cb8 refactor: interface{} -> any 2022-03-16 18:41:40 +08:00
dudaodong
af480efa8c docs: add xerror package doc 2022-03-16 18:21:30 +08:00
dudaodong
bc913d70b1 docs: update doc style 2022-03-16 18:06:06 +08:00
dudaodong
2bc87d8a6b docs: add docs/algorithm.md 2022-03-16 18:00:38 +08:00
dudaodong
2185c48eab docs: add docs/algorithm.md 2022-03-16 18:00:29 +08:00
dudaodong
59b5046a15 docs: update slice.md 2022-03-16 16:59:15 +08:00
dudaodong
569902b528 fix: fix lru cache bug 2022-03-14 11:19:30 +08:00
dudaodong
78519088ab feat: add lru cache 2022-03-11 17:05:55 +08:00
dudaodong
0c06cdb29f Merge branch 'main' into v2 2022-03-04 17:42:18 +08:00
dudaodong
7ac6816532 docs: add Factorial 2022-03-04 17:37:49 +08:00
dudaodong
81c4216699 release v1.2.6 2022-03-04 17:31:38 +08:00
dudaodong
2e30389703 test: add TestTruncRound 2022-03-04 17:30:47 +08:00
dudaodong
0e1d5cf04b docs: add doc for mathutil package 2022-03-04 17:28:53 +08:00
dudaodong
4e2d84e4fc feat: add mathutil package 2022-03-03 15:55:36 +08:00
dudaodong
e8b8ff8927 merge main branch 2022-03-01 15:00:02 +08:00
dudaodong
13ee045b99 docs: add section 'How to Contribute' 2022-03-01 14:55:42 +08:00
dudaodong
06bd407a0c feat: add LevelOrderTraverse func 2022-03-01 11:23:33 +08:00
dudaodong
aa28479d11 feat: update deleteTreeNode func 2022-03-01 11:13:44 +08:00
dudaodong
bf7db0ded2 feat: add DeletetNode 2022-03-01 11:04:38 +08:00
dudaodong
dd1cbf2ee3 refactor: rename Insert to InsertNode 2022-03-01 10:11:37 +08:00
dudaodong
9d5db895c9 Merge branch 'main' into v2 2022-03-01 10:02:23 +08:00
dudaodong
f1fd4c876b fmt: gofmt function.go 2022-02-28 10:11:07 +08:00
dudaodong
cd63b2b18f docs: add func UUIdV4 in readme file 2022-02-28 10:09:23 +08:00
dudaodong
bab9b4a6b3 release v1.2.5 2022-02-25 16:39:03 +08:00
dudaodong
b3c34578bf fix: set request body content-length 2022-02-25 16:38:32 +08:00
dudaodong
f26477904e refactor: set body byte for http post request 2022-02-25 15:31:39 +08:00
dudaodong
6b09da6e6e feat: add funcs to traverse bstree 2022-02-23 19:34:35 +08:00
dudaodong
b2b6710a1b feat: add BSTree which is binary search tree 2022-02-21 16:48:27 +08:00
dudaodong
e7ee2ed7cf Merge branch 'main' into v2 2022-02-20 11:35:43 +08:00
dudaodong
85886cf618 docs: add func UUIdV4 2022-02-20 11:09:51 +08:00
dudaodong
a19a861552 feat: add func UUIdV4 2022-02-20 10:16:15 +08:00
dudaodong
1dfd1ec1d3 Merge branch 'main' into v2 2022-02-19 21:55:09 +08:00
dudaodong
96d57a6d24 docs: remove duplicated 2022-02-19 21:53:27 +08:00
dudaodong
b48155c249 refactor: rename files *_util.go to *_internal.go 2022-02-19 21:52:10 +08:00
dudaodong
41685022c0 refactor: rename files *_util.go to *_internal.go 2022-02-19 21:51:58 +08:00
dudaodong
2e8834a2c1 docs: update slice.doc 2022-02-18 11:05:14 +08:00
dudaodong
df098392c2 merge main branch 2022-02-18 10:28:47 +08:00
dudaodong
4e7274ce05 fix: check fn param must be function 2022-02-17 19:51:52 +08:00
dudaodong
2384b0e51f docs: fix func link mistake 2022-02-16 14:26:03 +08:00
dudaodong
6b6b938d1e docs: fix func link mistake 2022-02-16 14:24:18 +08:00
dudaodong
29d8987909 docs: update readme file 2022-02-16 14:12:42 +08:00
dudaodong
43fb3f1a06 release v1.2.4 2022-02-16 14:10:25 +08:00
dudaodong
34c28fece3 docs&refactor: rename request.go to http.go 2022-02-15 17:46:07 +08:00
dudaodong
40c2402493 feat: add func GetIps and GetMacAddrs 2022-02-15 17:38:09 +08:00
dudaodong
c965e79bfc docs: add doc for begin and end time funcs 2022-02-15 16:37:48 +08:00
dudaodong
eeadb1fecb feat: add funcs for get begin and end time for year, month, week, day, hour, minute 2022-02-15 16:07:59 +08:00
dudaodong
5e318a78d2 refactor: remove unused code 2022-02-15 11:19:07 +08:00
dudaodong
d872d64fe0 feat: add CircularQueue 2022-02-15 10:34:14 +08:00
dudaodong
c2257493a8 fix: fix panic info text 2022-02-14 15:36:44 +08:00
dudaodong
48c1f8ffad fix: fix some spell mistake 2022-02-13 19:00:44 +08:00
dudaodong
8a4c8218d2 update func DeQueue comment 2022-02-11 10:49:33 +08:00
dudaodong
92e1321d43 refactor: rename func Length -> Size 2022-02-11 10:48:38 +08:00
dudaodong
43fb907a81 feat: add LinkedQueue 2022-02-11 10:46:48 +08:00
dudaodong
f551c56921 refactor: reconstructure souce file into the corresponding folder 2022-02-10 17:57:53 +08:00
dudaodong
85e1f711f5 feat: and Clear and IsEmpty func 2022-02-10 17:41:51 +08:00
dudaodong
ade567a620 feat: add ArrayQueue data structure 2022-02-10 17:30:37 +08:00
dudaodong
a26e519a3f refactor: rename func Length -> Size 2022-02-10 15:42:05 +08:00
dudaodong
797e47363f rename: rename StackArray -> ArrayStack, StackLink -> LinkedStack 2022-02-10 11:50:03 +08:00
dudaodong
20e1836eb7 rename: rename StackArray -> ArrayStack, StackLink -> LinkedStack 2022-02-10 11:49:46 +08:00
dudaodong
5ae746a1f0 rename: rename InsertByIndex -> InsertAt, UpdateByIndex -> UpdateAt, DeleteByIndex -> DeleteAt for release 2.0 2022-02-10 11:25:34 +08:00
dudaodong
17d271190b feat: add DoublyLink data structure 2022-02-10 10:57:17 +08:00
dudaodong
310f8bd1e1 feat: add Set data structure 2022-02-09 15:15:49 +08:00
dudaodong
bf7a4e729f feat: add func Contain, Union, Intersection 2022-02-09 11:40:08 +08:00
dudaodong
1dd826f050 add logo png and update readme file 2022-02-08 14:43:57 +08:00
dudaodong
8b04aa5f31 release v1.2.3 update readme file 2022-02-07 16:35:01 +08:00
dudaodong
6855fe0bce docs: add doc for validator package 2022-02-07 12:41:58 +08:00
dudaodong
300be9e3dc docs: add doc for system package 2022-02-07 11:21:47 +08:00
dudaodong
384be2e2e9 docs: add doc for strutil package 2022-02-07 10:54:44 +08:00
dudaodong
1d71a0ad3a docs: add doc for slice package 2022-02-06 17:16:16 +08:00
dudaodong
0e0ed316f1 docs: fix code issue 2022-02-05 09:54:48 +08:00
dudaodong
8d0ff28304 update comment for StackLink 2022-02-04 22:45:01 +08:00
dudaodong
cee9bb538f feat: add stacklink.go implements stack with link 2022-02-04 22:42:51 +08:00
dudaodong
eb59d02a08 feat: add stackarray.go implements stack with array 2022-02-04 19:35:06 +08:00
dudaodong
10ed71a3a2 refactor: rename linknode.go to node.go 2022-02-04 09:22:16 +08:00
dudaodong
0e86244559 refactor: rename linknode.go to node.go 2022-02-04 09:21:35 +08:00
dudaodong
5ab150cad3 feat: add DeleteAtHead, DeleteAtTail, DeleteAt, Reverse, Size, GetMiddleNode funcs in singlelink 2022-02-03 16:37:34 +08:00
dudaodong
3546afe86c feat: add some functons of singlelink 2022-02-02 22:41:49 +08:00
dudaodong
961eedda04 docs: add doc for package retry 2022-02-01 18:57:41 +08:00
dudaodong
f4881d2f49 docs: add doc for package random 2022-01-31 23:46:59 +08:00
dudaodong
a3eb269bdb docs: add doc for package netutil 2022-01-31 23:34:44 +08:00
dudaodong
e367123070 docs: fix code fmt issue 2022-01-30 22:01:52 +08:00
dudaodong
0f1d3fb553 docs: fix misspell in readme file 2022-01-30 21:54:24 +08:00
dudaodong
a4658b2341 docs: add doc for package function 2022-01-30 21:53:25 +08:00
dudaodong
739113ef9e docs: add doc for package formatter 2022-01-30 19:04:07 +08:00
dudaodong
1629b861cd docs: add doc for package fileutil 2022-01-30 15:28:33 +08:00
dudaodong
acce85557f fmt: fmt example code in docs 2022-01-29 22:49:54 +08:00
dudaodong
05aefbaa62 docs: add doc for package datetime 2022-01-28 16:25:49 +08:00
dudaodong
6988fdc451 docs: fix code fmt issue 2022-01-28 15:33:20 +08:00
dudaodong
5963830879 docs: fix source link disabled issue 2022-01-28 11:50:25 +08:00
dudaodong
134aded4d8 docs: add md doc for every package 2022-01-28 11:45:50 +08:00
dudaodong
35780d9dc1 update: add DesEcbEncrypt and DesEcbDecrypt comment 2022-01-28 10:53:14 +08:00
dudaodong
c40ac9bb9b refactor: add error value return for GenerateRsaKey func 2022-01-28 10:51:40 +08:00
dudaodong
51bd974cc9 refactor: make some code cleaner 2022-01-27 20:09:42 +08:00
dudaodong
0b93fbffd9 fix: fix misspell in readme file 2022-01-27 11:13:19 +08:00
dudaodong
349f8b6c97 test: add some cases for convertor test 2022-01-27 10:55:37 +08:00
dudaodong
70077a6010 merge main branch 2022-01-26 17:47:57 +08:00
dudaodong
efdf36a817 Merge branch 'main' into v2 2022-01-26 17:44:46 +08:00
dudaodong
e233788f69 comment: add comment for List struct 2022-01-26 15:25:52 +08:00
dudaodong
957e6356f6 feat: add singlelink 2022-01-26 15:25:02 +08:00
dudaodong
887eaa528a update: algorithm package comment 2022-01-26 14:57:37 +08:00
dudaodong
33126570bd feat: add datastructure package and list implementation 2022-01-26 14:56:40 +08:00
dudaodong
5937183af0 feat: replace constraints comparable into any in some funcs 2022-01-24 15:47:47 +08:00
dudaodong
5899921054 fix: fix some text 2022-01-24 15:30:22 +08:00
dudaodong
ec19014578 feat: add FindLast func 2022-01-24 15:29:14 +08:00
dudaodong
1ad990ce9d feat: add FindLast func 2022-01-24 15:28:47 +08:00
dudaodong
4eaa0a39d5 feat: add FindLast func 2022-01-24 15:22:43 +08:00
dudaodong
18ec73839b feat: add DifferenceWith 2022-01-24 14:53:45 +08:00
dudaodong
89aef977a2 refactor: clean code for slice/slice.go 2022-01-24 11:46:09 +08:00
dudaodong
2612569500 merge: merge main branch and refector slice func with generics 2022-01-24 11:10:12 +08:00
dudaodong
acc8b59387 comment: add comment for Unwrap 2022-01-24 10:24:10 +08:00
dudaodong
8bb102cb6e release v1.2.2 2022-01-24 10:10:38 +08:00
dudaodong
e07d54d1da fix: fix exec windows command test failed 2022-01-23 14:40:59 +08:00
dudaodong
6f035f710e feat: add DifferenceBy func 2022-01-23 14:27:37 +08:00
donutloop
2878d389c8 error: Add unwrap (#24)
Add a unwrap func helper

* Unwrap if err is nil then it returns a valid value otherwise it panics
2022-01-22 21:25:31 +08:00
dudaodong
92967e0add fix: TestCompact for blank string case 2022-01-22 21:21:12 +08:00
dudaodong
6a1a0b8677 feat: add Concat func 2022-01-22 21:16:34 +08:00
dudaodong
ca88687f3d feat: add UpperFirst func 2022-01-22 18:55:41 +08:00
dudaodong
aa64bf5bee feat: add IsUrl func 2022-01-22 18:11:52 +08:00
dudaodong
a3399503f7 feat: add Debounced func 2022-01-21 17:13:31 +08:00
dudaodong
3ca096b4ac update MiMeType func comment 2022-01-21 14:54:55 +08:00
dudaodong
3f8effb7a3 refactor: make BinarySearch func code clear 2022-01-21 11:57:36 +08:00
dudaodong
bd30855ae6 feat: add LinearSearch 2022-01-21 11:36:31 +08:00
dudaodong
0efe2f57c3 merge main 2022-01-19 20:47:47 +08:00
dudaodong
28317a1683 feat: remove ConvertSlice func 2022-01-19 20:41:46 +08:00
dudaodong
2ab898741d test: add TestOsDetection 2022-01-19 20:18:04 +08:00
dudaodong
454efd486d test: add test logic for assert 2022-01-19 19:45:18 +08:00
dudaodong
8868fcabed Merge branch 'main' into v2 2022-01-19 17:35:48 +08:00
dudaodong
efa20a97c4 release v1.2.1 2022-01-19 14:58:52 +08:00
dudaodong
25ef78bc64 refactor: Md5File for reading large file 2022-01-19 14:34:11 +08:00
dudaodong
261370e30d fix: os.go/ExecCommand make error the last return value 2022-01-17 16:57:38 +08:00
dudaodong
dfbb9e30e0 feat: algorithm package, BinarySearch and BinaryIterativeSearch functions 2022-01-17 15:36:48 +08:00
dudaodong
b22be7cade refactor: change var name low -> lowIndex, high -> highIndex 2022-01-17 15:11:33 +08:00
dudaodong
87da6c6816 Merge branch 'main' into v2 2022-01-17 15:01:38 +08:00
dudaodong
764a6fe107 release v1.2.0 2022-01-17 14:49:20 +08:00
dudaodong
f3749c52b9 feat: add system package 2022-01-17 11:54:03 +08:00
dudaodong
f368854b2d update text style of readme file 2022-01-17 10:40:41 +08:00
dudaodong
912f7052a3 gofmt 2022-01-17 10:29:42 +08:00
dudaodong
c424b88d40 update style of readme file 2022-01-16 22:17:51 +08:00
dudaodong
e6f9b0954c feat: add CountSort 2022-01-16 17:20:20 +08:00
dudaodong
98e861cf3b feat: add QuickSort, HeapSort, and MergeSort functions 2022-01-16 16:52:17 +08:00
dudaodong
43e0ca7edf feat: add ShellSort 2022-01-14 18:17:46 +08:00
dudaodong
d491bea263 feat: add BubbleSort and InsertionSort 2022-01-14 17:57:14 +08:00
dudaodong
6f1feb96d6 experimental feature, algorithm/sorter.go try to implements sort function with go generics 2022-01-14 17:01:44 +08:00
Dan Anstis
aeebd63eda docs(readme): fix convertor import example (#23) 2022-01-14 12:33:53 +08:00
dudaodong
22b3c4dd42 feat: add validator functions, IsAllUpper, IsAllLower, ContainUpper, ContainLower, ContainLetter, IsJSON and IsPort 2022-01-13 20:19:41 +08:00
dudaodong
bd976642f6 feat: add try package for executing a function repeatedly 2022-01-13 16:18:49 +08:00
dudaodong
d46d12f949 feat: add func ContainSubSlice 2022-01-13 11:52:21 +08:00
dudaodong
e31fb28003 feat: add func ContainSubSlice 2022-01-13 11:00:27 +08:00
dudaodong
fd271fe176 add test passing badge 2022-01-12 11:27:09 +08:00
dudaodong
6890bbfe05 update: rename workflow 2022-01-12 11:23:51 +08:00
dudaodong
c6fc92a94c update go version to v1.18 2022-01-12 10:23:04 +08:00
dudaodong
24ae47a12f remove v2 branch 2022-01-12 10:13:13 +08:00
dudaodong
f4fa790b72 Merge branch 'main' into v2 2022-01-12 10:05:35 +08:00
dudaodong
d8d85efedf update: add v2 branch 2022-01-12 10:05:21 +08:00
dudaodong
22798fd750 fix: fix some go report issue 2022-01-12 10:01:48 +08:00
dudaodong
ba73847b80 fix: fix some go report issue 2022-01-12 09:57:10 +08:00
dudaodong
69453eba19 release v1.1.9 2022-01-11 20:42:04 +08:00
dudaodong
907df56f86 update: make func comment consistent 2022-01-11 20:27:06 +08:00
donutloop
f147f78a41 Slice: sort from v2 branch (#22)
ref: f1d7154179
2022-01-11 20:13:25 +08:00
dudaodong
3dadfa234b update: make func comment consistent 2022-01-11 19:33:15 +08:00
donutloop
f1d7154179 refactor: sort (#21)
Removed reverse func because it use to much cpu and add test cas for asc sort
2022-01-11 19:24:36 +08:00
dudaodong
dc47b9ce98 fix: fix confict in readme file 2022-01-11 18:15:09 +08:00
dudaodong
6e626851cf merge #pr20 2022-01-11 18:12:57 +08:00
donutloop
c906d8aea7 Slice: group by and without v2 (#20)
* Slice: group by and without v2

Migrate from reflection to generic

* update doc
2022-01-11 18:11:01 +08:00
dudaodong
e5e4e09308 comment without func 2022-01-11 18:10:21 +08:00
dudaodong
7ed173849a refactor: rewrite DeleteByIndex, InsertByIndex, UpdateByIndex and Without func with generics 2022-01-11 18:08:22 +08:00
donutloop
24c0d95112 Slice: reverse and shufffle v2 (#19)
* Slice: reverse and shufffle v2

Migrate from reflection to generic form

Note: after migration, old reverse must be removed

* Suffle test: remove reflection calls

* Reverse test: change name of test
2022-01-10 19:52:23 +08:00
dudaodong
e9fed34729 fmt: slice.go 2022-01-10 10:27:20 +08:00
dudaodong
9caefdb67d fmt: slice.go 2022-01-10 10:24:33 +08:00
dudaodong
681d5b6bdf update comment for Count func 2022-01-09 22:17:50 +08:00
dudaodong
b0e9758e0d Merge branch 'v2' of github.com:duke-git/lancet into v2 2022-01-09 22:15:18 +08:00
donutloop
7b9a8a55e7 Slice: CountV2 (#18)
Use generic instead of reflection
2022-01-09 22:15:03 +08:00
dudaodong
44ac82e8b8 refactor: rewrite some slice functions with go generics 2022-01-09 22:14:46 +08:00
dudaodong
c4b4cb1173 merge master: rewrite all unit test functions with assert 2022-01-09 18:33:00 +08:00
dudaodong
bbfc5b7060 delete file utils.go and fix some misspel 2022-01-09 16:12:26 +08:00
dudaodong
1f45937190 refactor: rewrite all unit test functions with assert 2022-01-09 16:04:33 +08:00
dudaodong
52c5a91606 refactor: rewrite all unit test functions with assert 2022-01-09 15:57:21 +08:00
dudaodong
49f62c3550 refactor: rewrite all unit test functions with assert 2022-01-09 15:53:30 +08:00
dudaodong
23701e6998 refactor: rewrite all unit test functions with assert 2022-01-09 15:49:52 +08:00
dudaodong
1199c30ef3 refactor: rewrite all unit test functions with assert 2022-01-09 15:48:29 +08:00
dudaodong
b0e17c7bc4 refactor: rewrite all unit test functions with assert 2022-01-09 15:39:50 +08:00
dudaodong
d3525dfe8f refactor: rewrite all unit test functions with assert 2022-01-09 15:34:17 +08:00
dudaodong
9da7115169 refactor: rewrite all unit test functions with assert 2022-01-09 15:10:56 +08:00
dudaodong
9cb9aa2f2f refactor: rewrite all unit test functions with assert 2022-01-09 14:46:17 +08:00
dudaodong
e4cd7dad35 refactor: rewrite all unit test functions with assert 2022-01-09 14:31:31 +08:00
dudaodong
31e08197d4 remove file comment 2022-01-09 14:03:46 +08:00
dudaodong
642d0b8077 refactor: rewrite all unit test functions with assert 2022-01-09 14:01:51 +08:00
dudaodong
25b2ae6b98 fix: return empty byte slice when rand bytes lenght less 1 2022-01-09 14:00:23 +08:00
dudaodong
65719515bd feat: add LessOrEqual and GreaterOrEqual 2022-01-09 13:58:27 +08:00
dudaodong
3ffd81a98a refactor: rewrite all unit test functions with assert 2022-01-09 13:51:07 +08:00
dudaodong
f490ef2404 refactor: rewrite all unit test functions with assert 2022-01-09 13:30:08 +08:00
dudaodong
3438f3b18a refactor: rewrite all unit test functions with assert 2022-01-09 13:07:49 +08:00
dudaodong
73f4ae7b35 refactor: add internal/assert.go and rewrite all unit funcs string_test.go with assert 2022-01-08 21:58:35 +08:00
donutloop
30d798366b Slice: find v2 (#17)
* If slice len is zero then return false
* Convert find to generic form.
* If return T is nil then no items matched the predicate func
2022-01-07 20:19:27 +08:00
dudaodong
3e9a2b5c59 refactor: refact Filter, ForEach, Map func with generics 2022-01-07 17:53:55 +08:00
dudaodong
1343683b08 checkout v2 branch for generics migration 2022-01-07 17:48:00 +08:00
rumikk
a8996933bf ToJson fix error handling (#16) 2022-01-07 15:00:05 +08:00
donutloop
3905c0bde1 Slice: Add count func (#15)
Returns the count of matched elements
2022-01-06 20:32:14 +08:00
dudaodong
c7e961704d Merge branch 'main' of github.com:duke-git/lancet into main 2022-01-06 17:09:43 +08:00
dudaodong
cb7df1b57d update: add some new feature comments for file and slice 2022-01-06 17:09:01 +08:00
dudaodong
eeff28606e feat: add IsLink, FileMode, MiMeType funcs for file 2022-01-06 16:53:32 +08:00
dudaodong
86d4b25a2b feat: and Zip and UnZip func for file operation 2022-01-06 15:15:59 +08:00
Ahmad Alfy
ad287ed99a doc: minor spelling mistak (#14) 2022-01-05 21:25:21 +08:00
dudaodong
df9de3065b feat: add ForEach func 2022-01-05 20:17:16 +08:00
dudaodong
71a2ea3f20 update: change case name for TestNone func 2022-01-05 19:46:51 +08:00
dudaodong
955f2e6de6 update func GetElapsedTime and None comment 2022-01-05 19:44:22 +08:00
donutloop
4aef9d6d22 Slice: Add none func (#13)
Returns true whether no elements of this slice match the provided predicate
func. Negated form of Every func
2022-01-05 19:38:14 +08:00
dudaodong
4752725dd6 add Wrap and Unwrap func comment 2022-01-04 11:22:54 +08:00
dudaodong
07d1704cb2 release v1.1.7 2022-01-04 10:56:05 +08:00
dudaodong
74d262e609 Merge branch 'main' of github.com:duke-git/lancet into main 2022-01-03 20:11:32 +08:00
dudaodong
97e0789ea4 feat: add Wrap and Unwrap func 2022-01-03 20:11:15 +08:00
donutloop
bc39b0887b Filter: remove second loop and indexes slice (#12)
Use less memory and cpu resources to filter out elements from the slice.
2022-01-03 20:10:15 +08:00
dudaodong
4fd8a18677 release v1.1.6 2022-01-03 15:58:19 +08:00
dudaodong
3de906d7c9 refactor: reduce gocyclo of doHttpRequest func 2022-01-03 15:53:25 +08:00
dudaodong
56fc12c660 refactor: reduce gocyclo of ToString func 2022-01-03 15:15:22 +08:00
dudaodong
7a9b0847f9 fix: fix some go line issue in go report card 2022-01-03 14:57:14 +08:00
dudaodong
9266d99249 add chinese comment for GroupBy func 2022-01-02 22:12:01 +08:00
donutloop
f15131f032 Slice: find nothing case (#11)
The current behavior can result into wired edge cases.

**Current behavior**

if find was unsuccessfully then it will return the first element of the
slice

**Desired behavior**

if find was unsuccessfully then it should return negative ok and a none
value
2022-01-02 22:05:27 +08:00
donutloop
b4a49fccfd Slice: Add GroupBy func (#10)
Group by: split slice into two groups, applies on each slice element a
predicate func to categorize this element.

Changes

* Add groub by func
* Add test case for this func
2022-01-02 21:24:56 +08:00
dudaodong
94b1a1d383 feat: add Reset func for watcher 2022-01-01 20:14:41 +08:00
dudaodong
7db46696f6 release v1.1.5 2022-01-01 20:13:21 +08:00
dudaodong
d4f49af2ad feat: add watcher for record code excution time 2022-01-01 19:56:15 +08:00
dudaodong
ed4acc1c67 feat: add Shuffle func 2022-01-01 19:18:33 +08:00
dudaodong
042a00296f feat: add FlattenDeep func 2022-01-01 18:14:35 +08:00
dudaodong
b42aac53b3 feat: add Drop func 2022-01-01 17:20:41 +08:00
dudaodong
c625a88067 refactor: rename package 'utils' to 'internal' 2021-12-31 11:36:11 +08:00
dudaodong
e15ae9eb98 update: add Md5String func and Md5File func 2021-12-31 11:25:43 +08:00
dudaodong
bb4ac01209 Merge branch 'main' of github.com:duke-git/lancet into main 2021-12-31 10:18:11 +08:00
donutloop
147c1625b5 Slice: Optimize slice func tools (#9)
IntSlice and StringSlice: preallocate memory up front for output slice.
Instead returning a error throw a panic because most likely it's a
programming error.
Contain: rename slice to iterableType and add default case for type
mismatches
2021-12-31 10:15:38 +08:00
dudaodong
2aed55f704 refactor: function in slice.go 2021-12-31 10:12:14 +08:00
dudaodong
051f20caef release: v1.1.4, merge pr7 and pr8 2021-12-30 20:25:20 +08:00
donutloop
613785b07c function: catch earlier programming error (#8)
Place at first line of the function body a function type safe guard
check.
2021-12-30 20:22:00 +08:00
donutloop
0b0eb695e8 datetime: optimized func calls (#7)
Replace time parsing calls with less expensive operations
2021-12-30 10:29:10 +08:00
dudaodong
745082fff1 fix: update api url for http timeout issue in the task of github actions 2021-12-29 11:39:48 +08:00
dudaodong
24b8da360e release: v1.1.3, merge pr5 and pr6 2021-12-29 09:55:42 +08:00
donutloop
b106c428ae Every: use int counter (#6)
Use counter to verify all elements passed the perdicate func.
Replace slice of indexes with int counter.
2021-12-29 09:51:50 +08:00
dudaodong
8b1171d0cb fmt: go fmt for request_test.go 2021-12-28 19:28:55 +08:00
donutloop
ab012f2545 LowerFirst: use slicing and utf8 func tools (#5)
Replace looping with slicing and utf8 func tools operations.
2021-12-28 19:25:44 +08:00
dudaodong
a952cb208a release v1.1.2 2021-12-28 11:28:00 +08:00
dudaodong
f239a8ca8e fix: fix request timeout issue 2021-12-28 11:04:57 +08:00
dudaodong
5c6626b37e fmt: go fmt for function.go 2021-12-28 11:00:43 +08:00
dudaodong
16b5101600 fix: fix TestHttpPost timeout issue 2021-12-28 10:56:54 +08:00
dudaodong
ec983b7aa6 fix: fix
Intersection slice issue
2021-12-28 10:16:53 +08:00
dudaodong
56fc2aabd6 fmt: fix lint issue 2021-12-28 10:08:08 +08:00
dudaodong
0ddd52225b Merge branch 'main' of github.com:duke-git/lancet into main 2021-12-28 10:07:33 +08:00
donutloop
3919160e38 Optimized: Capitalize (#4)
* Use unicode.ToUpper func to convert first letter in string to upper case
letter.

* Preallocate memory with correct length and cap because the final
  string is not changing.
2021-12-28 10:04:15 +08:00
dudaodong
40ec5bc0f6 fmt: fix lint issue 2021-12-27 20:40:54 +08:00
dudaodong
99faeccb05 feat: add Intersection, Union, Without func for slice/slice.go 2021-12-27 19:54:04 +08:00
dudaodong
ad777bc877 feat: add Intersection, Union, Without func for slice/slice.go 2021-12-27 19:47:45 +08:00
dudaodong
589ce7404f refactor: update painc message 2021-12-27 15:12:18 +08:00
dudaodong
6ab4fca433 fmt: go fmt fileutil/file_test.go and function/function.go 2021-12-26 21:41:46 +08:00
dudaodong
b33a9cbfe3 release v1.0.10 2021-12-26 21:20:18 +08:00
donutloop
9ad9d1805b Regex validators: Precompile all known regex patterns (#3)
Reduce executions time of pattern matching, regex patterns are expensive to
compile at runtime.
2021-12-26 21:16:20 +08:00
dudaodong
0a1386f5a7 release v1.0.9 2021-12-26 13:57:05 +08:00
Beyond
b5541ea177 Merge pull request #2 from donutloop/slice/Some
Some: allocate slice to keep track of unused indexes is not necessary
2021-12-26 11:44:46 +08:00
Marcel Edmund Franke
578b1bba65 Some: allocate slice to keep track unused indexes is not necessary
Waste of memory for those unused indexes. It got replaced by a simple
boolean to keep track of it.
2021-12-25 13:04:03 +01:00
dudaodong
3045d56503 release: update readme.file v1.0.8, ParseHttpResponse in netutil/request.go 2021-12-20 11:43:39 +08:00
dudaodong
f1dbd943aa refactor: rename ParseResponse to ParseHttpResponse func in netutil/request.go 2021-12-17 17:29:28 +08:00
dudaodong
e87f3b70f0 feat: add ParseResponse func in netutil/request.go 2021-12-17 17:23:18 +08:00
dudaodong
26b59dd56b update: update go test command in workflows/codecov.yml 2021-12-14 11:02:19 +08:00
dudaodong
143aba7112 release: update readme file, new feature for functional programming 2021-12-14 10:55:07 +08:00
dudaodong
60f3a72c88 refactor: update Compose func in function.go 2021-12-14 10:29:53 +08:00
dudaodong
d1b74cfcfb feat: add Compose in function.go 2021-12-13 20:15:34 +08:00
dudaodong
72a89be8c1 feat: add function package for funcational programming 2021-12-11 13:30:11 +08:00
dudaodong
0cf59323ff update: update comment for ReadFileByLine in file.go 2021-12-10 10:51:50 +08:00
dudaodong
afec27fb4e release: new feature for slice and fileutil 2021-12-10 10:50:46 +08:00
dudaodong
3021985df9 feat: add ClearFile, ReadFileToString, ReadFileByLine into file.go 2021-12-09 20:19:13 +08:00
dudaodong
188d52cd9d feat: add Some and Every function in slice.go 2021-12-09 19:27:20 +08:00
dudaodong
8c8f991390 feat: add Find function in slice.go 2021-12-09 17:54:16 +08:00
dudaodong
b7bb7c6ae0 fmt: gofmt random_test.go 2021-12-01 20:38:54 +08:00
128 changed files with 26616 additions and 2286 deletions

View File

@@ -1,11 +1,13 @@
name: Test and coverage
name: test
on:
push:
branches:
- main
# - v2
pull_request:
branches:
- main
# - v2
jobs:
build:
runs-on: ubuntu-latest
@@ -15,8 +17,8 @@ jobs:
fetch-depth: 2
- uses: actions/setup-go@v2
with:
go-version: "1.16"
go-version: "1.18"
- name: Run coverage
run: go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
- name: Upload coverage to Codecov
run: bash <(curl -s https://codecov.io/bash)

3
.gitignore vendored
View File

@@ -3,4 +3,7 @@
.DS_Store
cryptor/*.txt
fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
cryptor/*.pem

689
README.md
View File

@@ -1,44 +1,54 @@
<div align="center">
<h1 style="width: 100%; text-align: center;">Lancet</h1>
<p style="font-size: 18px">
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
</p>
<div align="center" style="text-align: center;">
<div align=center>
<img src="./logo.png" width="200" height="200"/>
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.0.5-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![Release](https://img.shields.io/badge/release-2.0.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/duke-git/lancet)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/duke-git/lancet/blob/main/LICENSE)
</div>
<div STYLE="page-break-after: always;"></div>
<p style="font-size: 20px">
Lancet is a comprehensive, efficient, and reusable util function library of go. Inspired by the java apache common package and lodash.js.
</p>
English | [简体中文](./README_zh-CN.md)
</div>
### Feature
## Feature
- 👏 Comprehensive, efficient and reusable.
- 💪 100+ common go util functions, support string, slice, datetime, net, crypt...
- 💪 300+ go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depend on the go standard library.
- 🌍 Unit test for exery exported function.
- 🌍 Unit test for every exported function.
### Installation
## Installation
### Note:
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause v2.x.x rewrite all functions with generics of go1.18.</b>
```go
go get github.com/duke-git/lancet
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
```
### Usage
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.2.9. </b>
```go
go get github.com/duke-git/lancet@v1.2.9 // below go1.18, install latest version of v1.x.x
```
## Usage
Lancet organizes the code into package structure, and you need to import the corresponding package name when use it. For example, if you use string-related functions,import the strutil package like below:
```go
import "github.com/duke-git/lancet/strutil"
import "github.com/duke-git/lancet/v2/strutil"
```
### Example
## Example
Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported.
@@ -47,7 +57,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/strutil"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
@@ -57,394 +67,403 @@ func main() {
}
```
### API Documentation
## API Documentation
#### 1. convertor contains some functions for data convertion
- Support conversion between commonly used data types.
- Usage: import "github.com/duke-git/lancet/cryptor"
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
s := "12.3"
f, err := convertor.ToFloat(s)
if err != nil {
fmt.Errorf("error is %s", err.Error())
}
fmt.Println(f) // 12.3
}
import "github.com/duke-git/lancet/v2/algorithm"
```
#### Function list:
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BubbleSort)
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#CountSort)
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#HeapSort)
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#InsertionSort)
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#MergeSort)
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#QuickSort)
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#SelectionSort)
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#ShellSort)
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinarySearch)
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#BinaryIterativeSearch)
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LinearSearch)
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)
- Function list:
### 2. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
```go
func ColorHexToRGB(colorHex string) (red, green, blue int) //convert color hex to color rgb
func ColorRGBToHex(red, green, blue int) string //convert color rgb to color hex
func ToBool(s string) (bool, error) //convert string to a boolean
func ToBytes(data interface{}) ([]byte, error) //convert interface to bytes
func ToChar(s string) []string //convert string to char slice
func ToFloat(value interface{}) (float64, error) //convert value to float64, if input is not a float return 0.0 and error
func ToInt(value interface{}) (int64, error) //convert value to int64, if input is not a numeric format return 0 and error
func ToJson(value interface{}) (string, error) //convert value to a valid json string
func ToString(value interface{}) string //convert value to string
func StructToMap(value interface{}) (map[string]interface{}, error) //convert struct to map, only convert exported field, tag `json` should be set
import "github.com/duke-git/lancet/v2/concurrency"
```
#### Function list:
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Bridge)
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)
#### 2. cryptor is for data encryption and decryption
- Support md5, hmac, aes, des, ras.
- Usage: import "github.com/duke-git/lancet/cryptor"
### 3. Convertor package contains some functions for data convertion.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) // hello
}
import "github.com/duke-git/lancet/v2/convertor"
```
- Function list:
#### Function list:
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
### 4. Cryptor package is for data encryption and decryption.
```go
func AesEcbEncrypt(data, key []byte) []byte //AES ECB encrypt
func AesEcbDecrypt(encrypted, key []byte) []byte //AES ECB decrypt
func AesCbcEncrypt(data, key []byte) []byte //AES CBC encrypt
func AesCbcDecrypt(encrypted, key []byte) []byte //AES CBC decrypt
func AesCtrCrypt(data, key []byte) []byte //AES CTR encrypt / decrypt
func AesCfbEncrypt(data, key []byte) []byte //AES CFB encrypt
func AesCfbDecrypt(encrypted, key []byte) []byte //AES CFB decrypt
func AesOfbEncrypt(data, key []byte) []byte //AES OFB encrypt
func AesOfbDecrypt(data, key []byte) []byte //AES OFB decrypt
func Base64StdEncode(s string) string //base64 encode
func Base64StdDecode(s string) string //base64 decode
func DesCbcEncrypt(data, key []byte) []byte //DES CBC encrypt
func DesCbcDecrypt(encrypted, key []byte) []byte //DES CBC decrypt
func DesCtrCrypt(data, key []byte) []byte //DES CTR encrypt/decrypt
func DesCfbEncrypt(data, key []byte) []byte //DES CFB encrypt
func DesCfbDecrypt(encrypted, key []byte) []byte //DES CFB decrypt
func DesOfbEncrypt(data, key []byte) []byte //DES OFB encrypt
func DesOfbDecrypt(data, key []byte) []byte //DES OFB decrypt
func HmacMd5(data, key string) string //get hmac md5 value
func HmacSha1(data, key string) string //get hmac sha1 value
func HmacSha256(data, key string) string //get hmac sha256 value
func HmacSha512(data, key string) string //get hmac sha512 value
func Sha1(data string) string //get sha1 value
func Sha256(data string) string //getsha256 value
func Sha512(data string) string //get sha512 value
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) //generate RSA pem file
func RsaEncrypt(data []byte, pubKeyFileName string) []byte //RSA encrypt
func RsaDecrypt(data []byte, privateKeyFileName string) []byte //RSA decrypt
import "github.com/duke-git/lancet/v2/cryptor"
```
#### 3. datetime parse and format datetime
#### Function list:
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesEcbEncrypt)
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesEcbDecrypt)
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCbcEncrypt)
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCbcDecrypt)
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCtrCrypt)
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCfbEncrypt)
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesCfbDecrypt)
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesOfbEncrypt)
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#AesOfbDecrypt)
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Base64StdEncode)
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Base64StdDecode)
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesEcbEncrypt)
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesEcbDecrypt)
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCbcEncrypt)
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCbcDecrypt)
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCtrCrypt)
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCfbEncrypt)
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesCfbDecrypt)
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesOfbEncrypt)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5)
- [HmacSha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha1)
- [HmacSha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256)
- [HmacSha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512)
- [Md5String](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5String)
- [Md5File](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha1)
- [Sha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256)
- [Sha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)
### 5. Datetime package supports date and time format and compare.
- Parse and format datetime
- Usage: import "github.com/duke-git/lancet/datetime"
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
now := time.Now()
s := datetime.FormatTimeToStr(now, "yyyy-mm-dd hh:mm:ss")
fmt.Println(s) // 2021-11-24 11:16:55
}
import "github.com/duke-git/lancet/v2/datetime"
```
#### Function list:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddMinute)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)
- Function list:
### 6. Fileutil package implements some basic functions for file operations.
```go
func AddDay(t time.Time, day int64) time.Time //add or sub days to time
func AddHour(t time.Time, hour int64) time.Time //add or sub hours to time
func AddMinute(t time.Time, minute int64) time.Time //add or sub minutes to time
func GetNowDate() string //get current date, format is yyyy-mm-dd
func GetNowTime() string //get current time, format is hh:mm:ss
func GetNowDateTime() string //get current date and time, format is yyyy-mm-dd hh:mm:ss
func GetZeroHourTimestamp() int64 //return timestamp of zero hour (timestamp of 00:00)
func GetNightTimestamp() int64 //return timestamp of zero hour (timestamp of 23:59)
func FormatTimeToStr(t time.Time, format string) string //convert time to string
func FormatStrToTime(str, format string) time.Time //convert string to time
import "github.com/duke-git/lancet/v2/fileutil"
```
#### 4. fileutil basic functions for file operations
#### Function list
- Basic functions for file operations.
- Usage: import "github.com/duke-git/lancet/fileutil"
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CopyFile)
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#FileMode)
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#MiMeType)
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsExist)
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsLink)
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#IsDir)
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ListFileNames)
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#RemoveFile)
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)
### 7. Formatter contains some functions for data formatting.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
fmt.Println(fileutil.IsDir("./")) // true
}
import "github.com/duke-git/lancet/v2/formatter"
```
#### Function list:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
- 函数列表:
### 8. Function package can control the flow of function execution and support part of functional programming
```go
func CreateFile(path string) bool // create a file in path
func CopyFile(srcFilePath string, dstFilePath string) error //copy src file to dst file
func IsExist(path string) bool //checks if a file or directory exists
func IsDir(path string) bool //checks if the path is directy or not
func ListFileNames(path string) ([]string, error) //return all file names in the path
func RemoveFile(path string) error //remove the path file
import "github.com/duke-git/lancet/v2/function"
```
#### 5. formatter is for data format
#### Function list:
- [After](https://github.com/duke-git/lancet/blob/main/docs/function.md#After)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function.md#Before)
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function.md#Curry)
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function.md#Compose)
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function.md#Debounced)
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function.md#Delay)
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
- Contain some formatting function
- Usage: import "github.com/duke-git/lancet/formatter"
### 9. Maputil package includes some functions to manipulate map.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345"
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
import "github.com/duke-git/lancet/v2/maputil"
```
- Function list:
#### Function list:
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)
### 10. Mathutil package implements some functions for math calculation.
```go
func Comma(v interface{}, symbol string) string //add comma to number by every 3 numbers from right. ahead by symbol char
import "github.com/duke-git/lancet/v2/mathutil"
```
#### 6. netutil is for net process
#### Function list:
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MaxBy)
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#MinBy)
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)
- Ip and http request method.
- Usage: import "github.com/duke-git/lancet/netutil".
- The Http function params orderurl, header, query string, body, httpclient.
### 11. Netutil package contains functions to get net information and send http request.
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/netutil"
)
func main() {
url := "https://gutendex.com/books?"
header := make(map[string]string)
header["Content-Type"] = "application/json"
queryParams := make(map[string]interface{})
queryParams["ids"] = "1"
resp, err := netutil.HttpGet(url, header, queryParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
import "github.com/duke-git/lancet/v2/netutil"
```
- Function list:
#### Function list:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
### 12. Random package implements some basic functions to generate random int and string.
```go
func GetInternalIp() string //get internal ip
func GetPublicIpInfo() (*PublicIpInfo, error) //get public ip info: country, region, isp, city, lat, lon, ip
func IsPublicIP(IP net.IP) bool //判断ip是否为公共ip
func HttpGet(url string, params ...interface{}) (*http.Response, error) //http get request
func HttpPost(url string, params ...interface{}) (*http.Response, error) //http post request
func HttpPut(url string, params ...interface{}) (*http.Response, error) //http put request
func HttpDelete(url string, params ...interface{}) (*http.Response, error) //http delete request
func HttpPatch(url string, params ...interface{}) (*http.Response, error) //http patch request
func ConvertMapToQueryString(param map[string]interface{}) string //convert map to url query string
import "github.com/duke-git/lancet/v2/random"
```
#### 7. random is for rand string and int generation
#### Function list:
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandBytes)
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
- Generate random string and int.
- Usage: import "github.com/duke-git/lancet/random".
### 13. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
}
import "github.com/duke-git/lancet/v2/retry"
```
- Function list:
#### Function list:
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)
### 14. Slice contains some functions to manipulate slice.
```go
func RandBytes(length int) []byte //generate random []byte
func RandInt(min, max int) int //generate random int
func RandString(length int) string //generate random string
import "github.com/duke-git/lancet/v2/slice"
```
#### 8. slice is for process slice
#### Function list:
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IndexOf)
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice.md#LastIndexOf)
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SymmetricDifference)
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
- Contain function for process slice.
- Usage: import "github.com/duke-git/lancet/slice"
- Due to the unstable support of generic, most of the slice processing function parameter and return value is interface {}. After go generic is stable, the related functions will be refactored.
### 15. Strutil package contains some functions to manipulate string.
```go
import "github.com/duke-git/lancet/v2/strutil"
```
#### Function list:
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReverseStr)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
### 16. System package contain some functions about os, runtime, shell command.
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/slice"
)
func main() {
nums := []int{1, 4, 3, 4, 6, 7, 3}
uniqueNums, _ := slice.IntSlice(slice.Unique(nums))
fmt.Println(uniqueNums) //[1 4 3 6 7]
}
import "github.com/duke-git/lancet/v2/system"
```
#### Function list:
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsWindows)
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsLinux)
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system.md#IsMac)
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsEnv)
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#SetOsEnv)
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#RemoveOsEnv)
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system.md#CompareOsEnv)
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)
- Function list:
### 17. Validator package contains some functions for data validation.
```go
func Contain(slice interface{}, value interface{}) bool //check if the value is in the slice or not
func Chunk(slice []interface{}, size int) [][]interface{} //creates an slice of elements split into groups the length of `size`.
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //convert originalSlice to newSliceType
func Difference(slice1, slice2 interface{}) interface{} //creates an slice of whose element not included in the other given slice
func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //delete the element of slice from start index to end index - 1
func Filter(slice, function interface{}) interface{} //filter slice, function signature should be func(index int, value interface{}) bool
func IntSlice(slice interface{}) ([]int, error) //convert value to int slice
func InterfaceSlice(slice interface{}) []interface{} //convert value to interface{} slice
func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //insert the element into slice at index.
func Map(slice, function interface{}) interface{} //map lisce, function signature should be func(index int, value interface{}) interface{}
func ReverseSlice(slice interface{}) //revere slice
func Reduce(slice, function, zero interface{}) interface{} //reduce slice, function signature should be func(index int, value1, value2 interface{}) interface{}
func SortByField(slice interface{}, field string, sortType ...string) error //sort struct slice by field
func StringSlice(slice interface{}) []string //convert value to string slice
func Unique(slice interface{}) interface{} //remove duplicate elements in slice
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //update the slice element at index.
import "github.com/duke-git/lancet/v2/validator"
```
#### 9. strutil is for processing string
#### Function list:
- Contain functions to precess string
- Usage: import "github.com/duke-git/lancet/strutil"
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
### 18. xerror package implements helpers for errors.
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "Foo-Bar"
camelCaseStr := strutil.CamelCase(str)
fmt.Println(camelCaseStr) //fooBar
}
import "github.com/duke-git/lancet/v2/xerror"
```
#### Function list:
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Unwrap)
- Function list:
## How to Contribute
```go
func After(s, char string) string //create substring in source string after position when char first appear
func AfterLast(s, char string) string //create substring in source string after position when char last appear
func Before(s, char string) string //create substring in source string before position when char first appear
func BeforeLast(s, char string) string //create substring in source string before position when char last appear
func CamelCase(s string) string //covert string to camelCase string. "foo bar" -> "fooBar"
func Capitalize(s string) string //convert the first character of a string to upper case, "fOO" -> "Foo"
func IsString(v interface{}) bool //check if the value data type is string or not
func KebabCase(s string) string //covert string to kebab-case, "foo_Bar" -> "foo-bar"
func LowerFirst(s string) string //convert the first character of string to lower case
func PadEnd(source string, size int, padStr string) string //pads string on the right side if it's shorter than size
func PadStart(source string, size int, padStr string) string//pads string on the left side if it's shorter than size
func ReverseStr(s string) string //return string whose char order is reversed to the given string
func SnakeCase(s string) string //covert string to snake_case "fooBar" -> "foo_bar"
```
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
#### 10. validator is for data validation
- Contain function for data validation.
- Usage: import "github.com/duke-git/lancet/validator".
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/validator"
)
func main() {
str := "Foo-Bar"
isAlpha := validator.IsAlpha(str)
fmt.Println(isAlpha) //false
}
```
- Function list:
```go
func ContainChinese(s string) bool //check if the string contain mandarin chinese
func IsAlpha(s string) bool //checks if the string contains only letters (a-zA-Z)
func IsBase64(base64 string) bool //check if the string is base64 string
func IsChineseMobile(mobileNum string) bool //check if the string is chinese mobile number
func IsChineseIdNum(id string) bool //check if the string is chinese id number
func IsChinesePhone(phone string) bool //check if the string is chinese phone number
func IsCreditCard(creditCart string) bool //check if the string is credit card
func IsDns(dns string) bool //check if the string is dns
func IsEmail(email string) bool //check if the string is a email address
func IsEmptyString(s string) bool //check if the string is empty
func IsFloatStr(s string) bool //check if the string can convert to a float
func IsNumberStr(s string) bool //check if the string can convert to a number
func IsRegexMatch(s, regex string) bool //check if the string match the regexp
func IsIntStr(s string) bool //check if the string can convert to a integer
func IsIp(ipstr string) bool //check if the string is a ip address
func IsIpV4(ipstr string) bool //check if the string is a ipv4 address
func IsIpV6(ipstr string) bool //check if the string is a ipv6 address
func IsStrongPassword(password string, length int) bool //check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?><))
func IsWeakPassword(password string) bool //check if the string is weak passwordonly letter or only number or letter + number
```
1. Fork the repository.
2. Create your feature branch.
3. Commit your changes.
4. Push to the branch
5. Create new pull request.

View File

@@ -1,45 +1,54 @@
<div align="center">
<h1 style="width: 100%; text-align: center;">Lancet</h1>
<p style="font-size: 18px">
lancet柳叶刀是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
</p>
<div align="center" style="text-align: center;">
<div align=center>
<img src="./logo.png" width="200" height="200"/>
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-1.0.5-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com//duke-git/lancet?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet)](https://goreportcard.com/report/github.com/duke-git/lancet)
[![Release](https://img.shields.io/badge/release-2.0.7-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
[![codecov](https://codecov.io/gh/duke-git/lancet/branch/main/graph/badge.svg?token=FC48T1F078)](https://codecov.io/gh/duke-git/lancet)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/duke-git/lancet/blob/main/LICENSE)
</div>
<div STYLE="page-break-after: always;"></div>
<p style="font-size: 18px">
lancet柳叶刀是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。
</p>
简体中文 | [English](./README.md)
</div>
### 特性
## 特性
- 👏 全面、高效、可复用
- 💪 100+常用go工具函数支持string、slice、datetime、net、crypt...
- 💪 300+常用go工具函数支持string、slice、datetime、net、crypt...
- 💅 只依赖go标准库
- 🌍 所有导出函数单元测试覆盖率100%
### 安装
## 安装
### Note:
1. <b>对于使用go1.18及以上的用户建议安装v2.x.x。 因为v2.x.x用go1.18的泛型重写了大部分函数。</b>
```go
go get github.com/duke-git/lancet
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
```
### 用法
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.2.9。</b>
```go
go get github.com/duke-git/lancet@v1.2.9 // 使用go1.18以下版本, 必须安装v1.x.x版本
```
## 用法
lancet是以包的结构组织代码的使用时需要导入相应的包名。例如如果使用字符串相关函数需要导入strutil包:
```go
import "github.com/duke-git/lancet/strutil"
import "github.com/duke-git/lancet/v2/strutil"
```
### 例子
## 例子
此处以字符串工具函数ReverseStr逆序字符串为例需要导入strutil包:
@@ -48,7 +57,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/strutil"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
@@ -58,394 +67,405 @@ func main() {
}
```
### API文档
## API文档
#### 1. convertor数据转换包
- 转换函数支持常用数据类型之间的转换
- 导入包import "github.com/duke-git/lancet/convertor"
### 1. algorithm算法包实现一些基本算法。eg. sort, search.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
s := "12.3"
f, err := convertor.ToFloat(s)
if err != nil {
fmt.Errorf("error is %s", err.Error())
}
fmt.Println(f) // 12.3
}
import "github.com/duke-git/lancet/v2/algorithm"
```
#### Function list:
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BubbleSort)
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#CountSort)
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#HeapSort)
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#InsertionSort)
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#MergeSort)
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#QuickSort)
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#SelectionSort)
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#ShellSort)
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinarySearch)
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinaryIterativeSearch)
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
- 函数列表:
### 2. 并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
```go
func ColorHexToRGB(colorHex string) (red, green, blue int) //颜色值16进制转rgb
func ColorRGBToHex(red, green, blue int) string //颜色值rgb转16进制
func ToBool(s string) (bool, error) //字符串转成Bool
func ToBytes(data interface{}) ([]byte, error) //interface转成byte slice
func ToChar(s string) []string //字符串转成字符slice
func ToFloat(value interface{}) (float64, error) //interface转成float64
func ToInt(value interface{}) (int64, error) //interface转成int64
func ToJson(value interface{}) (string, error) //interface转成json string
func ToString(value interface{}) string //interface转成string
func StructToMap(value interface{}) (map[string]interface{}, error) //struct串转成map, 需要设置struct tag `json`
import "github.com/duke-git/lancet/v2/concurrency"
```
#### 2. cryptor加解密包
- 加密函数支持md5, hmac, aes, des, ras
- 导入包import "github.com/duke-git/lancet/cryptor"
#### Function list:
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Bridge)
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
### 3. convertor转换器包支持一些常见的数据类型转换。
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
)
func main() {
data := "hello"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) // hello
}
import "github.com/duke-git/lancet/v2/convertor"
```
- 函数列表:
#### 函数列表:
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
### 4. cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
```go
func AesEcbEncrypt(data, key []byte) []byte //AES ECB模式加密
func AesEcbDecrypt(encrypted, key []byte) []byte //AES ECB模式解密
func AesCbcEncrypt(data, key []byte) []byte //AES CBC模式加密
func AesCbcDecrypt(encrypted, key []byte) []byte //AES CBC模式解密
func AesCtrCrypt(data, key []byte) []byte //AES CTR模式加密/解密
func AesCfbEncrypt(data, key []byte) []byte //AES CFB模式加密
func AesCfbDecrypt(encrypted, key []byte) []byte //AES CFB模式解密
func AesOfbEncrypt(data, key []byte) []byte //AES OFB模式加密
func AesOfbDecrypt(data, key []byte) []byte //AES OFB模式解密
func Base64StdEncode(s string) string //base64编码
func Base64StdDecode(s string) string //base64解码
func DesCbcEncrypt(data, key []byte) []byte //DES CBC模式加密
func DesCbcDecrypt(encrypted, key []byte) []byte //DES CBC模式解密
func DesCtrCrypt(data, key []byte) []byte //DES CTR模式加密/解密
func DesCfbEncrypt(data, key []byte) []byte //DES CFB模式加密
func DesCfbDecrypt(encrypted, key []byte) []byte //DES CFB模式解密
func DesOfbEncrypt(data, key []byte) []byte //DES OFB模式加密
func DesOfbDecrypt(data, key []byte) []byte //DES OFB模式解密
func HmacMd5(data, key string) string //获取hmac md5值
func HmacSha1(data, key string) string //获取hmac sha1值
func HmacSha256(data, key string) string //获取hmac sha256值
func HmacSha512(data, key string) string //获取hmac sha512值
func Sha1(data string) string //获取sha1值
func Sha256(data string) string //获取sha256值
func Sha512(data string) string //获取sha512值
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) //生成RSA私钥文件
func RsaEncrypt(data []byte, pubKeyFileName string) []byte //RSA加密
func RsaDecrypt(data []byte, privateKeyFileName string) []byte //RSA解密
import "github.com/duke-git/lancet/v2/cryptor"
```
#### 3. datetime日期时间处理包
#### 函数列表:
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbEncrypt)
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbDecrypt)
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcEncrypt)
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcDecrypt)
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCtrCrypt)
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbEncrypt)
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbDecrypt)
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbEncrypt)
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbDecrypt)
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdEncode)
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdDecode)
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbEncrypt)
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbDecrypt)
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcEncrypt)
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcDecrypt)
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCtrCrypt)
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbEncrypt)
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbDecrypt)
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbEncrypt)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)
- [HmacSha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)
- [HmacSha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)
- [HmacSha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)
- [Md5String](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)
- [Md5File](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)
- [Sha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)
- [Sha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)
### 5. datetime日期时间处理包格式化日期比较日期。
- 处理日期时间
- 导入包import "github.com/duke-git/lancet/datetime"
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datetime"
)
func main() {
now := time.Now()
s := datetime.FormatTimeToStr(now, "yyyy-mm-dd hh:mm:ss")
fmt.Println(s) // 2021-11-24 11:16:55
}
import "github.com/duke-git/lancet/v2/datetime"
```
#### 函数列表:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)
- 函数列表:
### 6. fileutil包支持文件基本操作。
```go
func AddDay(t time.Time, day int64) time.Time //加减天数
func AddHour(t time.Time, hour int64) time.Time //加减小时数
func AddMinute(t time.Time, minute int64) time.Time //加减分钟数
func GetNowDate() string //获取当天日期 格式yyyy-mm-dd
func GetNowTime() string //获取当前时间 格式hh:mm:ss
func GetNowDateTime() string //获取当前日期时间 格式yyyy-mm-dd hh:mm:ss
func GetZeroHourTimestamp() int64 //获取当天零时时间戳00:00)
func GetNightTimestamp() int64 //获取当天23时时间戳23:59)
func FormatTimeToStr(t time.Time, format string) string //时间格式化字符串
func FormatStrToTime(str, format string) time.Time //字符串转换成时间
import "github.com/duke-git/lancet/v2/fileutil"
```
#### 4. fileutil文件处理包
#### 函数列表:
- 文件处理常用函数
- 导入包import "github.com/duke-git/lancet/fileutil"
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ClearFile)
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateFile)
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CopyFile)
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileMode)
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MiMeType)
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsExist)
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsLink)
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsDir)
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ListFileNames)
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#RemoveFile)
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
### 7. formatter格式化器包含一些数据格式化处理方法。
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
fmt.Println(fileutil.IsDir("./")) // true
}
import "github.com/duke-git/lancet/v2/formatter"
```
#### 函数列表:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
- 函数列表:
### 8. function函数包控制函数执行流程包含部分函数式编程。
```go
func IsExist(path string) bool //判断文件/目录是否存在
func CreateFile(path string) bool //创建文件
func IsDir(path string) bool //判断是否为目录
func RemoveFile(path string) error //删除文件
func CopyFile(srcFilePath string, dstFilePath string) error //复制文件
func ListFileNames(path string) ([]string, error) //列出目录下所有文件名称
import "github.com/duke-git/lancet/v2/function"
```
#### 5. formatter格式化处理包
#### 函数列表:
- [After](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Curry)
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
- 格式化相关处理函数
- 导入包import "github.com/duke-git/lancet/formatter"
### 9. maputil包包括一些操作map的函数.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345"
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
import "github.com/duke-git/lancet/v2/maputil"
```
- 函数列表
#### 函数列表:
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
### 10. mathutil包实现了一些数学计算的函数。
```go
func Comma(v interface{}, symbol string) string //用逗号每隔3位分割数字/字符串
import "github.com/duke-git/lancet/v2/mathutil"
```
#### 6. netutil网络处理包
#### Function list:
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)
- [MaxBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MaxBy)
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)
- [MinBy](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#MinBy)
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
- 处理ip, http请求相关函数
- 导入包import "github.com/duke-git/lancet/netutil"
- http方法params参数顺序header, query string, body, httpclient
### 11. netutil网络包支持获取ip地址发送http请求
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/netutil"
)
func main() {
url := "https://gutendex.com/books?"
header := make(map[string]string)
header["Content-Type"] = "application/json"
queryParams := make(map[string]interface{})
queryParams["ids"] = "1"
resp, err := netutil.HttpGet(url, header, queryParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
import "github.com/duke-git/lancet/v2/netutil"
```
- 函数列表
#### 函数列表:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
### 12. random随机数生成器包可以生成随机[]bytes, int, string。
```go
func GetInternalIp() string //获取内部ip
func GetPublicIpInfo() (*PublicIpInfo, error) //获取公共ip信息: country, region, isp, city, lat, lon, ip
func IsPublicIP(IP net.IP) bool //判断ip是否为公共ip
func HttpGet(url string, params ...interface{}) (*http.Response, error) //http get请求
func HttpPost(url string, params ...interface{}) (*http.Response, error) //http post请求
func HttpPut(url string, params ...interface{}) (*http.Response, error) //http put请求
func HttpDelete(url string, params ...interface{}) (*http.Response, error) //http delete请求
func HttpPatch(url string, params ...interface{}) (*http.Response, error) //http patch请求
func ConvertMapToQueryString(param map[string]interface{}) string //将map转换成url query string
import "github.com/duke-git/lancet/v2/random"
```
#### 7. random随机数处理包
- 生成和处理随机数
- 导入包import "github.com/duke-git/lancet/random"
#### 函数列表:
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
### 13. retry重试执行函数直到函数运行成功或被context cancel。
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
}
import "github.com/duke-git/lancet/v2/retry"
```
- 函数列表
#### 函数列表:
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
### 14. slice包包含操作切片的方法集合。
```go
func RandBytes(length int) []byte //生成随机[]byte
func RandInt(min, max int) int //生成随机int
func RandString(length int) string //生成随机string
import "github.com/duke-git/lancet/v2/slice"
```
#### 8. slice切片操作包
#### 函数列表:
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)
- [IndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IndexOf)
- [LastIndexOf](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#LastIndexOf)
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SymmetricDifference)
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateAt)
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
- 切片操作相关函数
- 导入包import "github.com/duke-git/lancet/slice"
- 由于go目前对范型支持不稳定slice处理函数参数和返回值大部分为interface{}, 待范型特性稳定后,会重构相关函数
### 15. strutil包含处理字符串的相关函数。
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/slice"
)
func main() {
nums := []int{1, 4, 3, 4, 6, 7, 3}
uniqueNums, _ := slice.IntSlice(slice.Unique(nums))
fmt.Println(uniqueNums) //[1 4 3 6 7]
}
import "github.com/duke-git/lancet/v2/strutil"
```
- 函数列表
#### 函数列表:
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
### 16. system包含os, runtime, shell command相关函数。
```go
func Contain(slice interface{}, value interface{}) bool //判断slice是否包含value
func Chunk(slice []interface{}, size int) [][]interface{} //均分slice
func ConvertSlice(originalSlice interface{}, newSliceType reflect.Type) interface{} //将originalSlice转换为 newSliceType
func Difference(slice1, slice2 interface{}) interface{} //返回
func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error) //删除切片中start到end位置的值
func Filter(slice, function interface{}) interface{} //过滤slice, 函数签名func(index int, value interface{}) bool
func IntSlice(slice interface{}) ([]int, error) //转成int切片
func InterfaceSlice(slice interface{}) []interface{} //转成interface{}切片
func InsertByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置插入value
func Map(slice, function interface{}) interface{} //遍历切片, 函数签名func(index int, value interface{}) interface{}
func ReverseSlice(slice interface{}) //反转切片
func Reduce(slice, function, zero interface{}) interface{} //切片reduce操作 函数签名func(index int, value1, value2 interface{}) interface{}
func SortByField(slice interface{}, field string, sortType ...string) error //对struct切片进行排序
func StringSlice(slice interface{}) []string //转为string切片
func Unique(slice interface{}) interface{} //去重切片
func UpdateByIndex(slice interface{}, index int, value interface{}) (interface{}, error) //在切片中index位置更新value
import "github.com/duke-git/lancet/v2/system"
```
#### 9. strutil字符串处理包
#### 函数列表:
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsWindows)
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsLinux)
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsMac)
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsEnv)
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#SetOsEnv)
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#RemoveOsEnv)
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#CompareOsEnv)
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
- 字符串操作相关函数
- 导入包import "github.com/duke-git/lancet/strutil"
### 17. validator验证器包包含常用字符串格式验证函数。
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/strutil"
)
func main() {
str := "Foo-Bar"
camelCaseStr := strutil.CamelCase(str)
fmt.Println(camelCaseStr) //fooBar
}
import "github.com/duke-git/lancet/v2/validator"
```
#### 函数列表:
- 函数列表:
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainChinese)
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLetter)
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLower)
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainUpper)
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAlpha)
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllUpper)
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseMobile)
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseIdNum)
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChinesePhone)
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmail)
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmptyString)
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsRegexMatch)
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
validator.md#IsWeakPassword)
### 18. xerror包实现一些错误处理函数
```go
func After(s, char string) string //截取字符串中char第一次出现之后的字符串
func AfterLast(s, char string) string //截取字符串中char最后一次出现之后的字符串
func Before(s, char string) string //截取字符串中char第一次出现之前的字符串
func BeforeLast(s, char string) string //截取字符串中char最后一次出现之前的字符串
func CamelCase(s string) string //字符串转为cameCase, "foo bar" -> "fooBar"
func Capitalize(s string) string //字符串转为Capitalize, "fOO" -> "Foo"
func IsString(v interface{}) bool //判断是否是字符串
func KebabCase(s string) string //字符串转为KebabCase, "foo_Bar" -> "foo-bar"
func LowerFirst(s string) string //字符串的第一个字母转为小写字母
func PadEnd(source string, size int, padStr string) string //字符串末尾填充size个字符
func PadStart(source string, size int, padStr string) string//字符串开头填充size个字符
func ReverseStr(s string) string //字符串逆袭
func SnakeCase(s string) string //字符串转为SnakeCase, "fooBar" -> "foo_bar"
import "github.com/duke-git/lancet/v2/xerror"
```
#### 函数列表:
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)
#### 10. validator验证器包
## 如何贡献代码
- 数据校验相关函数
- 导入包import "github.com/duke-git/lancet/validator"
非常感激任何的代码提交以使lancet的功能越来越强大。创建pull request时请遵守以下规则。
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/validator"
)
func main() {
str := "Foo-Bar"
isAlpha := validator.IsAlpha(str)
fmt.Println(isAlpha) //false
}
```
- 函数列表:
```go
func ContainChinese(s string) bool //判断字符串中是否含有中文字符
func IsAlpha(s string) bool //判断字符串是否只含有字母
func IsBase64(base64 string) bool //判断字符串是base64
func IsChineseMobile(mobileNum string) bool //判断字符串是否是手机号
func IsChineseIdNum(id string) bool //判断字符串是否是身份证号
func IsChinesePhone(phone string) bool //判断字符串是否是座机电话号码
func IsCreditCard(creditCart string) bool //判断字符串是否是信用卡
func IsDns(dns string) bool //判断字符串是否是DNS
func IsEmail(email string) bool //判断字符串是否是邮箱
func IsEmptyString(s string) bool //判断字符串是否为空
func IsFloatStr(s string) bool //判断字符串是否可以转成float
func IsNumberStr(s string) bool //判断字符串是否可以转成数字
func IsRegexMatch(s, regex string) bool //判断字符串是否match正则表达式
func IsIntStr(s string) bool //判断字符串是否可以转成整数
func IsIp(ipstr string) bool //判断字符串是否是ip
func IsIpV4(ipstr string) bool //判断字符串是否是ipv4
func IsIpV6(ipstr string) bool //判断字符串是否是ipv6
func IsStrongPassword(password string, length int) bool //判断字符串是否是强密码(大小写字母+数字+特殊字符)
func IsWeakPassword(password string) bool //判断字符串是否是弱密码(只有字母或数字)
```
1. Fork lancet仓库。
2. 创建自己的特性分支。
3. 提交变更。
4. Push分支。
5. 创建新的pull request。

102
algorithm/lru_cache.go Normal file
View File

@@ -0,0 +1,102 @@
package algorithm
type lruNode[K comparable, V any] struct {
key K
value V
pre *lruNode[K, V]
next *lruNode[K, V]
}
// newLruNode return a lruNode pointer
func newLruNode[K comparable, V any](key K, value V) *lruNode[K, V] {
return &lruNode[K, V]{
key: key,
value: value,
pre: nil,
next: nil,
}
}
// LRUCache lru cache (thread unsafe)
type LRUCache[K comparable, V any] struct {
cache map[K]*lruNode[K, V]
head *lruNode[K, V]
tail *lruNode[K, V]
capacity int
length int
}
// NewLRUCache return a LRUCache pointer
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
return &LRUCache[K, V]{
cache: make(map[K]*lruNode[K, V], capacity),
head: nil,
tail: nil,
capacity: capacity,
length: 0,
}
}
// Get value of key from lru cache
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
var value V
node, ok := l.cache[key]
if ok {
l.moveToHead(node)
return node.value, true
}
return value, false
}
// Put value of key into lru cache
func (l *LRUCache[K, V]) Put(key K, value V) {
node, ok := l.cache[key]
if !ok {
newNode := newLruNode(key, value)
l.cache[key] = newNode
l.addNode(newNode)
if len(l.cache) > l.capacity {
oldKey := l.deleteNode(l.head)
delete(l.cache, oldKey)
}
} else {
node.value = value
l.moveToHead(node)
}
l.length = len(l.cache)
}
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
if l.tail != nil {
l.tail.next = node
node.pre = l.tail
node.next = nil
}
l.tail = node
if l.head == nil {
l.head = node
}
}
func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
if node == l.tail {
l.tail = l.tail.pre
} else if node == l.head {
l.head = l.head.next
} else {
node.pre.next = node.next
node.next.pre = node.pre
}
return node.key
}
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
if l.tail == node {
return
}
l.deleteNode(node)
l.addNode(node)
}

View File

@@ -0,0 +1,36 @@
package algorithm
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLRUCache(t *testing.T) {
asssert := internal.NewAssert(t, "TestLRUCache")
cache := NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
_, ok := cache.Get(0)
asssert.Equal(false, ok)
v, ok := cache.Get(1)
asssert.Equal(true, ok)
asssert.Equal(1, v)
v, ok = cache.Get(2)
asssert.Equal(true, ok)
asssert.Equal(2, v)
cache.Put(3, 3)
v, ok = cache.Get(1)
asssert.Equal(false, ok)
asssert.NotEqual(1, v)
v, ok = cache.Get(3)
asssert.Equal(true, ok)
asssert.Equal(3, v)
}

63
algorithm/search.go Normal file
View File

@@ -0,0 +1,63 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
// If a target is found, the index of the target is returned. Else the function return -1
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
for i, v := range slice {
if comparator.Compare(v, target) == 0 {
return i
}
}
return -1
}
// BinarySearch search for target within a sorted slice, recursive call itself.
// If a target is found, the index of the target is returned. Else the function return -1
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
if highIndex < lowIndex || len(sortedSlice) == 0 {
return -1
}
midIndex := int(lowIndex + (highIndex-lowIndex)/2)
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
if isMidValGreatTarget {
return BinarySearch(sortedSlice, target, lowIndex, midIndex-1, comparator)
} else if isMidValLessTarget {
return BinarySearch(sortedSlice, target, midIndex+1, highIndex, comparator)
}
return midIndex
}
// BinaryIterativeSearch search for target within a sorted slice.
// If a target is found, the index of the target is returned. Else the function return -1
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
startIndex := lowIndex
endIndex := highIndex
var midIndex int
for startIndex <= endIndex {
midIndex = int(startIndex + (endIndex-startIndex)/2)
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
if isMidValGreatTarget {
endIndex = midIndex - 1
} else if isMidValLessTarget {
startIndex = midIndex + 1
} else {
return midIndex
}
}
return -1
}

33
algorithm/search_test.go Normal file
View File

@@ -0,0 +1,33 @@
package algorithm
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
func TestLinearSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestLinearSearch")
comparator := &intComparator{}
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
}
func TestBinarySearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinarySearch")
comparator := &intComparator{}
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
func TestBinaryIterativeSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
comparator := &intComparator{}
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}

188
algorithm/sorter.go Normal file
View File

@@ -0,0 +1,188 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// BubbleSort use bubble to sort slice.
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := 0; j < len(slice)-1-i; j++ {
isCurrGreatThanNext := comparator.Compare(slice[j], slice[j+1]) == 1
if isCurrGreatThanNext {
swap(slice, j, j+1)
}
}
}
}
// InsertionSort use insertion to sort slice.
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := i; j > 0; j-- {
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
if isPreLessThanCurrent {
swap(slice, j, j-1)
} else {
break
}
}
}
}
// SelectionSort use selection to sort slice.
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
min := i
for j := i + 1; j < len(slice); j++ {
if comparator.Compare(slice[j], slice[min]) == -1 {
min = j
}
}
swap(slice, i, min)
}
}
// ShellSort shell sort slice.
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
gap := 1
for gap < size/3 {
gap = 3*gap + 1
}
for gap >= 1 {
for i := gap; i < size; i++ {
for j := i; j >= gap && comparator.Compare(slice[j], slice[j-gap]) == -1; j -= gap {
swap(slice, j, j-gap)
}
}
gap = gap / 3
}
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
QuickSort(slice, lowIndex, p-1, comparator)
QuickSort(slice, p+1, highIndex, comparator)
}
}
// partition split slice into two parts
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
p := slice[highIndex]
i := lowIndex
for j := lowIndex; j < highIndex; j++ {
if comparator.Compare(slice[j], p) == -1 { //slice[j] < p
swap(slice, i, j)
i++
}
}
swap(slice, i, highIndex)
return i
}
// HeapSort use heap to sort slice
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
for i := size/2 - 1; i >= 0; i-- {
sift(slice, i, size-1, comparator)
}
for j := size - 1; j > 0; j-- {
swap(slice, 0, j)
sift(slice, 0, j-1, comparator)
}
}
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
i := lowIndex
j := 2*i + 1
temp := slice[i]
for j <= highIndex {
if j < highIndex && comparator.Compare(slice[j], slice[j+1]) == -1 { //slice[j] < slice[j+1]
j++
}
if comparator.Compare(temp, slice[j]) == -1 { //tmp < slice[j]
slice[i] = slice[j]
i = j
j = 2*i + 1
} else {
break
}
}
slice[i] = temp
}
// MergeSort merge sorting for slice
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
mergeSort(slice, 0, len(slice)-1, comparator)
}
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
mid := (lowIndex + highIndex) / 2
mergeSort(slice, lowIndex, mid, comparator)
mergeSort(slice, mid+1, highIndex, comparator)
merge(slice, lowIndex, mid, highIndex, comparator)
}
}
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
i := lowIndex
j := midIndex + 1
temp := []T{}
for i <= midIndex && j <= highIndex {
//slice[i] < slice[j]
if comparator.Compare(slice[i], slice[j]) == -1 {
temp = append(temp, slice[i])
i++
} else {
temp = append(temp, slice[j])
j++
}
}
if i <= midIndex {
temp = append(temp, slice[i:midIndex+1]...)
} else {
temp = append(temp, slice[j:highIndex+1]...)
}
for k := 0; k < len(temp); k++ {
slice[lowIndex+k] = temp[k]
}
}
// CountSort use count sorting for slice
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
out := make([]T, size)
for i := 0; i < size; i++ {
count := 0
for j := 0; j < size; j++ {
//slice[i] > slice[j]
if comparator.Compare(slice[i], slice[j]) == 1 {
count++
}
}
out[count] = slice[i]
}
return out
}
// swap two slice value at index i and j
func swap[T any](slice []T, i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}

218
algorithm/sorter_test.go Normal file
View File

@@ -0,0 +1,218 @@
package algorithm
import (
"fmt"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
// People test mock data
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
}
// var peoples = []people{
// {Name: "a", Age: 20},
// {Name: "b", Age: 10},
// {Name: "c", Age: 17},
// {Name: "d", Age: 8},
// {Name: "e", Age: 28},
// }
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
// var intSlice = []int{2, 1, 5, 3, 6, 4}
func TestBubbleSortForStructSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
BubbleSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestBubbleSortForIntSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
asssert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
}
func TestInsertionSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestInsertionSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
InsertionSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestSelectionSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestSelectionSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
SelectionSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestShellSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestShellSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
ShellSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestQuickSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestQuickSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
QuickSort(peoples, 0, len(peoples)-1, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestHeapSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestHeapSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
HeapSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestMergeSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestMergeSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
MergeSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)
asssert.Equal(expected, actual)
}
func TestCountSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestCountSort")
peoples := []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
sortedPeopleByAge := CountSort(peoples, comparator)
t.Log(sortedPeopleByAge)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", sortedPeopleByAge)
asssert.Equal(expected, actual)
}

243
concurrency/channel.go Normal file
View File

@@ -0,0 +1,243 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
package concurrency
import (
"context"
"sync"
)
// Channel is a logic object which can generate or manipulate go channel
// all methods of Channel are in the book tilted《Concurrency in Go》
type Channel struct {
}
// NewChannel return a Channel instance
func NewChannel() *Channel {
return &Channel{}
}
// Generate a data of type any chan, put param `values` into the chan
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
go func() {
defer close(dataStream)
for _, v := range values {
select {
case <-ctx.Done():
return
case dataStream <- v:
}
}
}()
return dataStream
}
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
go func() {
defer close(dataStream)
for {
for _, v := range values {
select {
case <-ctx.Done():
return
case dataStream <- v:
}
}
}
}()
return dataStream
}
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
// until close the `done` channel
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
dataStream := make(chan any)
go func() {
defer close(dataStream)
for {
select {
case <-ctx.Done():
return
case dataStream <- fn():
}
}
}()
return dataStream
}
// Take return a chan whose values are tahken from another chan
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
takeStream := make(chan any)
go func() {
defer close(takeStream)
for i := 0; i < number; i++ {
select {
case <-ctx.Done():
return
case takeStream <- <-valueStream:
}
}
}()
return takeStream
}
// FanIn merge multiple channels into one channel
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
out := make(chan any)
go func() {
var wg sync.WaitGroup
wg.Add(len(channels))
for _, c := range channels {
go func(c <-chan any) {
defer wg.Done()
for v := range c {
select {
case <-ctx.Done():
return
case out <- v:
}
}
}(c)
}
wg.Wait()
close(out)
}()
return out
}
// Tee split one chanel into two channels
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
out1 := make(chan any)
out2 := make(chan any)
go func() {
defer close(out1)
defer close(out2)
for val := range c.OrDone(ctx, in) {
var out1, out2 = out1, out2
for i := 0; i < 2; i++ {
select {
case <-ctx.Done():
case out1 <- val:
out1 = nil
case out2 <- val:
out2 = nil
}
}
}
}()
return out1, out2
}
// Bridge link multiply channels into one channel
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
valStream := make(chan any)
go func() {
defer close(valStream)
for {
var stream <-chan any
select {
case maybeStream, ok := <-chanStream:
if ok == false {
return
}
stream = maybeStream
case <-ctx.Done():
return
}
for val := range c.OrDone(ctx, stream) {
select {
case valStream <- val:
case <-ctx.Done():
}
}
}
}()
return valStream
}
// Or read one or more channels into one channel, will close when any readin channel is closed
func (c *Channel) Or(channels ...<-chan any) <-chan any {
switch len(channels) {
case 0:
return nil
case 1:
return channels[0]
}
orDone := make(chan any)
go func() {
defer close(orDone)
switch len(channels) {
case 2:
select {
case <-channels[0]:
case <-channels[1]:
}
default:
m := len(channels) / 2
select {
case <-c.Or(channels[:m]...):
case <-c.Or(channels[m:]...):
}
// select {
// case <-channels[0]:
// case <-channels[1]:
// case <-channels[2]:
// case <-c.Or(append(channels[3:], orDone)...):
// }
}
}()
return orDone
}
// OrDone read a channel into another channel, will close until cancel context.
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
valStream := make(chan any)
go func() {
defer close(valStream)
for {
select {
case <-ctx.Done():
return
case v, ok := <-channel:
if !ok {
return
}
select {
case valStream <- v:
case <-ctx.Done():
}
}
}
}()
return valStream
}

206
concurrency/channel_test.go Normal file
View File

@@ -0,0 +1,206 @@
package concurrency
import (
"context"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestGenerate(t *testing.T) {
assert := internal.NewAssert(t, "TestGenerate")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
intStream := c.Generate(ctx, 1, 2, 3)
// for v := range intStream {
// t.Log(v) //1, 2, 3
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
}
func TestRepeat(t *testing.T) {
assert := internal.NewAssert(t, "TestRepeat")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
// for v := range intStream {
// t.Log(v) //1, 2, 1, 2, 1
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
}
func TestRepeatFn(t *testing.T) {
assert := internal.NewAssert(t, "TestRepeatFn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
}
c := NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
// for v := range dataStream {
// t.Log(v) //a, a, a
// }
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
}
func TestTake(t *testing.T) {
assert := internal.NewAssert(t, "TestTake")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := NewChannel()
intStream := c.Take(ctx, numbers, 3)
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
}
func TestFanIn(t *testing.T) {
assert := internal.NewAssert(t, "TestFanIn")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
channels := make([]<-chan any, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
t.Logf("\t%d\n", val)
}
assert.Equal(1, 1)
}
func TestOr(t *testing.T) {
assert := internal.NewAssert(t, "TestOr")
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := NewChannel()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
t.Logf("done after %v", time.Since(start))
assert.Equal(1, 1)
}
func TestOrDone(t *testing.T) {
assert := internal.NewAssert(t, "TestOrDone")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
var res any
for val := range c.OrDone(ctx, intStream) {
t.Logf("%v", val)
res = val
}
assert.Equal(1, res)
}
func TestTee(t *testing.T) {
assert := internal.NewAssert(t, "TestTee")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
val1 := val
val2 := <-out2
// t.Log("val1 is", val1)
// t.Log("val2 is", val2)
assert.Equal(1, val1)
assert.Equal(1, val2)
}
}
func TestBridge(t *testing.T) {
assert := internal.NewAssert(t, "TestBridge")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
// t.Logf("%v ", val) //0 1 2 3 4 5 6 7 8 9
assert.Equal(index, val)
index++
}
}

View File

@@ -6,9 +6,10 @@ package convertor
import (
"bytes"
"encoding/gob"
"encoding/binary"
"encoding/json"
"fmt"
"math"
"reflect"
"regexp"
"strconv"
@@ -21,14 +22,44 @@ func ToBool(s string) (bool, error) {
}
// ToBytes convert interface to bytes
func ToBytes(data interface{}) ([]byte, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(data)
if err != nil {
return nil, err
func ToBytes(value any) ([]byte, error) {
v := reflect.ValueOf(value)
switch value.(type) {
case int, int8, int16, int32, int64:
number := v.Int()
buf := bytes.NewBuffer([]byte{})
buf.Reset()
err := binary.Write(buf, binary.BigEndian, number)
return buf.Bytes(), err
case uint, uint8, uint16, uint32, uint64:
number := v.Uint()
buf := bytes.NewBuffer([]byte{})
buf.Reset()
err := binary.Write(buf, binary.BigEndian, number)
return buf.Bytes(), err
case float32:
number := float32(v.Float())
bits := math.Float32bits(number)
bytes := make([]byte, 4)
binary.BigEndian.PutUint32(bytes, bits)
return bytes, nil
case float64:
number := v.Float()
bits := math.Float64bits(number)
bytes := make([]byte, 8)
binary.BigEndian.PutUint64(bytes, bits)
return bytes, nil
case bool:
return strconv.AppendBool([]byte{}, v.Bool()), nil
case string:
return []byte(v.String()), nil
case []byte:
return v.Bytes(), nil
default:
newValue, err := json.Marshal(value)
return newValue, err
}
return buf.Bytes(), nil
}
// ToChar convert string to char slice
@@ -44,59 +75,49 @@ func ToChar(s string) []string {
}
// ToString convert value to string
func ToString(value interface{}) string {
var res string
func ToString(value any) string {
res := ""
if value == nil {
return res
}
switch v := value.(type) {
case float64:
res = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
res = strconv.FormatFloat(float64(v), 'f', -1, 64)
case int:
res = strconv.Itoa(v)
case uint:
res = strconv.Itoa(int(v))
case int8:
res = strconv.Itoa(int(v))
case uint8:
res = strconv.Itoa(int(v))
case int16:
res = strconv.Itoa(int(v))
case uint16:
res = strconv.Itoa(int(v))
case int32:
res = strconv.Itoa(int(v))
case uint32:
res = strconv.Itoa(int(v))
case int64:
res = strconv.FormatInt(v, 10)
case uint64:
res = strconv.FormatUint(v, 10)
v := reflect.ValueOf(value)
switch value.(type) {
case float32, float64:
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
return res
case int, int8, int16, int32, int64:
res = strconv.FormatInt(v.Int(), 10)
return res
case uint, uint8, uint16, uint32, uint64:
res = strconv.FormatUint(v.Uint(), 10)
return res
case string:
res = value.(string)
res = v.String()
return res
case []byte:
res = string(value.([]byte))
res = string(v.Bytes())
return res
default:
newValue, _ := json.Marshal(value)
res = string(newValue)
return res
}
return res
}
// ToJson convert value to a valid json string
func ToJson(value interface{}) (string, error) {
func ToJson(value any) (string, error) {
res, err := json.Marshal(value)
if err != nil {
res = []byte("")
return "", err
}
return string(res), err
return string(res), nil
}
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
func ToFloat(value interface{}) (float64, error) {
func ToFloat(value any) (float64, error) {
v := reflect.ValueOf(value)
res := 0.0
@@ -123,7 +144,7 @@ func ToFloat(value interface{}) (float64, error) {
}
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
func ToInt(value interface{}) (int64, error) {
func ToInt(value any) (int64, error) {
v := reflect.ValueOf(value)
var res int64
@@ -151,7 +172,7 @@ func ToInt(value interface{}) (int64, error) {
// StructToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value
func StructToMap(value interface{}) (map[string]interface{}, error) {
func StructToMap(value any) (map[string]any, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
@@ -162,7 +183,7 @@ func StructToMap(value interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
res := make(map[string]interface{})
res := make(map[string]any)
fieldNum := t.NumField()
pattern := `^[A-Z]`

View File

@@ -2,13 +2,14 @@ package convertor
import (
"fmt"
"reflect"
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestToChar(t *testing.T) {
assert := internal.NewAssert(t, "TestToChar")
cases := []string{"", "abc", "1 2#3"}
expected := [][]string{
{""},
@@ -16,50 +17,52 @@ func TestToChar(t *testing.T) {
{"1", " ", "2", "#", "3"},
}
for i := 0; i < len(cases); i++ {
res := ToChar(cases[i])
if !reflect.DeepEqual(res, expected[i]) {
utils.LogFailedTestInfo(t, "ToChar", cases[i], expected[i], res)
t.FailNow()
}
assert.Equal(expected[i], ToChar(cases[i]))
}
}
func TestToBool(t *testing.T) {
cases := []string{"true", "True", "false", "False", "0", "1", "123"}
expected := []bool{true, true, false, false, false, true, false}
assert := internal.NewAssert(t, "TestToBool")
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
expected := []bool{true, true, true, false, false, false, false, false, false}
for i := 0; i < len(cases); i++ {
res, _ := ToBool(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "ToBool", cases[i], expected[i], res)
t.FailNow()
}
actual, _ := ToBool(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestToBytes(t *testing.T) {
cases := []interface{}{
assert := internal.NewAssert(t, "TestToBytes")
cases := []any{
0,
false,
"1",
}
expected := [][]byte{
{3, 4, 0, 0},
{3, 2, 0, 0},
{4, 12, 0, 1, 49},
{0, 0, 0, 0, 0, 0, 0, 0},
{102, 97, 108, 115, 101},
{49},
}
for i := 0; i < len(cases); i++ {
res, _ := ToBytes(cases[i])
fmt.Println(res)
if !reflect.DeepEqual(res, expected[i]) {
utils.LogFailedTestInfo(t, "ToBytes", cases[i], expected[i], res)
t.FailNow()
}
actual, _ := ToBytes(cases[i])
assert.Equal(expected[i], actual)
}
bytesData, err := ToBytes("abc")
if err != nil {
t.Error(err)
t.Fail()
}
assert.Equal("abc", ToString(bytesData))
}
func TestToInt(t *testing.T) {
cases := []interface{}{"123", "-123", 123,
assert := internal.NewAssert(t, "TestToInt")
cases := []any{"123", "-123", 123,
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float32(12.3), float64(12.3),
"abc", false, "111111111111111111111111111111111111111"}
@@ -67,16 +70,15 @@ func TestToInt(t *testing.T) {
expected := []int64{123, -123, 123, 123, 123, 123, 123, 123, 12, 12, 0, 0, 0}
for i := 0; i < len(cases); i++ {
res, _ := ToInt(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "ToInt", cases[i], expected[i], res)
t.FailNow()
}
actual, _ := ToInt(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestToFloat(t *testing.T) {
cases := []interface{}{
assert := internal.NewAssert(t, "TestToFloat")
cases := []any{
"", "-1", "-.11", "1.23e3", ".123e10", "abc",
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
@@ -86,108 +88,74 @@ func TestToFloat(t *testing.T) {
0, 1, -1, 123, 123, 123, 123, 123, 123, 123, 12.3, 12.300000190734863}
for i := 0; i < len(cases); i++ {
res, _ := ToFloat(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "ToFloat", cases[i], expected[i], res)
t.FailNow()
}
actual, _ := ToFloat(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestToString(t *testing.T) {
// map
assert := internal.NewAssert(t, "TestToString")
aMap := make(map[string]int)
aMap["a"] = 1
aMap["b"] = 2
aMap["c"] = 3
// struct
type TestStruct struct {
Name string
}
aStruct := TestStruct{Name: "TestStruct"}
cases := []interface{}{
cases := []any{
"", nil,
int(0), int8(1), int16(-1), int32(123), int64(123),
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float64(12.3), float32(12.3),
true, false,
[]int{1, 2, 3}, aMap, aStruct, []byte{104, 101, 108, 108, 111}}
expected := []string{"0", "1", "-1", "123", "123", "123", "123", "123",
"123", "123", "12.3", "12.300000190734863", "true", "false",
expected := []string{
"", "",
"0", "1", "-1",
"123", "123", "123", "123", "123", "123", "123",
"12.3", "12.300000190734863",
"true", "false",
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
for i := 0; i < len(cases); i++ {
res := ToString(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "ToString", cases[i], expected[i], res)
t.FailNow()
}
actual := ToString(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestToJson(t *testing.T) {
// map
aMap := make(map[string]int)
aMap["a"] = 1
aMap["b"] = 2
aMap["c"] = 3
assert := internal.NewAssert(t, "TestToJson")
mapJson := "{\"a\":1,\"b\":2,\"c\":3}"
r1, _ := ToJson(aMap)
if r1 != mapJson {
utils.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1)
t.FailNow()
}
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
mapJsonStr, _ := ToJson(aMap)
assert.Equal("{\"a\":1,\"b\":2,\"c\":3}", mapJsonStr)
// struct
type TestStruct struct {
Name string
}
aStruct := TestStruct{Name: "TestStruct"}
structJson := "{\"Name\":\"TestStruct\"}"
r2, _ := ToJson(aStruct)
if r2 != structJson {
utils.LogFailedTestInfo(t, "ToJson", aMap, mapJson, r1)
t.FailNow()
}
structJsonStr, _ := ToJson(aStruct)
assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
}
func TestStructToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToMap")
type People struct {
Name string `json:"name"`
age int
}
p1 := People{
p := People{
"test",
100,
}
pm1, _ := StructToMap(p1)
m1 := make(map[string]interface{})
m1["name"] = "test"
//exp1["100"] = 100
if !reflect.DeepEqual(pm1, m1) {
utils.LogFailedTestInfo(t, "StructToMap", p1, m1, pm1)
t.FailNow()
}
p2 := People{
"test",
100,
}
pm2, _ := StructToMap(p1)
m2 := make(map[string]interface{})
m2["name"] = "test"
m2["100"] = 100
if reflect.DeepEqual(pm2, m2) {
utils.LogFailedTestInfo(t, "StructToMap", p2, m2, pm2)
t.FailNow()
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
}
func TestColorHexToRGB(t *testing.T) {
@@ -196,22 +164,17 @@ func TestColorHexToRGB(t *testing.T) {
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
expected := "0,51,102"
if colorRGB != expected {
utils.LogFailedTestInfo(t, "ColorHexToRGB", colorHex, expected, colorRGB)
t.FailNow()
}
assert := internal.NewAssert(t, "TestColorHexToRGB")
assert.Equal(expected, colorRGB)
}
func TestColorRGBToHex(t *testing.T) {
r := 0
g := 51
b := 102
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
colorHex := ColorRGBToHex(r, g, b)
expected := "#003366"
if colorHex != expected {
utils.LogFailedTestInfo(t, "ColorHexToRGB", colorRGB, expected, colorHex)
t.FailNow()
}
assert := internal.NewAssert(t, "TestColorRGBToHex")
assert.Equal(expected, colorHex)
}

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestAesEcbEncrypt(t *testing.T) {
@@ -13,10 +13,8 @@ func TestAesEcbEncrypt(t *testing.T) {
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
if string(aesEcbDecrypt) != data {
utils.LogFailedTestInfo(t, "AesEcbEncrypt/AesEcbDecrypt", data, data, string(aesEcbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
assert.Equal(data, string(aesEcbDecrypt))
}
func TestAesCbcEncrypt(t *testing.T) {
@@ -26,10 +24,8 @@ func TestAesCbcEncrypt(t *testing.T) {
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
if string(aesCbcDecrypt) != data {
utils.LogFailedTestInfo(t, "AesCbcEncrypt/AesCbcDecrypt", data, data, string(aesCbcDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
assert.Equal(data, string(aesCbcDecrypt))
}
func TestAesCtrCrypt(t *testing.T) {
@@ -39,10 +35,8 @@ func TestAesCtrCrypt(t *testing.T) {
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
if string(aesCtrDeCrypt) != data {
utils.LogFailedTestInfo(t, "AesCtrCrypt", data, data, string(aesCtrDeCrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestAesCtrCrypt")
assert.Equal(data, string(aesCtrDeCrypt))
}
func TestAesCfbEncrypt(t *testing.T) {
@@ -52,10 +46,8 @@ func TestAesCfbEncrypt(t *testing.T) {
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
if string(aesCfbDecrypt) != data {
utils.LogFailedTestInfo(t, "AesCfbEncrypt/AesCfbDecrypt", data, data, string(aesCfbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
assert.Equal(data, string(aesCfbDecrypt))
}
func TestAesOfbEncrypt(t *testing.T) {
@@ -65,8 +57,6 @@ func TestAesOfbEncrypt(t *testing.T) {
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
if string(aesOfbDecrypt) != data {
utils.LogFailedTestInfo(t, "AesOfbEncrypt/AesOfbDecrypt", data, data, string(aesOfbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
assert.Equal(data, string(aesOfbDecrypt))
}

View File

@@ -6,6 +6,7 @@
package cryptor
import (
"bufio"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
@@ -13,7 +14,9 @@ import (
"crypto/sha512"
"encoding/base64"
"encoding/hex"
"io/ioutil"
"fmt"
"io"
"os"
)
// Base64StdEncode encode string with base64 encoding
@@ -36,14 +39,34 @@ func Md5String(s string) string {
// Md5File return the md5 value of file
func Md5File(filename string) (string, error) {
f, err := ioutil.ReadFile(filename)
if fileInfo, err := os.Stat(filename); err != nil {
return "", err
} else if fileInfo.IsDir() {
return "", nil
}
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()
h := md5.New()
h.Write(f)
return hex.EncodeToString(h.Sum(nil)), nil
hash := md5.New()
chunkSize := 65536
for buf, reader := make([]byte, chunkSize), bufio.NewReader(file); ; {
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return "", err
}
hash.Write(buf[:n])
}
checksum := fmt.Sprintf("%x", hash.Sum(nil))
return checksum, nil
}
// HmacMd5 return the hmac hash of string use md5

View File

@@ -1,66 +1,36 @@
package cryptor
import (
"fmt"
"os"
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestBase64StdEncode(t *testing.T) {
s := "hello world"
bs := Base64StdEncode(s)
if bs != "aGVsbG8gd29ybGQ=" {
utils.LogFailedTestInfo(t, "Base64StdEncode", s, "aGVsbG8gd29ybGQ=", bs)
t.FailNow()
}
assert := internal.NewAssert(t, "TestBase64StdEncode")
assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world"))
}
func TestBase64StdDecode(t *testing.T) {
bs := "aGVsbG8gd29ybGQ="
s := Base64StdDecode(bs)
if s != "hello world" {
utils.LogFailedTestInfo(t, "Base64StdDecode", bs, "hello world=", s)
t.FailNow()
}
assert := internal.NewAssert(t, "TestBase64StdDecode")
assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ="))
}
func TestMd5String(t *testing.T) {
s := "hello"
smd5 := Md5String(s)
expected := "5d41402abc4b2a76b9719d911017c592"
if smd5 != expected {
utils.LogFailedTestInfo(t, "Md5String", s, expected, smd5)
t.FailNow()
}
assert := internal.NewAssert(t, "TestMd5String")
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
}
func TestMd5File(t *testing.T) {
file, _ := os.Create("./hello.txt")
defer file.Close()
file.WriteString("hello\n")
fileMd5, err := Md5File("./hello.txt")
if err != nil {
t.FailNow()
}
fmt.Println(fileMd5)
fileMd5, err := Md5File("./basic.go")
assert := internal.NewAssert(t, "TestMd5File")
assert.IsNotNil(fileMd5)
assert.IsNil(err)
}
func TestHmacMd5(t *testing.T) {
s := "hello world"
key := "12345"
hmacMd5 := HmacMd5(s, key)
expected := "5f4c9faaff0a1ad3007d9ddc06abe36d"
if hmacMd5 != expected {
utils.LogFailedTestInfo(t, "HmacMd5", s, expected, hmacMd5)
t.FailNow()
}
assert := internal.NewAssert(t, "TestHmacMd5")
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
}
func TestHmacSha1(t *testing.T) {
@@ -69,10 +39,8 @@ func TestHmacSha1(t *testing.T) {
hmacSha1 := HmacSha1(s, key)
expected := "3826f812255d8683f051ee97346d1359234d5dbd"
if hmacSha1 != expected {
utils.LogFailedTestInfo(t, "HmacSha1", s, expected, hmacSha1)
t.FailNow()
}
assert := internal.NewAssert(t, "TestHmacSha1")
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
@@ -81,10 +49,8 @@ func TestHmacSha256(t *testing.T) {
hmacSha256 := HmacSha256(s, key)
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
if hmacSha256 != expected {
utils.LogFailedTestInfo(t, "HmacSha256", s, expected, hmacSha256)
t.FailNow()
}
assert := internal.NewAssert(t, "TestHmacSha256")
assert.Equal(expected, hmacSha256)
}
func TestHmacSha512(t *testing.T) {
@@ -93,10 +59,8 @@ func TestHmacSha512(t *testing.T) {
hmacSha512 := HmacSha512(s, key)
expected := "5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175"
if hmacSha512 != expected {
utils.LogFailedTestInfo(t, "HmacSha512", s, expected, hmacSha512)
t.FailNow()
}
assert := internal.NewAssert(t, "TestHmacSha512")
assert.Equal(expected, hmacSha512)
}
func TestSha1(t *testing.T) {
@@ -104,10 +68,8 @@ func TestSha1(t *testing.T) {
sha1 := Sha1(s)
expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
if sha1 != expected {
utils.LogFailedTestInfo(t, "Sha1", s, expected, sha1)
t.FailNow()
}
assert := internal.NewAssert(t, "TestSha1")
assert.Equal(expected, sha1)
}
func TestSha256(t *testing.T) {
@@ -115,10 +77,8 @@ func TestSha256(t *testing.T) {
sha256 := Sha256(s)
expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
if sha256 != expected {
utils.LogFailedTestInfo(t, "Sha256", s, expected, sha256)
t.FailNow()
}
assert := internal.NewAssert(t, "TestSha256")
assert.Equal(expected, sha256)
}
func TestSha512(t *testing.T) {
@@ -126,8 +86,6 @@ func TestSha512(t *testing.T) {
sha512 := Sha512(s)
expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
if sha512 != expected {
utils.LogFailedTestInfo(t, "Sha512", s, expected, sha512)
t.FailNow()
}
assert := internal.NewAssert(t, "TestSha512")
assert.Equal(expected, sha512)
}

View File

@@ -19,10 +19,12 @@ func DesEcbEncrypt(data, key []byte) []byte {
length := (len(data) + des.BlockSize) / des.BlockSize
plain := make([]byte, length*des.BlockSize)
copy(plain, data)
pad := byte(len(plain) - len(data))
for i := len(data); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
@@ -36,7 +38,7 @@ func DesEcbEncrypt(data, key []byte) []byte {
func DesEcbDecrypt(encrypted, key []byte) []byte {
cipher, _ := des.NewCipher(generateDesKey(key))
decrypted := make([]byte, len(encrypted))
//
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
@@ -59,6 +61,7 @@ func DesCbcEncrypt(data, key []byte) []byte {
encrypted := make([]byte, len(data))
blockMode.CryptBlocks(encrypted, data)
return encrypted
}
@@ -72,6 +75,7 @@ func DesCbcDecrypt(encrypted, key []byte) []byte {
decrypted := make([]byte, len(encrypted))
blockMode.CryptBlocks(decrypted, encrypted)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}
@@ -105,6 +109,7 @@ func DesCfbEncrypt(data, key []byte) []byte {
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
@@ -120,6 +125,7 @@ func DesCfbDecrypt(encrypted, key []byte) []byte {
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(encrypted, encrypted)
return encrypted
}
@@ -139,6 +145,7 @@ func DesOfbEncrypt(data, key []byte) []byte {
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(encrypted[des.BlockSize:], data)
return encrypted
}
@@ -161,6 +168,6 @@ func DesOfbDecrypt(data, key []byte) []byte {
mode.XORKeyStream(decrypted, data)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
return decrypted
}

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestDesEcbEncrypt(t *testing.T) {
@@ -13,10 +13,8 @@ func TestDesEcbEncrypt(t *testing.T) {
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
if string(desEcbDecrypt) != data {
utils.LogFailedTestInfo(t, "DesEcbEncrypt/DesEcbDecrypt", data, data, string(desEcbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
assert.Equal(data, string(desEcbDecrypt))
}
func TestDesCbcEncrypt(t *testing.T) {
@@ -26,10 +24,8 @@ func TestDesCbcEncrypt(t *testing.T) {
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
if string(desCbcDecrypt) != data {
utils.LogFailedTestInfo(t, "DesCbcEncrypt/DesCbcDecrypt", data, data, string(desCbcDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
assert.Equal(data, string(desCbcDecrypt))
}
func TestDesCtrCrypt(t *testing.T) {
@@ -39,10 +35,8 @@ func TestDesCtrCrypt(t *testing.T) {
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
if string(desCtrDeCrypt) != data {
utils.LogFailedTestInfo(t, "DesCtrCrypt", data, data, string(desCtrDeCrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestDesCtrCrypt")
assert.Equal(data, string(desCtrDeCrypt))
}
func TestDesCfbEncrypt(t *testing.T) {
@@ -52,10 +46,8 @@ func TestDesCfbEncrypt(t *testing.T) {
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
if string(desCfbDecrypt) != data {
utils.LogFailedTestInfo(t, "DesCfbEncrypt/DesCfbDecrypt", data, data, string(desCfbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
assert.Equal(data, string(desCfbDecrypt))
}
func TestDesOfbEncrypt(t *testing.T) {
@@ -65,8 +57,6 @@ func TestDesOfbEncrypt(t *testing.T) {
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
if string(desOfbDecrypt) != data {
utils.LogFailedTestInfo(t, "DesOfbEncrypt/DesOfbDecrypt", data, data, string(desOfbDecrypt))
t.FailNow()
}
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
assert.Equal(data, string(desOfbDecrypt))
}

View File

@@ -14,11 +14,11 @@ import (
// GenerateRsaKey make a rsa private key, and return key file name
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) {
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
// private key
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
panic(err)
return err
}
derText := x509.MarshalPKCS1PrivateKey(privateKey)
@@ -41,7 +41,7 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) {
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
panic(err)
return err
}
block = pem.Block{
@@ -52,10 +52,12 @@ func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) {
//file,err = os.Create("rsa_public.pem")
file, err = os.Create(pubKeyFile)
if err != nil {
panic(err)
return err
}
pem.Encode(file, &block)
file.Close()
return nil
}
// RsaEncrypt encrypt data with ras algorithm

View File

@@ -3,17 +3,18 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestRsaEncrypt(t *testing.T) {
GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()
}
data := []byte("hello world")
encrypted := RsaEncrypt(data, "rsa_public.pem")
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
if string(data) != string(decrypted) {
utils.LogFailedTestInfo(t, "RsaEncrypt/RsaDecrypt", string(data), string(data), string(decrypted))
t.FailNow()
}
assert := internal.NewAssert(t, "TestRsaEncrypt")
assert.Equal(string(data), string(decrypted))
}

View File

@@ -0,0 +1,241 @@
package datastructure
import (
"errors"
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
type DoublyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
}
// NewDoublyLink return *DoublyLink instance
func NewDoublyLink[T any]() *DoublyLink[T] {
return &DoublyLink[T]{Head: nil}
}
// InsertAtHead insert value into doubly linklist at head index
func (link *DoublyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
size := link.Size()
if size == 0 {
link.Head = newNode
link.length++
return
}
newNode.Next = link.Head
newNode.Pre = nil
link.Head.Pre = newNode
link.Head = newNode
link.length++
}
// InsertAtTail insert value into doubly linklist at tail index
func (link *DoublyLink[T]) InsertAtTail(value T) {
current := link.Head
if current == nil {
link.InsertAtHead(value)
return
}
for current.Next != nil {
current = current.Next
}
newNode := datastructure.NewLinkNode(value)
newNode.Next = nil
newNode.Pre = current
current.Next = newNode
link.length++
}
// InsertAt insert value into doubly linklist at index
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
size := link.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of doubly link.")
}
if index == 0 {
link.InsertAtHead(value)
return nil
}
if index == size {
link.InsertAtTail(value)
return nil
}
i := 0
current := link.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
newNode.Pre = current
current.Next = newNode
link.length++
return nil
}
i++
current = current.Next
}
return errors.New("doubly link list no exist")
}
// DeleteAtHead delete value in doubly linklist at head index
func (link *DoublyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
}
current := link.Head
link.Head = current.Next
link.Head.Pre = nil
link.length--
return nil
}
// DeleteAtTail delete value in doubly linklist at tail index
func (link *DoublyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
}
current := link.Head
if current.Next == nil {
return link.DeleteAtHead()
}
for current.Next.Next != nil {
current = current.Next
}
current.Next = nil
link.length--
return nil
}
// DeleteAt delete value in doubly linklist at index
func (link *DoublyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("doubly link list no exist")
}
current := link.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
}
i++
current = current.Next
}
return errors.New("delete error")
}
// Reverse the linked list
func (link *DoublyLink[T]) Reverse() {
current := link.Head
var temp *datastructure.LinkNode[T]
for current != nil {
temp = current.Pre
current.Pre = current.Next
current.Next = temp
current = current.Pre
}
if temp != nil {
link.Head = temp.Pre
}
}
// GetMiddleNode return node at middle index of linked list
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
}
fast := link.Head
slow := link.Head
for fast != nil {
fast = fast.Next
if fast != nil {
fast = fast.Next
slow = slow.Next
} else {
return slow
}
}
return slow
}
// Size return the count of doubly linked list
func (link *DoublyLink[T]) Size() int {
return link.length
}
// Values return slice of all doubly linklist node value
func (link *DoublyLink[T]) Values() []T {
res := []T{}
current := link.Head
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// Print all nodes info of a linked list
func (link *DoublyLink[T]) Print() {
current := link.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}
// IsEmpty checks if link is empty or not
func (link *DoublyLink[T]) IsEmpty() bool {
return link.length == 0
}
// Clear checks if link is empty or not
func (link *DoublyLink[T]) Clear() {
link.Head = nil
link.length = 0
}

View File

@@ -0,0 +1,179 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestDoublyLink_InsertAtFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtFirst")
link := NewDoublyLink[int]()
link.InsertAtHead(1)
link.InsertAtHead(2)
link.InsertAtHead(3)
link.Print()
expected := []int{3, 2, 1}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_InsertAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtTail")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_InsertAt(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_InsertAt")
link := NewDoublyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtHead(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
link := NewDoublyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
link := NewDoublyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
link := NewDoublyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
assert.Equal([]int{2, 3, 4}, link.Values())
link.DeleteAt(1)
assert.Equal(2, link.Size())
assert.Equal([]int{2, 4}, link.Values())
}
func TestDoublyLink_Reverse(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_Reverse")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
func TestDoublyLink_GetMiddleNode(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_GetMiddleNode")
link := NewDoublyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
middle1 := link.GetMiddleNode()
assert.Equal(3, middle1.Value)
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}
func TestDoublyLink_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_Clear")
link := NewDoublyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
link.InsertAtTail(1)
assert.Equal(false, link.IsEmpty())
assert.Equal(1, link.Size())
link.Clear()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
}

View File

@@ -0,0 +1,246 @@
package datastructure
import (
"errors"
"fmt"
"reflect"
"github.com/duke-git/lancet/v2/datastructure"
)
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
type SinglyLink[T any] struct {
Head *datastructure.LinkNode[T]
length int
}
// NewSinglyLink return *SinglyLink instance
func NewSinglyLink[T any]() *SinglyLink[T] {
return &SinglyLink[T]{Head: nil}
}
// InsertAtHead insert value into singly linklist at head index
func (link *SinglyLink[T]) InsertAtHead(value T) {
newNode := datastructure.NewLinkNode(value)
newNode.Next = link.Head
link.Head = newNode
link.length++
}
// InsertAtTail insert value into singly linklist at tail index
func (link *SinglyLink[T]) InsertAtTail(value T) {
current := link.Head
if current == nil {
link.InsertAtHead(value)
return
}
for current.Next != nil {
current = current.Next
}
newNode := datastructure.NewLinkNode(value)
newNode.Next = nil
current.Next = newNode
link.length++
}
// InsertAt insert value into singly linklist at index
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
size := link.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of singly link.")
}
if index == 0 {
link.InsertAtHead(value)
return nil
}
if index == size {
link.InsertAtTail(value)
return nil
}
i := 0
current := link.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
current.Next = newNode
link.length++
return nil
}
i++
current = current.Next
}
return errors.New("singly link list no exist")
}
// DeleteAtHead delete value in singly linklist at head index
func (link *SinglyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("singly link list no exist")
}
current := link.Head
link.Head = current.Next
link.length--
return nil
}
// DeleteAtTail delete value in singly linklist at tail index
func (link *SinglyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("singly link list no exist")
}
current := link.Head
if current.Next == nil {
return link.DeleteAtHead()
}
for current.Next.Next != nil {
current = current.Next
}
current.Next = nil
link.length--
return nil
}
// DeleteAt delete value in singly linklist at index
func (link *SinglyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("singly link list no exist")
}
current := link.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
}
i++
current = current.Next
}
return errors.New("delete error")
}
// DeleteValue delete value in singly linklist
func (link *SinglyLink[T]) DeleteValue(value T) {
if link.Head == nil {
return
}
dummyHead := datastructure.NewLinkNode(value)
dummyHead.Next = link.Head
current := dummyHead
for current.Next != nil {
if reflect.DeepEqual(current.Next.Value, value) {
current.Next = current.Next.Next
link.length--
} else {
current = current.Next
}
}
link.Head = dummyHead.Next
}
// Reverse the linked list
func (link *SinglyLink[T]) Reverse() {
var pre, next *datastructure.LinkNode[T]
current := link.Head
for current != nil {
next = current.Next
current.Next = pre
pre = current
current = next
}
link.Head = pre
}
// GetMiddleNode return node at middle index of linked list
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
}
fast := link.Head
slow := link.Head
for fast != nil {
fast = fast.Next
if fast != nil {
fast = fast.Next
slow = slow.Next
} else {
return slow
}
}
return slow
}
// Size return the count of singly linked list
func (link *SinglyLink[T]) Size() int {
return link.length
}
// Values return slice of all singly linklist node value
func (link *SinglyLink[T]) Values() []T {
res := []T{}
current := link.Head
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// IsEmpty checks if link is empty or not
func (link *SinglyLink[T]) IsEmpty() bool {
return link.length == 0
}
// Clear checks if link is empty or not
func (link *SinglyLink[T]) Clear() {
link.Head = nil
link.length = 0
}
// Print all nodes info of a linked list
func (link *SinglyLink[T]) Print() {
current := link.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}

View File

@@ -0,0 +1,208 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestSinglyLink_InsertAtFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtFirst")
link := NewSinglyLink[int]()
link.InsertAtHead(1)
link.InsertAtHead(2)
link.InsertAtHead(3)
link.Print()
expected := []int{3, 2, 1}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_InsertAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtTail")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_InsertAt(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_InsertAt")
link := NewSinglyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
err = link.InsertAt(0, 1)
if err != nil {
t.FailNow()
}
err = link.InsertAt(1, 2)
if err != nil {
t.FailNow()
}
err = link.InsertAt(2, 4)
if err != nil {
t.FailNow()
}
err = link.InsertAt(2, 3)
if err != nil {
t.FailNow()
}
link.Print()
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteAtHead(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
assert.Equal(expected, values)
}
func TestSinglyLink_DeleteValue(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteValue")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.DeleteValue(2)
assert.Equal([]int{1, 3, 4}, link.Values())
link.DeleteValue(1)
assert.Equal([]int{3, 4}, link.Values())
}
func TestSinglyLink_DeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
assert.Equal([]int{2, 3, 4}, link.Values())
link.DeleteAt(1)
assert.Equal(2, link.Size())
assert.Equal([]int{2, 4}, link.Values())
}
func TestSinglyLink_Reverse(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_Reverse")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
func TestSinglyLink_GetMiddleNode(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_GetMiddleNode")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
link.InsertAtTail(4)
middle1 := link.GetMiddleNode()
assert.Equal(3, middle1.Value)
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}
func TestSinglyLink_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_Clear")
link := NewSinglyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
link.InsertAtTail(1)
assert.Equal(false, link.IsEmpty())
assert.Equal(1, link.Size())
link.Clear()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())
}

245
datastructure/list/list.go Normal file
View File

@@ -0,0 +1,245 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
package datastructure
import (
"reflect"
)
// List is a linear table, implemented with slice
type List[T any] struct {
data []T
}
// NewList return a pointer of List
func NewList[T any](data []T) *List[T] {
return &List[T]{data: data}
}
// Data return list data
func (l *List[T]) Data() []T {
return l.data
}
// ValueOf return the value pointer at index of list data.
func (l *List[T]) ValueOf(index int) (*T, bool) {
if index < 0 || index >= len(l.data) {
return nil, false
}
return &l.data[index], true
}
// IndexOf reture the index of value. if not found return -1
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
for i, v := range data {
if reflect.DeepEqual(v, value) {
index = i
break
}
}
return index
}
// Contain checks if the value in the list or not
func (l *List[T]) Contain(value T) bool {
data := l.data
for _, v := range data {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Push append value to the list data
func (l *List[T]) Push(value T) {
l.data = append(l.data, value)
}
// InsertAtFirst insert value into list at first index
func (l *List[T]) InsertAtFirst(value T) {
l.InsertAt(0, value)
}
// InsertAtLast insert value into list at last index
func (l *List[T]) InsertAtLast(value T) {
l.InsertAt(len(l.data), value)
}
// InsertAt insert value into list at index
func (l *List[T]) InsertAt(index int, value T) {
data := l.data
size := len(data)
if index < 0 || index > size {
return
}
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
}
// PopFirst delete the first value of list and return it
func (l *List[T]) PopFirst() (*T, bool) {
if len(l.data) == 0 {
return nil, false
}
v := l.data[0]
l.DeleteAt(0)
return &v, true
}
// PopLast delete the last value of list and return it
func (l *List[T]) PopLast() (*T, bool) {
size := len(l.data)
if size == 0 {
return nil, false
}
v := l.data[size-1]
l.DeleteAt(size - 1)
return &v, true
}
// DeleteAt delete the value of list at index
func (l *List[T]) DeleteAt(index int) {
data := l.data
size := len(data)
if index < 0 || index > size-1 {
return
}
if index == size-1 {
data = append(data[:index])
} else {
data = append(data[:index], data[index+1:]...)
}
l.data = data
}
// UpdateAt update value of list at index, index shoud between 0 and list size -1
func (l *List[T]) UpdateAt(index int, value T) {
data := l.data
size := len(data)
if index < 0 || index >= size {
return
}
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
}
// Equtal compare list to other list, use reflect.DeepEqual
func (l *List[T]) Equtal(other *List[T]) bool {
if len(l.data) != len(other.data) {
return false
}
for i := 0; i < len(l.data); i++ {
if !reflect.DeepEqual(l.data[i], other.data[i]) {
return false
}
}
return true
}
// IsEmpty check if the list is empty or not
func (l *List[T]) IsEmpty() bool {
return len(l.data) == 0
}
// Clear the data of list
func (l *List[T]) Clear() {
l.data = make([]T, 0, 0)
}
// Clone return a copy of list
func (l *List[T]) Clone() *List[T] {
cl := NewList(make([]T, len(l.data)))
copy(cl.data, l.data)
return cl
}
// Merge two list, return new list, don't change original list
func (l *List[T]) Merge(other *List[T]) *List[T] {
l1, l2 := len(l.data), len(other.data)
ml := NewList(make([]T, l1+l2, l1+l2))
data := append([]T{}, append(l.data, other.data...)...)
ml.data = data
return ml
}
// Size return number of list data items
func (l *List[T]) Size() int {
return len(l.data)
}
// Swap the value of index i and j in list
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
if i < 0 || i >= size || j < 0 || j >= size {
return
}
l.data[i], l.data[j] = l.data[j], l.data[i]
}
// Reverse the item order of list
func (l *List[T]) Reverse() {
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
}
// Unique remove duplicate items in list
func (l *List[T]) Unique() {
data := l.data
size := len(data)
uniqueData := make([]T, 0, 0)
for i := 0; i < size; i++ {
value := data[i]
skip := true
for _, v := range uniqueData {
if reflect.DeepEqual(value, v) {
skip = false
break
}
}
if skip {
uniqueData = append(uniqueData, value)
}
}
l.data = uniqueData
}
// Union creates a new list contain all element in list l and other, remove duplicate element.
func (l *List[T]) Union(other *List[T]) *List[T] {
res := NewList([]T{})
res.data = append(res.data, l.data...)
res.data = append(res.data, other.data...)
res.Unique()
return res
}
// Intersection creates a new list whose element both be contained in list l and other
func (l *List[T]) Intersection(other *List[T]) *List[T] {
res := NewList(make([]T, 0, 0))
for _, v := range l.data {
if other.Contain(v) {
res.data = append(res.data, v)
}
}
return res
}

View File

@@ -0,0 +1,272 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestListData(t *testing.T) {
assert := internal.NewAssert(t, "TestListData")
list := NewList([]int{1, 2, 3})
assert.Equal([]int{1, 2, 3}, list.Data())
}
func TestValueOf(t *testing.T) {
assert := internal.NewAssert(t, "TestValueOf")
list := NewList([]int{1, 2, 3})
v, ok := list.ValueOf(0)
assert.Equal(1, *v)
assert.Equal(true, ok)
_, ok = list.ValueOf(3)
assert.Equal(false, ok)
}
func TestIndexOf(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOf(1)
assert.Equal(0, i)
i = list.IndexOf(4)
assert.Equal(-1, i)
}
func TestContain(t *testing.T) {
assert := internal.NewAssert(t, "TestContain")
list := NewList([]int{1, 2, 3})
assert.Equal(true, list.Contain(1))
assert.Equal(false, list.Contain(0))
}
func TestPush(t *testing.T) {
assert := internal.NewAssert(t, "TestPush")
list := NewList([]int{1, 2, 3})
list.Push(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
}
func TestInsertAtFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestInsertAtFirst")
list := NewList([]int{1, 2, 3})
list.InsertAtFirst(0)
assert.Equal([]int{0, 1, 2, 3}, list.Data())
}
func TestInsertAtLast(t *testing.T) {
assert := internal.NewAssert(t, "TestInsertAtLast")
list := NewList([]int{1, 2, 3})
list.InsertAtLast(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
}
func TestInsertAt(t *testing.T) {
assert := internal.NewAssert(t, "TestInsertAt")
list := NewList([]int{1, 2, 3})
list.InsertAt(-1, 0)
assert.Equal([]int{1, 2, 3}, list.Data())
list.InsertAt(4, 0)
assert.Equal([]int{1, 2, 3}, list.Data())
list.InsertAt(0, 0)
assert.Equal([]int{0, 1, 2, 3}, list.Data())
list.InsertAt(4, 4)
assert.Equal([]int{0, 1, 2, 3, 4}, list.Data())
}
func TestPopFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestPopFirst")
list := NewList([]int{1, 2, 3})
v, ok := list.PopFirst()
assert.Equal(1, *v)
assert.Equal(true, ok)
assert.Equal([]int{2, 3}, list.Data())
list2 := NewList([]int{})
_, ok = list2.PopFirst()
assert.Equal(false, ok)
assert.Equal([]int{}, list2.Data())
}
func TestPopLast(t *testing.T) {
assert := internal.NewAssert(t, "TestPopLast")
list := NewList([]int{1, 2, 3})
v, ok := list.PopLast()
assert.Equal(3, *v)
assert.Equal(true, ok)
assert.Equal([]int{1, 2}, list.Data())
list2 := NewList([]int{})
_, ok = list2.PopLast()
assert.Equal(false, ok)
assert.Equal([]int{}, list2.Data())
}
func TestDeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestDeleteAt")
list := NewList([]int{1, 2, 3, 4})
list.DeleteAt(-1)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.DeleteAt(4)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.DeleteAt(0)
assert.Equal([]int{2, 3, 4}, list.Data())
list.DeleteAt(2)
assert.Equal([]int{2, 3}, list.Data())
}
func TestUpdateAt(t *testing.T) {
assert := internal.NewAssert(t, "TestUpdateAt")
list := NewList([]int{1, 2, 3, 4})
list.UpdateAt(-1, 0)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.UpdateAt(4, 0)
assert.Equal([]int{1, 2, 3, 4}, list.Data())
list.UpdateAt(0, 5)
assert.Equal([]int{5, 2, 3, 4}, list.Data())
list.UpdateAt(3, 1)
assert.Equal([]int{5, 2, 3, 1}, list.Data())
}
func TestEqutal(t *testing.T) {
assert := internal.NewAssert(t, "TestEqutal")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{1, 2, 3, 4})
list3 := NewList([]int{1, 2, 3})
assert.Equal(true, list1.Equtal(list2))
assert.Equal(false, list1.Equtal(list3))
}
func TestIsEmpty(t *testing.T) {
assert := internal.NewAssert(t, "TestIsEmpty")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{})
assert.Equal(false, list1.IsEmpty())
assert.Equal(true, list2.IsEmpty())
}
func TestIsClear(t *testing.T) {
assert := internal.NewAssert(t, "TestIsClear")
list1 := NewList([]int{1, 2, 3, 4})
list1.Clear()
empty := NewList([]int{})
assert.Equal(empty, list1)
}
func TestClone(t *testing.T) {
assert := internal.NewAssert(t, "TestClone")
list1 := NewList([]int{1, 2, 3, 4})
list2 := list1.Clone()
assert.Equal(true, list1.Equtal(list2))
}
func TestMerge(t *testing.T) {
assert := internal.NewAssert(t, "TestMerge")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{1, 2, 3, 4, 4, 5, 6})
list3 := list1.Merge(list2)
assert.Equal(true, expected.Equtal(list3))
}
func TestSize(t *testing.T) {
assert := internal.NewAssert(t, "TestSize")
list := NewList([]int{1, 2, 3, 4})
empty := NewList([]int{})
assert.Equal(4, list.Size())
assert.Equal(0, empty.Size())
}
func TestSwap(t *testing.T) {
assert := internal.NewAssert(t, "TestSwap")
list := NewList([]int{1, 2, 3, 4})
expected := NewList([]int{4, 2, 3, 1})
list.Swap(0, 3)
assert.Equal(true, expected.Equtal(list))
}
func TestReverse(t *testing.T) {
assert := internal.NewAssert(t, "TestReverse")
list := NewList([]int{1, 2, 3, 4})
expected := NewList([]int{4, 3, 2, 1})
list.Reverse()
assert.Equal(true, expected.Equtal(list))
}
func TestUnique(t *testing.T) {
assert := internal.NewAssert(t, "TestUnique")
list := NewList([]int{1, 2, 2, 3, 4})
expected := NewList([]int{1, 2, 3, 4})
list.Unique()
assert.Equal(true, expected.Equtal(list))
}
func TestUnion(t *testing.T) {
assert := internal.NewAssert(t, "TestUnion")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{1, 2, 3, 4, 5, 6})
list3 := list1.Union(list2)
assert.Equal(true, expected.Equtal(list3))
}
func TestIntersection(t *testing.T) {
assert := internal.NewAssert(t, "TestIntersection")
list1 := NewList([]int{1, 2, 3, 4})
list2 := NewList([]int{4, 5, 6})
expected := NewList([]int{4})
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equtal(list3))
}

51
datastructure/node.go Normal file
View File

@@ -0,0 +1,51 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
package datastructure
// LinkNode is a linkedlist node, which have a Value and Pre points to previous node, Next points to a next node of the link.
type LinkNode[T any] struct {
Value T
Pre *LinkNode[T]
Next *LinkNode[T]
}
// NewLinkNode return a LinkNode pointer
func NewLinkNode[T any](value T) *LinkNode[T] {
return &LinkNode[T]{value, nil, nil}
}
// StackNode is a node in stack, which have a Value and Next pointer points to next node in the stack.
type StackNode[T any] struct {
Value T
Next *StackNode[T]
}
// NewStackNode return a StackNode pointer
func NewStackNode[T any](value T) *StackNode[T] {
return &StackNode[T]{value, nil}
}
// QueueNode is a node in a queue, which have a Value and Next pointer points to next node in the queue.
type QueueNode[T any] struct {
Value T
Next *QueueNode[T]
}
// NewQueueNode return a QueueNode pointer
func NewQueueNode[T any](value T) *QueueNode[T] {
return &QueueNode[T]{value, nil}
}
// TreeNode is node of tree
type TreeNode[T any] struct {
Value T
Left *TreeNode[T]
Right *TreeNode[T]
}
// NewTreeNode return a TreeNode pointer
func NewTreeNode[T any](val T) *TreeNode[T] {
return &TreeNode[T]{val, nil, nil}
}

View File

@@ -0,0 +1,114 @@
package datastructure
import (
"fmt"
"reflect"
)
// ArrayQueue implements queue with slice
type ArrayQueue[T any] struct {
items []T
head int
tail int
capacity int
size int
}
func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
return &ArrayQueue[T]{
items: make([]T, 0, capacity),
head: 0,
tail: 0,
capacity: capacity,
size: 0,
}
}
// Data return queue data
func (q *ArrayQueue[T]) Data() []T {
items := []T{}
for i := q.head; i < q.tail; i++ {
items = append(items, q.items[i])
}
return items
}
// Size return length of queue data
func (q *ArrayQueue[T]) Size() int {
return q.size
}
// IsEmpty checks if queue is empty or not
func (q *ArrayQueue[T]) IsEmpty() bool {
return q.size == 0
}
// Front return front value of queue
func (q *ArrayQueue[T]) Front() T {
return q.items[0]
}
// Back return back value of queue
func (q *ArrayQueue[T]) Back() T {
return q.items[q.size-1]
}
// EnQueue put element into queue
func (q *ArrayQueue[T]) Enqueue(item T) bool {
if q.head == 0 && q.tail == q.capacity {
return false
} else if q.head != 0 && q.tail == q.capacity {
for i := q.head; i < q.tail; i++ {
q.items[i-q.head] = q.items[i]
}
q.tail = q.tail - q.head
q.head = 0
}
q.items = append(q.items, item)
q.tail++
q.size++
return true
}
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
func (q *ArrayQueue[T]) Dequeue() (T, bool) {
var item T
if q.head == q.tail {
return item, false
}
item = q.items[q.head]
q.head++
q.size--
return item, true
}
// Clear the queue data
func (q *ArrayQueue[T]) Clear() {
capacity := q.capacity
q.items = make([]T, 0, capacity)
q.head = 0
q.tail = 0
q.size = 0
q.capacity = capacity
}
// Contain checks if the value is in queue or not
func (q *ArrayQueue[T]) Contain(value T) bool {
for _, v := range q.items {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Print queue data
func (q *ArrayQueue[T]) Print() {
info := "["
for i := q.head; i < q.tail; i++ {
info += fmt.Sprintf("%+v, ", q.items[i])
}
info += "]"
fmt.Println(info)
}

View File

@@ -0,0 +1,102 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestArrayQueue_Enqueue(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
queue := NewArrayQueue[int](5)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
expected := []int{1, 2, 3}
data := queue.Data()
size := queue.Size()
queue.Print()
assert.Equal(expected, data)
assert.Equal(3, size)
}
func TestArrayQueue_Dequeue(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Dequeue")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val, ok := queue.Dequeue()
assert.Equal(true, ok)
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{2, 3}, queue.Data())
}
func TestArrayQueue_Front(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Front")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val := queue.Front()
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Back(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Back")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
val := queue.Back()
queue.Print()
assert.Equal(3, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
func TestArrayQueue_Contain(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Contain")
queue := NewArrayQueue[int](4)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(4))
}
func TestArrayQueue_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayQueue_Clear")
queue := NewArrayQueue[int](4)
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
queue.Enqueue(1)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Size())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
}

View File

@@ -0,0 +1,118 @@
package datastructure
import (
"errors"
"fmt"
"reflect"
)
// CircularQueue implements circular queue with slice,
// last index of CircularQueue don't contain value, so acturl capacity is size - 1
type CircularQueue[T any] struct {
data []T
front int
rear int
size int
}
// NewCircularQueue return a empty CircularQueue pointer
func NewCircularQueue[T any](size int) *CircularQueue[T] {
data := make([]T, size)
return &CircularQueue[T]{data: data, front: 0, rear: 0, size: size}
}
// Data return queue data
func (q *CircularQueue[T]) Data() []T {
data := []T{}
front := q.front
rear := q.rear
if front <= rear {
return q.data[front:rear]
}
data = append(data, q.data[front:]...)
data = append(data, q.data[0:rear]...)
return data
}
// Length return current data length of queue
func (q *CircularQueue[T]) Length() int {
if q.size == 0 {
return 0
}
return (q.rear - q.front + q.size) % q.size
}
// IsEmpty checks if queue is empty or not
func (q *CircularQueue[T]) IsEmpty() bool {
return q.front == q.rear
}
// IsFull checks if queue is full or not
func (q *CircularQueue[T]) IsFull() bool {
return (q.rear+1)%q.size == q.front
}
// Front return front value of queue
func (q *CircularQueue[T]) Front() T {
return q.data[q.front]
}
// Back return back value of queue
func (q *CircularQueue[T]) Back() T {
if q.rear-1 >= 0 {
return q.data[q.rear-1]
}
return q.data[q.size-1]
}
// EnQueue put element into queue
func (q *CircularQueue[T]) EnQueue(value T) error {
if q.IsFull() {
return errors.New("queue is full!")
}
q.data[q.rear] = value
q.rear = (q.rear + 1) % q.size
return nil
}
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
func (q *CircularQueue[T]) DeQueue() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
headItem := q.data[q.front]
var t T
q.data[q.front] = t
q.front = (q.front + 1) % q.size
return &headItem, nil
}
// Clear the queue data
func (q *CircularQueue[T]) Clear() {
q.data = []T{}
q.front = 0
q.rear = 0
q.size = 0
}
// Contain checks if the value is in queue or not
func (q *CircularQueue[T]) Contain(value T) bool {
for _, v := range q.data {
if reflect.DeepEqual(v, value) {
return true
}
}
return false
}
// Print queue data
func (q *CircularQueue[T]) Print() {
fmt.Printf("%+v\n", q)
}

View File

@@ -0,0 +1,148 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestCircularQueue_EnQueue(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_EnQueue")
queue := NewCircularQueue[int](6)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.EnQueue(4)
queue.EnQueue(5)
queue.Print()
// assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
assert.Equal(5, queue.Length())
err := queue.EnQueue(6)
assert.IsNotNil(err)
}
func TestCircularQueue_DeQueue(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
queue := NewCircularQueue[int](6)
assert.Equal(true, queue.IsEmpty())
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.EnQueue(4)
queue.EnQueue(5)
val, err := queue.DeQueue()
assert.IsNil(err)
assert.Equal(1, *val)
assert.Equal(false, queue.IsFull())
val, _ = queue.DeQueue()
queue.Print()
assert.Equal(2, *val)
queue.EnQueue(6)
queue.Print()
assert.Equal(false, queue.IsFull())
}
func TestCircularQueue_Front(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Front")
queue := NewCircularQueue[int](6)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.EnQueue(4)
queue.EnQueue(5)
queue.Print()
queue.DeQueue()
queue.DeQueue()
queue.EnQueue(6)
queue.EnQueue(7)
queue.Print()
val := queue.Front()
assert.Equal(3, val)
assert.Equal(5, queue.Length())
}
func TestCircularQueue_Back(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Back")
queue := NewCircularQueue[int](6)
assert.Equal(true, queue.IsEmpty())
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.EnQueue(4)
queue.EnQueue(5)
queue.Print()
assert.Equal(5, queue.Back())
queue.DeQueue()
queue.DeQueue()
queue.EnQueue(6)
queue.EnQueue(7)
queue.Print()
assert.Equal(7, queue.Back())
}
func TestCircularQueue_Contain(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
queue := NewCircularQueue[int](2)
queue.EnQueue(1)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(2))
}
func TestCircularQueue_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Clear")
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Length())
queue.EnQueue(1)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Length())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Length())
}
func TestCircularQueue_Data(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Data")
queue := NewCircularQueue[int](6)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.EnQueue(4)
queue.EnQueue(5)
queue.Print()
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
queue.DeQueue()
queue.DeQueue()
queue.EnQueue(6)
queue.EnQueue(7)
queue.Print()
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
}

View File

@@ -0,0 +1,104 @@
package datastructure
import (
"errors"
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// LinkedQueue implements queue with link list
type LinkedQueue[T any] struct {
head *datastructure.QueueNode[T]
tail *datastructure.QueueNode[T]
length int
}
// NewLinkedQueue return a empty LinkedQueue pointer
func NewLinkedQueue[T any]() *LinkedQueue[T] {
return &LinkedQueue[T]{head: nil, tail: nil, length: 0}
}
// Data return queue data
func (q *LinkedQueue[T]) Data() []T {
res := []T{}
current := q.head
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// Size return length of queue data
func (q *LinkedQueue[T]) Size() int {
return q.length
}
// IsEmpty checks if queue is empty or not
func (q *LinkedQueue[T]) IsEmpty() bool {
return q.length == 0
}
// EnQueue add element into queue
func (q *LinkedQueue[T]) EnQueue(value T) {
newNode := datastructure.NewQueueNode(value)
if q.IsEmpty() {
q.head = newNode
q.tail = newNode
} else {
q.tail.Next = newNode
q.tail = newNode
}
q.length++
}
// DeQueue delete head element of queue then return it, if queue is empty, return nil and error
func (q *LinkedQueue[T]) DeQueue() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
head := q.head
q.head = q.head.Next
q.length--
return &head.Value, nil
}
// Front return front value of queue
func (q *LinkedQueue[T]) Front() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
return &q.head.Value, nil
}
// Back return back value of queue
func (q *LinkedQueue[T]) Back() (*T, error) {
if q.IsEmpty() {
return nil, errors.New("queue is empty")
}
return &q.tail.Value, nil
}
// Clear clear the queue data
func (q *LinkedQueue[T]) Clear() {
q.head = nil
q.tail = nil
q.length = 0
}
// Print all nodes info of queue link
func (q *LinkedQueue[T]) Print() {
current := q.head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}

View File

@@ -0,0 +1,84 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLinkedQueue_EnQueue(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedQueue_EnQueue")
queue := NewLinkedQueue[int]()
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
queue.Print()
assert.Equal([]int{1, 2, 3}, queue.Data())
assert.Equal(3, queue.Size())
}
func TestLinkedQueue_DeQueue(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
queue := NewLinkedQueue[int]()
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
val, _ := queue.DeQueue()
queue.Print()
assert.Equal([]int{2, 3}, queue.Data())
assert.Equal(1, *val)
}
func TestLinkedQueue_Front(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedQueue_Front")
queue := NewLinkedQueue[int]()
_, err := queue.Front()
assert.IsNotNil(err)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
val, err := queue.Front()
assert.Equal(1, *val)
assert.IsNil(err)
}
func TestLinkedQueue_Back(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
_, err := queue.Back()
assert.IsNotNil(err)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
val, err := queue.Back()
assert.Equal(3, *val)
assert.IsNil(err)
}
func TestLinkedQueue_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
assert.Equal(true, queue.IsEmpty())
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(3)
assert.Equal(false, queue.IsEmpty())
queue.Clear()
assert.Equal(true, queue.IsEmpty())
}

View File

@@ -0,0 +1,108 @@
package datastructure
import (
"errors"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// PriorityQueue is a priority queue implemented by binary heap tree
// type T should implements Compare function in lancetconstraints.Comparator interface.
type PriorityQueue[T any] struct {
items []T
size int
comparator lancetconstraints.Comparator
}
// NewPriorityQueue return a pointer of PriorityQueue
// param `comparator` is used to compare values in the queue
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T] {
return &PriorityQueue[T]{
items: make([]T, capacity+1),
size: 0,
comparator: comparator,
}
}
// IsEmpty checks if the queue is empty or not
func (q *PriorityQueue[T]) IsEmpty() bool {
return q.size == 0
}
// IsFull checks if the queue capacity is full or not
func (q *PriorityQueue[T]) IsFull() bool {
return q.size == len(q.items)-1
}
// Data return data slice in the queue
func (q *PriorityQueue[T]) Data() []T {
data := make([]T, q.size)
for i := 1; i < q.size+1; i++ {
data[i-1] = q.items[i]
}
return data
}
// Enqueue insert value into queue
func (q *PriorityQueue[T]) Enqueue(val T) error {
if q.IsFull() {
return errors.New("queue is already full.")
}
q.size++
q.items[q.size] = val
q.swim(q.size)
return nil
}
// Dequeue delete and return max value in queue
func (q *PriorityQueue[T]) Dequeue() (T, bool) {
var val T
if q.IsEmpty() {
return val, false
}
max := q.items[1]
q.swap(1, q.size)
q.size--
q.sink(1)
//set zero value for rest values of the queue
q.items[q.size+1] = val
return max, true
}
// swim when child's key is larger than parent's key, exchange them.
func (q *PriorityQueue[T]) swim(index int) {
for index > 1 && q.comparator.Compare(q.items[index/2], q.items[index]) < 0 {
q.swap(index, index/2)
index = index / 2
}
}
// sink when parent's key smaller than child's key, exchange parent's key with larger child's key.
func (q *PriorityQueue[T]) sink(index int) {
for 2*index <= q.size {
j := 2 * index
// get larger child node index
if j < q.size && q.comparator.Compare(q.items[j], q.items[j+1]) < 0 {
j++
}
// if parent larger than child, stop
if !(q.comparator.Compare(q.items[index], q.items[j]) < 0) {
break
}
q.swap(index, j)
index = j
}
}
// swap the two values at index i and j
func (q *PriorityQueue[T]) swap(i, j int) {
q.items[i], q.items[j] = q.items[j], q.items[i]
}

View File

@@ -0,0 +1,60 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestPriorityQueue_Enqueue(t *testing.T) {
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
assert.Equal(true, pq.IsEmpty())
assert.Equal(false, pq.IsFull())
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
assert.Equal(true, pq.IsFull())
queueData := pq.Data()
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
}
func TestPriorityQueue_Dequeue(t *testing.T) {
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
_, ok := pq.Dequeue()
assert.Equal(false, ok)
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
val, ok := pq.Dequeue()
assert.Equal(true, ok)
assert.Equal(10, val)
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
}

136
datastructure/set/set.go Normal file
View File

@@ -0,0 +1,136 @@
package datastructure
// Set is a data container, like slice, but element of set is not duplicate
type Set[T comparable] map[T]bool
// NewSet return a instance of set
func NewSet[T comparable](values ...T) Set[T] {
set := make(Set[T])
set.Add(values...)
return set
}
// Add value to set
func (s Set[T]) Add(values ...T) {
for _, v := range values {
s[v] = true
}
}
// Contain checks if set contains value or not
func (s Set[T]) Contain(value T) bool {
_, ok := s[value]
return ok
}
// Contain checks if set contains other set
func (s Set[T]) ContainAll(other Set[T]) bool {
for k := range other {
_, ok := s[k]
if !ok {
return false
}
}
return true
}
// Clone return a copy of set
func (s Set[T]) Clone() Set[T] {
set := NewSet[T]()
set.Add(s.Values()...)
return set
}
// Delete value of set
func (s Set[T]) Delete(values ...T) {
for _, v := range values {
delete(s, v)
}
}
// Equal checks if two set has same elements or not
func (s Set[T]) Equal(other Set[T]) bool {
if s.Size() != other.Size() {
return false
}
return s.ContainAll(other) && other.ContainAll(s)
}
// Iterate call function by every element of set
func (s Set[T]) Iterate(fn func(value T)) {
for v := range s {
fn(v)
}
}
// IsEmpty checks the set is empty or not
func (s Set[T]) IsEmpty() bool {
return len(s) == 0
}
// Size get the number of elements in set
func (s Set[T]) Size() int {
return len(s)
}
// Values return all values of set
func (s Set[T]) Values() []T {
values := make([]T, 0, 0)
s.Iterate(func(value T) {
values = append(values, value)
})
return values
}
// Union creates a new set contain all element of set s and other
func (s Set[T]) Union(other Set[T]) Set[T] {
set := s.Clone()
set.Add(other.Values()...)
return set
}
// Intersection creates a new set whose element both be contained in set s and other
func (s Set[T]) Intersection(other Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if other.Contain(value) {
set.Add(value)
}
})
return set
}
// SymmetricDifference creates a new set whose element is in set1 or set2, but not in both sets
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if !other.Contain(value) {
set.Add(value)
}
})
other.Iterate(func(value T) {
if !s.Contain(value) {
set.Add(value)
}
})
return set
}
// Minus creates an set of whose element in origin set but not in compared set
func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
set := NewSet[T]()
s.Iterate(func(value T) {
if !comparedSet.Contain(value) {
set.Add(value)
}
})
return set
}

View File

@@ -0,0 +1,149 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestSet_Add(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Add")
set := NewSet[int]()
set.Add(1, 2, 3)
expected := NewSet(1, 2, 3)
assert.Equal(true, set.Equal(expected))
}
func TestSet_Contain(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Contain")
set := NewSet[int]()
set.Add(1, 2, 3)
assert.Equal(true, set.Contain(1))
assert.Equal(false, set.Contain(4))
}
func TestSet_ContainAll(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_ContainAll")
set1 := NewSet(1, 2, 3)
set2 := NewSet(1, 2)
set3 := NewSet(1, 2, 3, 4)
assert.Equal(true, set1.ContainAll(set2))
assert.Equal(false, set1.ContainAll(set3))
}
func TestSet_Clone(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Clone")
set1 := NewSet(1, 2, 3)
set2 := set1.Clone()
assert.Equal(true, set1.Size() == set2.Size())
assert.Equal(true, set1.ContainAll(set2))
}
func TestSet_Delete(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Delete")
set := NewSet[int]()
set.Add(1, 2, 3)
set.Delete(3)
expected := NewSet(1, 2)
assert.Equal(true, set.Equal(expected))
}
func TestSet_Equal(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Equal")
set1 := NewSet(1, 2, 3)
set2 := NewSet(1, 2, 3)
set3 := NewSet(1, 2, 3, 4)
assert.Equal(true, set1.Equal(set2))
assert.Equal(false, set1.Equal(set3))
}
func TestSet_Iterate(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Iterate")
set := NewSet(1, 2, 3)
arr := []int{}
set.Iterate(func(value int) {
arr = append(arr, value)
})
assert.Equal(3, len(arr))
}
func TestSet_IsEmpty(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_IsEmpty")
set := NewSet[int]()
assert.Equal(true, set.IsEmpty())
}
func TestSet_Size(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Size")
set := NewSet(1, 2, 3)
assert.Equal(3, set.Size())
}
func TestSet_Values(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Values")
set := NewSet(1, 2, 3)
values := set.Values()
assert.Equal(3, len(values))
}
func TestSet_Union(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Union")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
expected := NewSet(1, 2, 3, 4, 5)
unionSet := set1.Union(set2)
assert.Equal(expected, unionSet)
}
func TestSet_Intersection(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Intersection")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
expected := NewSet(2, 3)
intersectionSet := set1.Intersection(set2)
assert.Equal(expected, intersectionSet)
}
func TestSet_SymmetricDifference(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
assert.Equal(NewSet(1, 4, 5), set1.SymmetricDifference(set2))
}
func TestSet_Minus(t *testing.T) {
assert := internal.NewAssert(t, "TestSet_Minus")
set1 := NewSet(1, 2, 3)
set2 := NewSet(2, 3, 4, 5)
set3 := NewSet(2, 3)
assert.Equal(NewSet(1), set1.Minus(set2))
assert.Equal(NewSet(4, 5), set2.Minus(set3))
}

View File

@@ -0,0 +1,62 @@
package datastructure
import "errors"
// ArrayStack implements stack with slice
type ArrayStack[T any] struct {
data []T
length int
}
// NewArrayStack return a empty ArrayStack pointer
func NewArrayStack[T any]() *ArrayStack[T] {
return &ArrayStack[T]{data: []T{}, length: 0}
}
// Data return stack data
func (s *ArrayStack[T]) Data() []T {
return s.data
}
// Size return length of stack data
func (s *ArrayStack[T]) Size() int {
return s.length
}
// IsEmpty checks if stack is empty or not
func (s *ArrayStack[T]) IsEmpty() bool {
return s.length == 0
}
// Push element into stack
func (s *ArrayStack[T]) Push(value T) {
s.data = append([]T{value}, s.data...)
s.length++
}
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
func (s *ArrayStack[T]) Pop() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
topItem := s.data[0]
s.data = s.data[1:]
s.length--
return &topItem, nil
}
// Peak return the top element of stack then return it
func (s *ArrayStack[T]) Peak() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
return &s.data[0], nil
}
// Clear the stack data
func (s *ArrayStack[T]) Clear() {
s.data = []T{}
s.length = 0
}

View File

@@ -0,0 +1,77 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestArrayStack_Push(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayStack_Push")
stack := NewArrayStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
expected := []int{3, 2, 1}
values := stack.Data()
length := stack.Size()
assert.Equal(expected, values)
assert.Equal(3, length)
}
func TestArrayStack_Pop(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayStack_Pop")
stack := NewArrayStack[int]()
_, err := stack.Pop()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Pop()
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
assert.Equal(expected, stack.Data())
}
func TestArrayStack_Peak(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayStack_Peak")
stack := NewArrayStack[int]()
_, err := stack.Peak()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Peak()
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
}
func TestArrayStack_Clear(t *testing.T) {
assert := internal.NewAssert(t, "TestArrayStack_Clear")
stack := NewArrayStack[int]()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
stack.Push(1)
assert.Equal(false, stack.IsEmpty())
assert.Equal(1, stack.Size())
stack.Clear()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
}

View File

@@ -0,0 +1,94 @@
package datastructure
import (
"errors"
"fmt"
"github.com/duke-git/lancet/v2/datastructure"
)
// LinkedStack implements stack with link list
type LinkedStack[T any] struct {
top *datastructure.StackNode[T]
length int
}
// NewLinkedStack return a empty LinkedStack pointer
func NewLinkedStack[T any]() *LinkedStack[T] {
return &LinkedStack[T]{top: nil, length: 0}
}
// Data return stack data
func (s *LinkedStack[T]) Data() []T {
res := []T{}
current := s.top
for current != nil {
res = append(res, current.Value)
current = current.Next
}
return res
}
// Size return length of stack data
func (s *LinkedStack[T]) Size() int {
return s.length
}
// IsEmpty checks if stack is empty or not
func (s *LinkedStack[T]) IsEmpty() bool {
return s.length == 0
}
// Push element into stack
func (s *LinkedStack[T]) Push(value T) {
newNode := datastructure.NewStackNode(value)
top := s.top
if top == nil {
s.top = newNode
} else {
newNode.Next = top
s.top = newNode
}
s.length++
}
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
func (s *LinkedStack[T]) Pop() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
top := s.top
s.top = s.top.Next
s.length--
return &top.Value, nil
}
// Peak return the top element of stack then return it
func (s *LinkedStack[T]) Peak() (*T, error) {
if s.IsEmpty() {
return nil, errors.New("stack is empty")
}
return &s.top.Value, nil
}
// Clear clear the stack data
func (s *LinkedStack[T]) Clear() {
s.top = nil
s.length = 0
}
// Print all nodes info of stack link
func (s *LinkedStack[T]) Print() {
current := s.top
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
current = current.Next
}
info += " ]"
fmt.Println(info)
}

View File

@@ -0,0 +1,80 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestLinkedStack_Push(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedStack_Push")
stack := NewLinkedStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
stack.Print()
expected := []int{3, 2, 1}
values := stack.Data()
size := stack.Size()
assert.Equal(expected, values)
assert.Equal(3, size)
}
func TestLinkedStack_Pop(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedStack_Pop")
stack := NewLinkedStack[int]()
_, err := stack.Pop()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Pop()
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
stack.Print()
assert.Equal(expected, stack.Data())
}
func TestLinkedStack_Peak(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedStack_Peak")
stack := NewLinkedStack[int]()
_, err := stack.Peak()
assert.IsNotNil(err)
stack.Push(1)
stack.Push(2)
stack.Push(3)
topItem, err := stack.Peak()
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
}
func TestLinkedStack_Empty(t *testing.T) {
assert := internal.NewAssert(t, "TestLinkedStack_Empty")
stack := NewLinkedStack[int]()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
stack.Push(1)
assert.Equal(false, stack.IsEmpty())
assert.Equal(1, stack.Size())
stack.Clear()
assert.Equal(true, stack.IsEmpty())
assert.Equal(0, stack.Size())
}

View File

@@ -0,0 +1,108 @@
package datastructure
import (
"math"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
// BSTree is a binary search tree data structure in which each node has at most two children,
// which are referred to as the left child and the right child.
// In BSTree: leftNode < rootNode < rightNode
// type T should implements Compare function in lancetconstraints.Comparator interface.
type BSTree[T any] struct {
root *datastructure.TreeNode[T]
comparator lancetconstraints.Comparator
}
// NewBSTree create a BSTree pointer
// param `comparator` is used to compare values in the tree
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T] {
root := datastructure.NewTreeNode(rootData)
return &BSTree[T]{root, comparator}
}
// InsertNode insert data into BSTree
func (t *BSTree[T]) InsertNode(data T) {
root := t.root
newNode := datastructure.NewTreeNode(data)
if root == nil {
t.root = newNode
} else {
insertTreeNode(root, newNode, t.comparator)
}
}
// DeletetNode delete data into BSTree
func (t *BSTree[T]) DeletetNode(data T) {
deleteTreeNode(t.root, data, t.comparator)
}
// NodeLevel get node level in BSTree
func (t *BSTree[T]) NodeLevel(node *datastructure.TreeNode[T]) int {
if node == nil {
return 0
}
left := float64(t.NodeLevel(node.Left))
right := float64(t.NodeLevel(node.Right))
return int(math.Max(left, right)) + 1
}
// PreOrderTraverse traverse tree node in pre order
func (t *BSTree[T]) PreOrderTraverse() []T {
return preOrderTraverse(t.root)
}
// PostOrderTraverse traverse tree node in post order
func (t *BSTree[T]) PostOrderTraverse() []T {
return postOrderTraverse(t.root)
}
// InOrderTraverse traverse tree node in mid order
func (t *BSTree[T]) InOrderTraverse() []T {
return inOrderTraverse(t.root)
}
// LevelOrderTraverse traverse tree node in level order
func (t *BSTree[T]) LevelOrderTraverse() []T {
traversal := make([]T, 0)
levelOrderTraverse(t.root, &traversal)
return traversal
}
// Depth returns the calculated depth of a binary saerch tree
func (t *BSTree[T]) Depth() int {
return calculateDepth(t.root, 0)
}
// IsSubTree checks if the tree `t` has `subTree` or not
func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
return hasSubTree(t.root, subTree.root, t.comparator)
}
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
comparator lancetconstraints.Comparator) bool {
res := false
if superTreeRoot != nil && subTreeRoot != nil {
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) == 0 {
res = isSubTree(superTreeRoot, subTreeRoot, comparator)
}
if !res {
res = hasSubTree(superTreeRoot.Left, subTreeRoot, comparator)
}
if !res {
res = hasSubTree(superTreeRoot.Right, subTreeRoot, comparator)
}
}
return res
}
// Print the bstree structure
func (t *BSTree[T]) Print() {
maxLevel := t.NodeLevel(t.root)
nodes := []*datastructure.TreeNode[T]{t.root}
printTreeNodes(nodes, 1, maxLevel)
}

View File

@@ -0,0 +1,157 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
type intComparator struct{}
func (c *intComparator) Compare(v1, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
func TestBSTree_InsertNode(t *testing.T) {
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
bstree.Print()
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
acturl := bstree.PreOrderTraverse()
t.Log(acturl)
assert.Equal([]int{6, 5, 2, 4, 7}, acturl)
}
func TestBSTree_PostOrderTraverse(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
acturl := bstree.PostOrderTraverse()
t.Log(acturl)
assert.Equal([]int{5, 2, 4, 7, 6}, acturl)
}
func TestBSTree_InOrderTraverse(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
acturl := bstree.InOrderTraverse()
t.Log(acturl)
assert.Equal([]int{2, 4, 5, 6, 7}, acturl)
}
func TestBSTree_LevelOrderTraverse(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
bstree.Print()
acturl := bstree.LevelOrderTraverse()
t.Log(acturl)
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
}
func TestBSTree_DeletetNode(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_DeletetNode")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
bstree.Print()
bstree.DeletetNode(4)
bstree.Print()
acturl1 := bstree.InOrderTraverse()
t.Log(acturl1)
assert.Equal([]int{2, 5, 6, 7}, acturl1)
//todo
// bstree.DeletetNode(6, comparator)
// bstree.Print()
// acturl2 := bstree.InOrderTraverse()
// t.Log(acturl2)
// assert.Equal([]int{2, 5, 7}, acturl2)
}
func TestBSTree_Depth(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_Depth")
bstree := NewBSTree(6, &intComparator{})
bstree.InsertNode(7)
bstree.InsertNode(5)
bstree.InsertNode(2)
bstree.InsertNode(4)
bstree.Print()
assert.Equal(bstree.Depth(), 4)
}
func TestBSTree_IsSubTree(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_IsSubTree")
superTree := NewBSTree(8, &intComparator{})
superTree.InsertNode(4)
superTree.InsertNode(5)
superTree.InsertNode(6)
superTree.InsertNode(9)
superTree.InsertNode(4)
superTree.Print()
subTree := NewBSTree(5, &intComparator{})
subTree.InsertNode(4)
subTree.InsertNode(6)
subTree.Print()
assert.Equal(true, superTree.HasSubTree(subTree))
assert.Equal(false, subTree.HasSubTree(superTree))
}

View File

@@ -0,0 +1,238 @@
package datastructure
import (
"fmt"
"math"
"github.com/duke-git/lancet/v2/datastructure"
"github.com/duke-git/lancet/v2/lancetconstraints"
)
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, node.Value)
data = append(data, preOrderTraverse(node.Left)...)
data = append(data, preOrderTraverse(node.Right)...)
}
return data
}
func postOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, preOrderTraverse(node.Left)...)
data = append(data, preOrderTraverse(node.Right)...)
data = append(data, node.Value)
}
return data
}
func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
data := []T{}
if node != nil {
data = append(data, inOrderTraverse(node.Left)...)
data = append(data, node.Value)
data = append(data, inOrderTraverse(node.Right)...)
}
return data
}
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
fmt.Printf("%v, ", node.Value)
preOrderPrint(node.Left)
preOrderPrint(node.Right)
}
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
preOrderPrint(node.Left)
preOrderPrint(node.Right)
fmt.Printf("%v, ", node.Value)
}
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
inOrderPrint(node.Left)
fmt.Printf("%v, ", node.Value)
inOrderPrint(node.Right)
}
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
var q []*datastructure.TreeNode[T] // queue
var n *datastructure.TreeNode[T] // temp node
q = append(q, root)
for len(q) != 0 {
n, q = q[0], q[1:]
*traversal = append(*traversal, n.Value)
if n.Left != nil {
q = append(q, n.Left)
}
if n.Right != nil {
q = append(q, n.Right)
}
}
}
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
if rootNode.Left == nil {
rootNode.Left = newNode
} else {
insertTreeNode(rootNode.Left, newNode, comparator)
}
} else {
if rootNode.Right == nil {
rootNode.Right = newNode
} else {
insertTreeNode(rootNode.Right, newNode, comparator)
}
}
}
// todo, delete root node failed
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
if node == nil {
return nil
}
if comparator.Compare(data, node.Value) == -1 {
node.Left = deleteTreeNode(node.Left, data, comparator)
} else if comparator.Compare(data, node.Value) == 1 {
node.Right = deleteTreeNode(node.Right, data, comparator)
} else {
if node.Left == nil {
node = node.Right
} else if node.Right == nil {
node = node.Left
} else {
l := node.Right
d := inOrderSuccessor(l)
d.Left = node.Left
return node.Right
}
}
return node
}
func inOrderSuccessor[T any](root *datastructure.TreeNode[T]) *datastructure.TreeNode[T] {
cur := root
for cur.Left != nil {
cur = cur.Left
}
return cur
}
func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel int) {
if len(nodes) == 0 || isAllNil(nodes) {
return
}
floor := maxLevel - level
endgeLines := int(math.Pow(float64(2), (math.Max(float64(floor)-1, 0))))
firstSpaces := int(math.Pow(float64(2), float64(floor))) - 1
betweenSpaces := int(math.Pow(float64(2), float64(floor)+1)) - 1
printSpaces(firstSpaces)
newNodes := []*datastructure.TreeNode[T]{}
for _, node := range nodes {
if node != nil {
fmt.Printf("%v", node.Value)
newNodes = append(newNodes, node.Left)
newNodes = append(newNodes, node.Right)
} else {
newNodes = append(newNodes, nil)
newNodes = append(newNodes, nil)
printSpaces(1)
}
printSpaces(betweenSpaces)
}
fmt.Println("")
for i := 1; i <= endgeLines; i++ {
for j := 0; j < len(nodes); j++ {
printSpaces(firstSpaces - i)
if nodes[j] == nil {
printSpaces(endgeLines + endgeLines + i + 1)
continue
}
if nodes[j].Left != nil {
fmt.Print("/")
} else {
printSpaces(1)
}
printSpaces(i + i - 1)
if nodes[j].Right != nil {
fmt.Print("\\")
} else {
printSpaces(1)
}
printSpaces(endgeLines + endgeLines - 1)
}
fmt.Println("")
}
printTreeNodes(newNodes, level+1, maxLevel)
}
// printSpaces
func printSpaces(n int) {
for i := 0; i < n; i++ {
fmt.Print(" ")
}
}
func isAllNil[T any](nodes []*datastructure.TreeNode[T]) bool {
for _, v := range nodes {
if v != nil {
return false
}
}
return true
}
func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
if node == nil {
return depth
}
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
}
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) bool {
if subTreeRoot == nil {
return true
}
if superTreeRoot == nil {
return false
}
if comparator.Compare(superTreeRoot.Value, subTreeRoot.Value) != 0 {
return false
}
res := isSubTree(superTreeRoot.Left, subTreeRoot.Left, comparator) && isSubTree(superTreeRoot.Right, subTreeRoot.Right, comparator)
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

60
datetime/conversion.go Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license.
package datetime
import "time"
type theTime struct {
unix int64
}
// NewUnixNow return unix timestamp of current time
func NewUnixNow() *theTime {
return &theTime{unix: time.Now().Unix()}
}
// NewUnix return unix timestamp of specified time
func NewUnix(unix int64) *theTime {
return &theTime{unix: unix}
}
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss"
func NewFormat(t string) (*theTime, error) {
timeLayout := "2006-01-02 15:04:05"
loc := time.FixedZone("CST", 8*3600)
tt, err := time.ParseInLocation(timeLayout, t, loc)
if err != nil {
return nil, err
}
return &theTime{unix: tt.Unix()}, nil
}
// NewISO8601 return unix timestamp of specified iso8601 time string
func NewISO8601(iso8601 string) (*theTime, error) {
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
if err != nil {
return nil, err
}
return &theTime{unix: t.Unix()}, nil
}
// ToUnix return unix timestamp
func (t *theTime) ToUnix() int64 {
return t.unix
}
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time
func (t *theTime) ToFormat() string {
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
}
// ToFormatForTpl return the time string which format is specified tpl
func (t *theTime) ToFormatForTpl(tpl string) string {
return time.Unix(t.unix, 0).Format(tpl)
}
// ToFormatForTpl return iso8601 time string
func (t *theTime) ToIso8601() string {
return time.Unix(t.unix, 0).Format(time.RFC3339)
}

View File

@@ -0,0 +1,53 @@
package datetime
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestToUnix(t *testing.T) {
assert := internal.NewAssert(t, "TestToUnix")
tm1 := NewUnixNow()
unixTimestamp := tm1.ToUnix()
tm2 := NewUnix(unixTimestamp)
assert.Equal(tm1, tm2)
}
func TestToFormat(t *testing.T) {
assert := internal.NewAssert(t, "TestToFormat")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormat -> ", tm.ToFormat())
}
func TestToFormatForTpl(t *testing.T) {
assert := internal.NewAssert(t, "TestToFormatForTpl")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
}
func TestToIso8601(t *testing.T) {
assert := internal.NewAssert(t, "TestToIso8601")
_, err := NewISO8601("2022-03-18 17:04:05")
assert.IsNotNil(err)
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
assert.IsNil(err)
t.Log("ToIso8601 -> ", tm.ToIso8601())
}

View File

@@ -25,7 +25,7 @@
package datetime
import (
"strconv"
"fmt"
"time"
)
@@ -56,24 +56,17 @@ func init() {
// AddMinute add or sub minute to the time
func AddMinute(t time.Time, minute int64) time.Time {
s := strconv.FormatInt(minute, 10)
m, _ := time.ParseDuration(s + "m")
return t.Add(m)
return t.Add(time.Minute * time.Duration(minute))
}
// AddHour add or sub hour to the time
func AddHour(t time.Time, hour int64) time.Time {
s := strconv.FormatInt(hour, 10)
h, _ := time.ParseDuration(s + "h")
return t.Add(h)
return t.Add(time.Hour * time.Duration(hour))
}
// AddDay add or sub day to the time
func AddDay(t time.Time, day int64) time.Time {
dayHours := day * 24
d := strconv.FormatInt(dayHours, 10)
h, _ := time.ParseDuration(d + "h")
return t.Add(h)
return t.Add(24 * time.Hour * time.Duration(day))
}
// GetNowDate return format yyyy-mm-dd of current date
@@ -109,7 +102,81 @@ func FormatTimeToStr(t time.Time, format string) string {
}
// FormatStrToTime convert string to time
func FormatStrToTime(str, format string) time.Time {
t, _ := time.Parse(timeFormat[format], str)
return t
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
if !ok {
return time.Time{}, fmt.Errorf("format %s not found", format)
}
return time.Parse(v, str)
}
// BeginOfMinute return beginning minute time of day
func BeginOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
}
// EndOfMinute return end minute time of day
func EndOfMinute(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfHour return beginning hour time of day
func BeginOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
}
// EndOfHour return end hour time of day
func EndOfHour(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfDay return beginning hour time of day
func BeginOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// EndOfDay return end time of day
func EndOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfWeek return beginning week, week begin from Sunday
func BeginOfWeek(t time.Time) time.Time {
y, m, d := t.AddDate(0, 0, 0-int(BeginOfDay(t).Weekday())).Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// EndOfWeek return end week time, week end with Saturday
func EndOfWeek(t time.Time) time.Time {
y, m, d := BeginOfWeek(t).AddDate(0, 0, 7).Add(-time.Nanosecond).Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfMonth return beginning of month
func BeginOfMonth(t time.Time) time.Time {
y, m, _ := t.Date()
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
}
// EndOfMonth return end of month
func EndOfMonth(t time.Time) time.Time {
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
}
// BeginOfYear return beginning of year
func BeginOfYear(t time.Time) time.Time {
y, _, _ := t.Date()
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
}
// EndOfYear return end of year
func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
}

View File

@@ -1,103 +1,72 @@
package datetime
import (
"github.com/duke-git/lancet/utils"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestAddDay(t *testing.T) {
now := time.Now()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Days := AddDay(now, 2)
diff1 := after2Days.Sub(now)
if diff1.Hours() != 48 {
utils.LogFailedTestInfo(t, "AddDay", now, 48, diff1.Hours())
t.FailNow()
}
assert.Equal(float64(48), diff1.Hours())
before2Days := AddDay(now, -2)
diff2 := before2Days.Sub(now)
if diff2.Hours() != -48 {
utils.LogFailedTestInfo(t, "AddDay", now, -48, diff2.Hours())
t.FailNow()
}
assert.Equal(float64(-48), diff2.Hours())
}
func TestAddHour(t *testing.T) {
now := time.Now()
func TestAddHour(t *testing.T) {
assert := internal.NewAssert(t, "TestAddHour")
now := time.Now()
after2Hours := AddHour(now, 2)
diff1 := after2Hours.Sub(now)
if diff1.Hours() != 2 {
utils.LogFailedTestInfo(t, "AddHour", now, 2, diff1.Hours())
t.FailNow()
}
assert.Equal(float64(2), diff1.Hours())
before2Hours := AddHour(now, -2)
diff2 := before2Hours.Sub(now)
if diff2.Hours() != -2 {
utils.LogFailedTestInfo(t, "AddHour", now, -2, diff2.Hours())
t.FailNow()
}
assert.Equal(float64(-2), diff2.Hours())
}
func TestAddMinute(t *testing.T) {
now := time.Now()
assert := internal.NewAssert(t, "TestAddMinute")
now := time.Now()
after2Minutes := AddMinute(now, 2)
diff1 := after2Minutes.Sub(now)
if diff1.Minutes() != 2 {
utils.LogFailedTestInfo(t, "AddMinute", now, 2, diff1.Minutes())
t.FailNow()
}
assert.Equal(float64(2), diff1.Minutes())
before2Minutes := AddMinute(now, -2)
diff2 := before2Minutes.Sub(now)
if diff2.Minutes() != -2 {
utils.LogFailedTestInfo(t, "AddMinute", now, -2, diff2.Minutes())
t.FailNow()
}
assert.Equal(float64(-2), diff2.Minutes())
}
func TestGetNowDate(t *testing.T) {
date := GetNowDate()
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
if date != expected {
utils.LogFailedTestInfo(t, "GetNowDate", "", expected, date)
t.FailNow()
}
assert.Equal(expected, GetNowDate())
}
func TestGetNotTime(t *testing.T) {
ts := GetNowTime()
assert := internal.NewAssert(t, "TestGetNotTime")
expected := time.Now().Format("15:04:05")
if ts != expected {
utils.LogFailedTestInfo(t, "GetNowTime", "", expected, ts)
t.FailNow()
}
assert.Equal(expected, GetNowTime())
}
func TestGetNowDateTime(t *testing.T) {
ts := GetNowDateTime()
assert := internal.NewAssert(t, "TestGetNowDateTime")
expected := time.Now().Format("2006-01-02 15:04:05")
if ts != expected {
utils.LogFailedTestInfo(t, "GetNowDateTime", "", expected, ts)
t.FailNow()
}
assert.Equal(expected, GetNowDateTime())
}
//todo
//func TestGetZeroHourTimestamp(t *testing.T) {
// ts := GetZeroHourTimestamp()
// expected := time.Now().UTC().Unix() - 8*3600
// if ts != expected {
// utils.LogFailedTestInfo(t, "GetZeroHourTimestamp", "", expected, ts)
// t.FailNow()
// }
//}
func TestFormatTimeToStr(t *testing.T) {
assert := internal.NewAssert(t, "TestFormatTimeToStr")
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
cases := []string{
"yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd",
@@ -110,16 +79,15 @@ func TestFormatTimeToStr(t *testing.T) {
"16:04:08", "2021/01"}
for i := 0; i < len(cases); i++ {
res := FormatTimeToStr(datetime, cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected[i], res)
t.FailNow()
}
}
actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual)
}
}
func TestFormatStrToTime(t *testing.T) {
assert := internal.NewAssert(t, "TestFormatStrToTime")
formats := []string{
"2006-01-02 15:04:05", "2006-01-02",
"02-01-06 15:04:05", "2006/01/02 15:04:05",
@@ -135,11 +103,131 @@ func TestFormatStrToTime(t *testing.T) {
"2021/01"}
for i := 0; i < len(cases); i++ {
res := FormatStrToTime(datetimeStr[i], cases[i])
expected, _ := time.Parse(formats[i], datetimeStr[i])
if res != expected {
utils.LogFailedTestInfo(t, "FormatTimeToStr", cases[i], expected, res)
t.FailNow()
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
if err != nil {
t.Fatal(err)
}
expected, _ := time.Parse(formats[i], datetimeStr[i])
assert.Equal(expected, actual)
}
}
func TestBeginOfMinute(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfMinute(td)
assert.Equal(expected, actual)
}
func TestEndOfMinute(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfMinute(td)
assert.Equal(expected, actual)
}
func TestBeginOfHour(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfHour")
expected := time.Date(2022, 2, 15, 15, 0, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfHour(td)
assert.Equal(expected, actual)
}
func TestEndOfHour(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfHour")
expected := time.Date(2022, 2, 15, 15, 59, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfHour(td)
assert.Equal(expected, actual)
}
func TestBeginOfDay(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfDay")
expected := time.Date(2022, 2, 15, 0, 0, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfDay(td)
assert.Equal(expected, actual)
}
func TestEndOfDay(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfDay")
expected := time.Date(2022, 2, 15, 23, 59, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfDay(td)
assert.Equal(expected, actual)
}
func TestBeginOfWeek(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfWeek")
expected := time.Date(2022, 2, 13, 0, 0, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfWeek(td)
assert.Equal(expected, actual)
}
func TestEndOfWeek(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfWeek")
expected := time.Date(2022, 2, 19, 23, 59, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfWeek(td)
assert.Equal(expected, actual)
}
func TestBeginOfMonth(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfMonth")
expected := time.Date(2022, 2, 1, 0, 0, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfMonth(td)
assert.Equal(expected, actual)
}
func TestEndOfMonth(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfMonth")
expected := time.Date(2022, 2, 28, 23, 59, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfMonth(td)
assert.Equal(expected, actual)
}
func TestBeginOfYear(t *testing.T) {
assert := internal.NewAssert(t, "TestBeginOfYear")
expected := time.Date(2022, 1, 1, 0, 0, 0, 0, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := BeginOfYear(td)
assert.Equal(expected, actual)
}
func TestEndOfYear(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfYear")
expected := time.Date(2022, 12, 31, 23, 59, 59, 999999999, time.Local)
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
actual := EndOfYear(td)
assert.Equal(expected, actual)
}

598
docs/algorithm.md Normal file
View File

@@ -0,0 +1,598 @@
# Algorithm
Package algorithm implements some basic algorithm. eg. sort, search.
<div STYLE="page-break-after: always;"></div>
## Source
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## Usage
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Algorithm](#algorithm)
- [Source](#source)
- [Usage](#usage)
- [Index](#index)
- [Documentation](#documentation)
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
- [<span id="ShellSort">ShellSort</span>](#shellsort)
- [<span id="QuickSort">QuickSort</span>](#quicksort)
- [<span id="HeapSort">HeapSort</span>](#heapsort)
- [<span id="MergeSort">MergeSort</span>](#mergesort)
- [<span id="CountSort">CountSort</span>](#countsort)
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
- [<span id="LRUCache">LRUCache</span>](#lrucache)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="BubbleSort">BubbleSort</span>
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
//decending order
// if p1.Age > p2.Age {
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="ShellSort">ShellSort</span>
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="QuickSort">QuickSort</span>
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="HeapSort">HeapSort</span>
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="MergeSort">MergeSort</span>
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="CountSort">CountSort</span>
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
<b>Signature:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b>
```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LRUCache">LRUCache</span>
<p>LRUCache implements mem cache with lru.</p>
<b>Signature:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false
v, ok := cache.Get(1) // v->1, ok->true
}
```

598
docs/algorithm_zh-CN.md Normal file
View File

@@ -0,0 +1,598 @@
# Algorithm
algorithm算法包实现一些基本算法sortsearchlrucache。
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
"github.com/duke-git/lancet/v2/algorithm"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Algorithm](#algorithm)
- [源码](#源码)
- [用法](#用法)
- [目录](#目录)
- [文档](#文档)
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
- [<span id="ShellSort">ShellSort</span>](#shellsort)
- [<span id="QuickSort">QuickSort</span>](#quicksort)
- [<span id="HeapSort">HeapSort</span>](#heapsort)
- [<span id="MergeSort">MergeSort</span>](#mergesort)
- [<span id="CountSort">CountSort</span>](#countsort)
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
- [<span id="LRUCache">LRUCache</span>](#lrucache)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="InsertionSort">InsertionSort</span>
<p>插入排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type people struct {
Name string
Age int
}
// PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people)
p2, _ := v2.(people)
//ascending order
if p1.Age < p2.Age {
return -1
} else if p1.Age > p2.Age {
return 1
}
return 0
//decending order
// if p1.Age > p2.Age {
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20},
{Name: "b", Age: 10},
{Name: "c", Age: 17},
{Name: "d", Age: 8},
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator)
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
}
```
### <span id="SelectionSort">SelectionSort</span>
<p>选择排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="ShellSort">ShellSort</span>
<p>希尔排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="QuickSort">QuickSort</span>
<p>快速排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="HeapSort">HeapSort</span>
<p>堆排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="MergeSort">MergeSort</span>
<p>归并排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="CountSort">CountSort</span>
<p>计数排序参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
}
```
### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LinearSearch">LinearSearch</span>
<p>线性查找,返回元素索引,未找到元素返回-1参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b>
```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int)
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
}
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
fmt.Println(notFoundIndex) //-1
}
```
### <span id="LRUCache">LRUCache</span>
<p>lru实现缓存</p>
<b>函数签名:</b>
```go
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/algorithm"
)
func main() {
cache := algorithm.NewLRUCache[int, int](2)
cache.Put(1, 1)
cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false
v, ok := cache.Get(1) // v->1, ok->true
}
```

390
docs/concurrency.md Normal file
View File

@@ -0,0 +1,390 @@
# Concurrency
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
## Documentation
## Channel
### <span id="NewChannel">NewChannel</span>
<p>return a Channel pointer instance.</p>
<b>Signature:</b>
```go
type Channel struct {}
func NewChannel() *Channel
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel()
}
```
### <span id="Bridge">Bridge</span>
<p>Link multiple channels into one channel until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
}
}
```
### <span id="FanIn">FanIn</span>
<p>merge multiple channels into one channel until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
}
}
```
### <span id="Repeat">Repeat</span>
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
}
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
}
}
```
### <span id="Or">Or</span>
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
<b>Signature:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>Read a channel into another channel, will close until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
}
}
```
### <span id="Take">Take</span>
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
}
}
```
### <span id="Tee">Tee</span>
<p>Split one chanel into two channels until cancel context.</p>
<b>Signature:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
}
}
```

390
docs/concurrency_zh-CN.md Normal file
View File

@@ -0,0 +1,390 @@
# Concurrency
并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/concurrency"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
### Channel
- [NewChannel](#NewChannel)
- [Bridge](#Bridge)
- [FanIn](#FanIn)
- [Generate](#Generate)
- [Or](#Or)
- [OrDone](#OrDone)
- [Repeat](#Repeat)
- [RepeatFn](#RepeatFn)
- [Take](#Take)
- [Tee](#Tee)
<div STYLE="page-break-after: always;"></div>
## 文档
### Channel
### <span id="NewChannel">NewChannel</span>
<p>返回一个 Channel 指针实例</p>
<b>函数签名:</b>
```go
type Channel struct {}
func NewChannel() *Channel
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
c := concurrency.NewChannel()
}
```
### <span id="Bridge">Bridge</span>
<p>将多个通道链接到一个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream <- i
close(stream)
chanStream <- stream
}
}()
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
}
}
```
### <span id="FanIn">FanIn</span>
<p>将多个通道合并为一个通道,直到取消上下文</p>
<b>函数签名:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
}
mergedChannel := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
}
}
```
### <span id="Repeat">Repeat</span>
<p>返回一个chan将参数`values`重复放入chan直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
}
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个chan重复执行函数fn并将结果放入返回的chan直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
}
}
```
### <span id="Or">Or</span>
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
c := concurrency.NewChannel()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
}
```
### <span id="OrDone">OrDone</span>
<p>将一个通道读入另一个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
}
}
```
### <span id="Take">Take</span>
<p>返回一个chan其值从另一个chan获取直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers <- 1
numbers <- 2
numbers <- 3
numbers <- 4
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
}
}
```
### <span id="Tee">Tee</span>
<p>将一个通道分成两个通道,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
}
}
```

349
docs/convertor.md Normal file
View File

@@ -0,0 +1,349 @@
# Convertor
Package convertor contains some functions for data type convertion.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>Convert color hex to color rgb.</p>
<b>Signature:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>Convert color rgb to color hex.</p>
<b>Signature:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := convertor.ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366
}
```
### <span id="ToBool">ToBool</span>
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
<b>Signature:</b>
```go
func ToBool(s string) (bool, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v1, _ := convertor.ToBool("1")
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true")
fmt.Println(v2) //true
v3, _ := convertor.ToBool("True")
fmt.Println(v3) //true
v4, _ := convertor.ToBool("123")
fmt.Println(v4) //false
}
```
### <span id="ToBytes">ToBytes</span>
<p>Convert interface to byte slice.</p>
<b>Signature:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("0")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
}
```
### <span id="ToChar">ToChar</span>
<p>Convert string to char slice.</p>
<b>Signature:</b>
```go
func ToChar(s string) []string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
chars := convertor.ToChar("")
fmt.Println(chars) //[]string{""}
chars = convertor.ToChar("abc")
fmt.Println(chars) //[]string{"a", "b", "c"}
chars = convertor.ToChar("1 2#3")
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
}
```
### <span id="ToFloat">ToFloat</span>
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
<b>Signature:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToFloat("")
if err != nil {
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat("-.11")
fmt.Println(v) //-0.11
}
```
### <span id="ToInt">ToInt</span>
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<b>Signature:</b>
```go
func ToInt(value any) (int64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToInt("")
if err != nil {
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat(1.12)
fmt.Println(v) //1
}
```
### <span id="ToJson">ToJson</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
<b>Signature:</b>
```go
func ToJson(value any) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
}
```
### <span id="ToString">ToString</span>
<p>Convert interface to string. </p>
<b>Signature:</b>
```go
func ToString(value any) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1"
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
}
```
### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
<b>Signature:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```

351
docs/convertor_zh-CN.md Normal file
View File

@@ -0,0 +1,351 @@
# Convertor
convertor转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/convertor"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb</p>
<b>函数签名:</b>
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制</p>
<b>函数签名:</b>
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := convertor.ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366
}
```
### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型使用strconv.ParseBool</p>
<b>函数签名:</b>
```go
func ToBool(s string) (bool, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v1, _ := convertor.ToBool("1")
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true")
fmt.Println(v2) //true
v3, _ := convertor.ToBool("True")
fmt.Println(v3) //true
v4, _ := convertor.ToBool("123")
fmt.Println(v4) //false
}
```
### <span id="ToBytes">ToBytes</span>
<p>interface转字节切片.</p>
<b>函数签名:</b>
```go
func ToBytes(data any) ([]byte, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
bytesData, err := convertor.ToBytes("0")
if err != nil {
fmt.Println(err)
}
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
}
```
### <span id="ToChar">ToChar</span>
<p>字符串转字符切片</p>
<b>函数签名:</b>
```go
func ToChar(s string) []string
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
chars := convertor.ToChar("")
fmt.Println(chars) //[]string{""}
chars = convertor.ToChar("abc")
fmt.Println(chars) //[]string{"a", "b", "c"}
chars = convertor.ToChar("1 2#3")
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b>
```go
func ToFloat(value any) (float64, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToFloat("")
if err != nil {
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat("-.11")
fmt.Println(v) //-0.11
}
```
### <span id="ToInt">ToInt</span>
<p>将interface转成intt64类型如果参数无法转换会返回0和error</p>
<b>函数签名:</b>
```go
func ToInt(value any) (int64, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
v, err := convertor.ToInt("")
if err != nil {
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
}
fmt.Println(v) //0
v, _ = convertor.ToFloat(1.12)
fmt.Println(v) //1
}
```
### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串如果参数无法转换会返回""和error</p>
<b>函数签名:</b>
```go
func ToJson(value any) (string, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
}
```
### <span id="ToString">ToString</span>
<p>将interface转成字符串</p>
<b>函数签名:</b>
```go
func ToString(value any) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1"
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
}
```
### <span id="StructToMap">StructToMap</span>
<p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
<b>函数签名:</b>
```go
func StructToMap(value any) (map[string]any, error)
```
<b>列子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type People struct {
Name string `json:"name"`
age int
}
p := People{
"test",
100,
}
pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```

1033
docs/cryptor.md Normal file

File diff suppressed because it is too large Load Diff

1028
docs/cryptor_zh-CN.md Normal file

File diff suppressed because it is too large Load Diff

897
docs/datetime.md Normal file
View File

@@ -0,0 +1,897 @@
# Datetime
Package datetime supports date and time format and compare.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/datetime/datetime.go](https://github.com/duke-git/lancet/blob/main/datetime/datetime.go)
- [https://github.com/duke-git/lancet/blob/main/datetime/conversion.go](https://github.com/duke-git/lancet/blob/main/datetime/conversion.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/datetime"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [AddDay](#AddDay)
- [AddHour](#AddHour)
- [AddMinute](#AddMinute)
- [BeginOfMinute](#BeginOfMinute)
- [BeginOfHour](#BeginOfHour)
- [BeginOfDay](#BeginOfDay)
- [BeginOfWeek](#BeginOfWeek)
- [BeginOfMonth](#BeginOfMonth)
- [BeginOfYear](#BeginOfYear)
- [EndOfMinute](#EndOfMinute)
- [EndOfHour](#EndOfHour)
- [EndOfDay](#EndOfDay)
- [EndOfWeek](#EndOfWeek)
- [EndOfMonth](#EndOfMonth)
- [EndOfYear](#EndOfYear)
- [GetNowDate](#GetNowDate)
- [GetNowTime](#GetNowTime)
- [GetNowDateTime](#GetNowDateTime)
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
- [FormatStrToTime](#FormatStrToTime)
- [NewUnixNow](#NewUnixNow)
- [NewUnix](#NewUnix)
- [NewFormat](#NewFormat)
- [NewISO8601](#NewISO8601)
- [ToUnix](#ToUnix)
- [ToFormat](#ToFormat)
- [ToFormatForTpl](#ToFormatForTpl)
- [ToIso8601](#ToIso8601)
<div STYLE="page-break-after: always;"></div>
## Documentation
## Note:
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
- yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm
- yyyy-mm-dd hh
- yyyy-mm-dd
- yyyy-mm
- mm-dd
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyy
- mm
- hh:mm:ss
- mm:ss
### <span id="AddDay">AddDay</span>
<p>Add or sub days to time.</p>
<b>Signature:</b>
```go
func AddDay(t time.Time, day int64) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Days := datetime.AddDay(now, 2)
before2Days := datetime.AddDay(now, -2)
fmt.Println(after2Days, before2Days)
}
```
### <span id="AddHour">AddHour</span>
<p>Add or sub hours to time.</p>
<b>Signature:</b>
```go
func AddHour(t time.Time, hour int64) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Hours := datetime.AddHour(now, 2)
before2Hours := datetime.AddHour(now, -2)
fmt.Println(after2Hours, after2Hours)
}
```
### <span id="AddMinute">AddMinute</span>
<p>Add or sub minutes to time.</p>
<b>Signature:</b>
```go
func AddMinute(t time.Time, minute int64) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Minute := datetime.AddMinute(now, 2)
before2Minute := datetime.AddMinute(now, -2)
fmt.Println(after2Minute, before2Minute)
}
```
### <span id="BeginOfMinute">BeginOfMinute</span>
<p>Return beginning minute time of day.</p>
<b>Signature:</b>
```go
func BeginOfMinute(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfMinute(td)
fmt.Println(bm) //2022-02-15 15:48:00 +0800 CST
}
```
### <span id="BeginOfHour">BeginOfHour</span>
<p>Return zero time of day.</p>
<b>Signature:</b>
```go
func BeginOfHour(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfHour(td)
fmt.Println(bm) //2022-02-15 15:00:00 +0800 CST
}
```
### <span id="BeginOfDay">BeginOfDay</span>
<p>Return begin time of day.</p>
<b>Signature:</b>
```go
func BeginOfDay(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfDay(td)
fmt.Println(bm) //2022-02-15 00:00:00 +0800 CST
}
```
### <span id="BeginOfWeek">BeginOfWeek</span>
<p>Return beginning time of week, week begin from Sunday.</p>
<b>Signature:</b>
```go
func BeginOfWeek(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfWeek(td)
fmt.Println(bm) //2022-02-13 00:00:00 +0800 CST
}
```
### <span id="BeginOfMonth">BeginOfMonth</span>
<p>Return beginning time of month</p>
<b>Signature:</b>
```go
func BeginOfMonth(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfMonth(td)
fmt.Println(bm) //2022-02-01 00:00:00 +0800 CST
}
```
### <span id="BeginOfYear">BeginOfYear</span>
<p>Return beginning time of year.</p>
<b>Signature:</b>
```go
func BeginOfYear(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfYear(td)
fmt.Println(bm) //2022-01-01 00:00:00 +0800 CST
}
```
### <span id="EndOfMinute">EndOfMinute</span>
<p>Return end time minute of day.</p>
<b>Signature:</b>
```go
func EndOfMinute(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfMinute(td)
fmt.Println(bm) //2022-02-15 15:48:59.999999999 +0800 CST
}
```
### <span id="EndOfHour">EndOfHour</span>
<p>Return end time hour of day.</p>
<b>Signature:</b>
```go
func EndOfHour(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfHour(td)
fmt.Println(bm) //2022-02-15 15:59:59.999999999 +0800 CST
}
```
### <span id="EndOfDay">EndOfDay</span>
<p>Return end time hour of day.</p>
<b>Signature:</b>
```go
func EndOfDay(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfDay(td)
fmt.Println(bm) //2022-02-15 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfWeek">EndOfWeek</span>
<p>Return end time of week, week end with Saturday.</p>
<b>Signature:</b>
```go
func EndOfWeek(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfWeek(td)
fmt.Println(bm) //2022-02-19 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfMonth">EndOfMonth</span>
<p>Return end time of month</p>
<b>Signature:</b>
```go
func EndOfMonth(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfMonth(td)
fmt.Println(bm) //2022-02-28 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfYear">EndOfYear</span>
<p>Return beginning time of year.</p>
<b>Signature:</b>
```go
func EndOfYear(t time.Time) time.Time
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfYear(td)
fmt.Println(bm) //2022-12-31 23:59:59.999999999 +0800 CST
}
```
### <span id="GetNowDate">GetNowDate</span>
<p>Get current date string, format is yyyy-mm-dd.</p>
<b>Signature:</b>
```go
func GetNowDate() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentDate := datetime.GetNowDate()
fmt.Println(currentDate) // 2022-01-28
}
```
### <span id="GetNowTime">GetNowTime</span>
<p>Get current time string, format is hh:mm:ss.</p>
<b>Signature:</b>
```go
func GetNowTime() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentTime := datetime.GetNowTime()
fmt.Println(currentDate) // 15:57:33
}
```
### <span id="GetNowDateTime">GetNowDateTime</span>
<p>Get current date time string, format is yyyy-mm-dd hh:mm:ss.</p>
<b>Signature:</b>
```go
func GetNowDateTime() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
current := datetime.GetNowDateTime()
fmt.Println(current) // 2022-01-28 15:59:33
}
```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>Return timestamp of zero hour (timestamp of 00:00).</p>
<b>Signature:</b>
```go
func GetZeroHourTimestamp() int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime) // 1643299200
}
```
### <span id="GetNightTimestamp">GetNightTimestamp</span>
<p>Return timestamp of zero hour (timestamp of 23:59).</p>
<b>Signature:</b>
```go
func GetNightTimestamp() int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime) // 1643385599
}
```
### <span id="FormatTimeToStr">FormatTimeToStr</span>
<p>Format time to string, `format` param specification see note 1.</p>
<b>Signature:</b>
```go
func FormatTimeToStr(t time.Time, format string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
timeStr := datetime.FormatTimeToStr(now, "yyyy/mm/dd hh:mm:ss")
fmt.Println(timeStr) //2022/01/28 16:07:44
}
```
### <span id="FormatStrToTime">FormatStrToTime</span>
<p>Format string to time, `format` param specification see note 1.</p>
<b>Signature:</b>
```go
func FormatStrToTime(str, format string) (time.Time, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
time := datetime.FormatStrToTime("2006-01-02 15:04:05", "yyyy/mm/dd hh:mm:ss")
fmt.Println(time)
}
```
### <span id="NewUnixNow">NewUnixNow</span>
<p>Return unix timestamp of current time</p>
<b>Signature:</b>
```go
type theTime struct {
unix int64
}
func NewUnixNow() *theTime
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnixNow()
fmt.Println(tm) //&{1647597438}
}
```
### <span id="NewUnix">NewUnix</span>
<p>Return unix timestamp of specified int64 value.</p>
<b>Signature:</b>
```go
type theTime struct {
unix int64
}
func NewUnix(unix int64) *theTime
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnix(1647597438)
fmt.Println(tm) //&{1647597438}
}
```
### <span id="NewFormat">NewFormat</span>
<p>Return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".</p>
<b>Signature:</b>
```go
type theTime struct {
unix int64
}
func NewFormat(t string) (*theTime, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, err := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm) //&{1647594245}
}
```
### <span id="NewISO8601">NewISO8601</span>
<p>Return unix timestamp of specified iso8601 time string.</p>
<b>Signature:</b>
```go
type theTime struct {
unix int64
}
func NewISO8601(iso8601 string) (*theTime, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
fmt.Println(tm) //&{1136214245}
}
```
### <span id="ToUnix">ToUnix</span>
<p>Return unix timestamp.</p>
<b>Signature:</b>
```go
func (t *theTime) ToUnix() int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnixNow()
fmt.Println(tm.ToUnix()) //1647597438
}
```
### <span id="ToFormat">ToFormat</span>
<p>Return time string 'yyyy-mm-dd hh:mm:ss'.</p>
<b>Signature:</b>
```go
func (t *theTime) ToFormat() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm.ToFormat()) //"2022-03-18 17:04:05"
}
```
### <span id="ToFormatForTpl">ToFormatForTpl</span>
<p>Return the time string which format is specified tpl.</p>
<b>Signature:</b>
```go
func (t *theTime) ToFormatForTpl(tpl string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
ts := tm.ToFormatForTpl("2006/01/02 15:04:05")
fmt.Println(ts) //"2022/03/18 17:04:05"
}
```
### <span id="ToIso8601">ToIso8601</span>
<p>Return iso8601 time string.</p>
<b>Signature:</b>
```go
func (t *theTime) ToIso8601() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
ts := tm.ToIso8601()
fmt.Println(ts) //"2006-01-02T23:04:05+08:00"
}
```

893
docs/datetime_zh-CN.md Normal file
View File

@@ -0,0 +1,893 @@
# Datetime
datetime日期时间处理包格式化日期比较日期。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/datetime/datetime.go](https://github.com/duke-git/lancet/blob/main/datetime/datetime.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/datetime"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [AddDay](#AddDay)
- [AddHour](#AddHour)
- [AddMinute](#AddMinute)
- [BeginOfMinute](#BeginOfMinute)
- [BeginOfHour](#BeginOfHour)
- [BeginOfDay](#BeginOfDay)
- [BeginOfWeek](#BeginOfWeek)
- [BeginOfMonth](#BeginOfMonth)
- [BeginOfYear](#BeginOfYear)
- [EndOfMinute](#EndOfMinute)
- [EndOfHour](#EndOfHour)
- [EndOfDay](#EndOfDay)
- [EndOfWeek](#EndOfWeek)
- [EndOfMonth](#EndOfMonth)
- [EndOfYear](#EndOfYear)
- [GetNowDate](#GetNowDate)
- [GetNowTime](#GetNowTime)
- [GetNowDateTime](#GetNowDateTime)
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
- [FormatStrToTime](#FormatStrToTime)
- [NewUnixNow](#NewUnixNow)
- [NewUnix](#NewUnix)
- [NewFormat](#NewFormat)
- [NewISO8601](#NewISO8601)
- [ToUnix](#ToUnix)
- [ToFormat](#ToFormat)
- [ToFormatForTpl](#ToFormatForTpl)
- [ToIso8601](#ToIso8601)
<div STYLE="page-break-after: always;"></div>
## 文档
## 注:
1. 方法FormatTimeToStr和FormatStrToTime中的format参数值需要传以下类型之一
- yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm
- yyyy-mm-dd hh
- yyyy-mm-dd
- yyyy-mm
- mm-dd
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyy
- mm
- hh:mm:ss
- mm:ss
### <span id="AddDay">AddDay</span>
<p>将日期加/减天数</p>
<b>函数签名:</b>
```go
func AddDay(t time.Time, day int64) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Days := datetime.AddDay(now, 2)
before2Days := datetime.AddDay(now, -2)
fmt.Println(after2Days, before2Days)
}
```
### <span id="AddHour">AddHour</span>
<p>将日期加/减小时数</p>
<b>函数签名:</b>
```go
func AddHour(t time.Time, hour int64) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Hours := datetime.AddHour(now, 2)
before2Hours := datetime.AddHour(now, -2)
fmt.Println(after2Hours, after2Hours)
}
```
### <span id="AddMinute">AddMinute</span>
<p>将日期加/减分钟数</p>
<b>函数签名:</b>
```go
func AddMinute(t time.Time, minute int64) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
after2Minute := datetime.AddMinute(now, 2)
before2Minute := datetime.AddMinute(now, -2)
fmt.Println(after2Minute, before2Minute)
}
```
### <span id="BeginOfMinute">BeginOfMinute</span>
<p>返回指定时间的分钟开始时间</p>
<b>函数签名:</b>
```go
func BeginOfMinute(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfMinute(td)
fmt.Println(bm) //2022-02-15 15:48:00 +0800 CST
}
```
### <span id="BeginOfHour">BeginOfHour</span>
<p>返回指定时间的小时开始时间</p>
<b>函数签名:</b>
```go
func BeginOfHour(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfHour(td)
fmt.Println(bm) //2022-02-15 15:00:00 +0800 CST
}
```
### <span id="BeginOfDay">BeginOfDay</span>
<p>返回指定时间的当天开始时间</p>
<b>函数签名:</b>
```go
func BeginOfDay(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfDay(td)
fmt.Println(bm) //2022-02-15 00:00:00 +0800 CST
}
```
### <span id="BeginOfWeek">BeginOfWeek</span>
<p>返回指定时间的星期开始时间</p>
<b>函数签名:</b>
```go
func BeginOfWeek(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfWeek(td)
fmt.Println(bm) //2022-02-13 00:00:00 +0800 CST
}
```
### <span id="BeginOfMonth">BeginOfMonth</span>
<p>返回指定时间的当月开始时间</p>
<b>函数签名:</b>
```go
func BeginOfMonth(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfMonth(td)
fmt.Println(bm) //2022-02-01 00:00:00 +0800 CST
}
```
### <span id="BeginOfYear">BeginOfYear</span>
<p>返回指定时间的当年开始时间</p>
<b>函数签名:</b>
```go
func BeginOfYear(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.BeginOfYear(td)
fmt.Println(bm) //2022-01-01 00:00:00 +0800 CST
}
```
### <span id="EndOfMinute">EndOfMinute</span>
<p>返回指定时间的分钟结束时间</p>
<b>函数签名:</b>
```go
func EndOfMinute(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfMinute(td)
fmt.Println(bm) //2022-02-15 15:48:59.999999999 +0800 CST
}
```
### <span id="EndOfHour">EndOfHour</span>
<p>返回指定时间的小时结束时间</p>
<b>函数签名:</b>
```go
func EndOfHour(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfHour(td)
fmt.Println(bm) //2022-02-15 15:59:59.999999999 +0800 CST
}
```
### <span id="EndOfDay">EndOfDay</span>
<p>返回指定时间的当天结束时间.</p>
<b>函数签名:</b>
```go
func EndOfDay(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfDay(td)
fmt.Println(bm) //2022-02-15 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfWeek">EndOfWeek</span>
<p>返回指定时间的星期结束时间</p>
<b>函数签名:</b>
```go
func EndOfWeek(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfWeek(td)
fmt.Println(bm) //2022-02-19 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfMonth">EndOfMonth</span>
<p>返回指定时间的月份结束时间</p>
<b>函数签名:</b>
```go
func EndOfMonth(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfMonth(td)
fmt.Println(bm) //2022-02-28 23:59:59.999999999 +0800 CST
}
```
### <span id="EndOfYear">EndOfYear</span>
<p>返回指定时间的年份结束时间</p>
<b>函数签名:</b>
```go
func EndOfYear(t time.Time) time.Time
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
bm := datetime.EndOfYear(td)
fmt.Println(bm) //2022-12-31 23:59:59.999999999 +0800 CST
}
```
### <span id="GetNowDate">GetNowDate</span>
<p>获取当天日期返回格式yyyy-mm-dd</p>
<b>函数签名:</b>
```go
func GetNowDate() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentDate := datetime.GetNowDate()
fmt.Println(currentDate) // 2022-01-28
}
```
### <span id="GetNowTime">GetNowTime</span>
<p>获取当时时间返回格式hh:mm:ss</p>
<b>函数签名:</b>
```go
func GetNowTime() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentTime := datetime.GetNowTime()
fmt.Println(currentDate) // 15:57:33
}
```
### <span id="GetNowDateTime">GetNowDateTime</span>
<p>获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss.</p>
<b>函数签名:</b>
```go
func GetNowDateTime() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
current := datetime.GetNowDateTime()
fmt.Println(current) // 2022-01-28 15:59:33
}
```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>获取零时时间戳(timestamp of 00:00).</p>
<b>函数签名:</b>
```go
func GetZeroHourTimestamp() int64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime) // 1643299200
}
```
### <span id="GetNightTimestamp">GetNightTimestamp</span>
<p>获取午夜时间戳(timestamp of 23:59).</p>
<b>函数签名:</b>
```go
func GetNightTimestamp() int64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime) // 1643385599
}
```
### <span id="FormatTimeToStr">FormatTimeToStr</span>
<p>将日期格式化成字符串,`format` 参数格式参考注<sup>1</sup></p>
<b>函数签名:</b>
```go
func FormatTimeToStr(t time.Time, format string) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
timeStr := datetime.FormatTimeToStr(now, "yyyy/mm/dd hh:mm:ss")
fmt.Println(timeStr) //2022/01/28 16:07:44
}
```
### <span id="FormatStrToTime">FormatStrToTime</span>
<p>将字符串格式化成时间,`format` 参数格式参考注<sup>1</sup></p>
<b>函数签名:</b>
```go
func FormatStrToTime(str, format string) (time.Time, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
time := datetime.FormatStrToTime("2006-01-02 15:04:05", "yyyy/mm/dd hh:mm:ss")
fmt.Println(time)
}
```
### <span id="NewUnixNow">NewUnixNow</span>
<p>创建一个当前时间的unix时间戳</p>
<b>函数签名:</b>
```go
type theTime struct {
unix int64
}
func NewUnixNow() *theTime
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnixNow()
fmt.Println(tm) //&{1647597438}
}
```
### <span id="NewUnix">NewUnix</span>
<p>创建一个unix时间戳</p>
<b>函数签名:</b>
```go
type theTime struct {
unix int64
}
func NewUnix(unix int64) *theTime
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnix(1647597438)
fmt.Println(tm) //&{1647597438}
}
```
### <span id="NewFormat">NewFormat</span>
<p>创建一个yyyy-mm-dd hh:mm:ss格式时间字符串的unix时间戳</p>
<b>函数签名:</b>
```go
type theTime struct {
unix int64
}
func NewFormat(t string) (*theTime, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, err := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm) //&{1647594245}
}
```
### <span id="NewISO8601">NewISO8601</span>
<p>创建一个iso8601格式时间字符串的unix时间戳</p>
<b>函数签名:</b>
```go
type theTime struct {
unix int64
}
func NewISO8601(iso8601 string) (*theTime, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
fmt.Println(tm) //&{1136214245}
}
```
### <span id="ToUnix">ToUnix</span>
<p>返回unix时间戳</p>
<b>函数签名:</b>
```go
func (t *theTime) ToUnix() int64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm := datetime.NewUnixNow()
fmt.Println(tm.ToUnix()) //1647597438
}
```
### <span id="ToFormat">ToFormat</span>
<p>返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串</p>
<b>函数签名:</b>
```go
func (t *theTime) ToFormat() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
fmt.Println(tm.ToFormat()) //"2022-03-18 17:04:05"
}
```
### <span id="ToFormatForTpl">ToFormatForTpl</span>
<p>返回tpl格式指定的日期字符串</p>
<b>函数签名:</b>
```go
func (t *theTime) ToFormatForTpl(tpl string) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
ts := tm.ToFormatForTpl("2006/01/02 15:04:05")
fmt.Println(ts) //"2022/03/18 17:04:05"
}
```
### <span id="ToIso8601">ToIso8601</span>
<p>返回iso8601日期字符串</p>
<b>函数签名:</b>
```go
func (t *theTime) ToIso8601() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
ts := tm.ToIso8601()
fmt.Println(ts) //"2006-01-02T23:04:05+08:00"
}
```

444
docs/fileutil.md Normal file
View File

@@ -0,0 +1,444 @@
# Fileutil
Package fileutil implements some basic functions for file operations.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/fileutil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ClearFile">ClearFile</span>
<p>Clear the file content, write empty string to the file.</p>
<b>Signature:</b>
```go
func ClearFile(path string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.ClearFile("./test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CreateFile">CreateFile</span>
<p>Create file in path. return true if create succeed.</p>
<b>Signature:</b>
```go
func CreateFile(path string) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isCreatedSucceed := fileutil.CreateFile("./test.txt")
fmt.Println(isCreatedSucceed)
}
```
### <span id="CopyFile">CopyFile</span>
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
<b>Signature:</b>
```go
func CopyFile(srcFilePath string, dstFilePath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="FileMode">FileMode</span>
<p>Return file mode infomation.</p>
<b>Signature:</b>
```go
func FileMode(path string) (fs.FileMode, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
### <span id="MiMeType">MiMeType</span>
<p>Get file mime type, 'file' param's type should be string or *os.File.</p>
<b>Signature:</b>
```go
func MiMeType(file any) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
type1 := fileutil.MiMeType("./test.txt")
fmt.Println(type1) //text/plain; charset=utf-8
f, _ := os.Open("./file.go")
type2 := fileutil.MiMeType(f)
fmt.Println(type2) //text/plain; charset=utf-8
}
```
### <span id="IsExist">IsExist</span>
<p>Checks if a file or directory exists.</p>
<b>Signature:</b>
```go
func IsExist(path string) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fileutil.CreateFile("./test.txt")
isFileExist := fileutil.IsExist("./test.txt")
fmt.Println(isFileExist) //true
}
```
### <span id="IsLink">IsLink</span>
<p>Checks if a file is symbol link or not.</p>
<b>Signature:</b>
```go
func IsLink(path string) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isLinkFile := fileutil.IsLink("./test.txt")
fmt.Println(isLinkFile) //false
}
```
### <span id="IsDir">IsDir</span>
<p>Checks if the path is directy or not.</p>
<b>Signature:</b>
```go
func IsDir(path string) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isDir := fileutil.IsDir("./")
fmt.Println(isDir) //true
isDir = fileutil.IsDir("./test.txt")
fmt.Println(isDir) //false
}
```
### <span id="ListFileNames">ListFileNames</span>
<p>List all file names in given path.</p>
<b>Signature:</b>
```go
func ListFileNames(path string) ([]string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fileNames, _ := fileutil.ListFileNames("./")
fmt.Println(fileNames)
}
```
### <span id="RemoveFile">RemoveFile</span>
<p>Remove the file of path.</p>
<b>Signature:</b>
```go
func RemoveFile(path string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="ReadFileToString">ReadFileToString</span>
<p>Return string of file content.</p>
<b>Signature:</b>
```go
func ReadFileToString(path string) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
### <span id="ReadFileByLine">ReadFileByLine</span>
<p>Read file line by line, and return slice of lines</p>
<b>Signature:</b>
```go
func ReadFileByLine(path string)([]string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
### <span id="Zip">Zip</span>
<p>Create a zip file of fpath, fpath could be a file or a directory.</p>
<b>Signature:</b>
```go
func Zip(fpath string, destPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span>
<p>Unzip the file and save it to dest path.</p>
<b>Signature:</b>
```go
func UnZip(zipFile string, destPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}
}
```

444
docs/fileutil_zh-CN.md Normal file
View File

@@ -0,0 +1,444 @@
# Fileutil
fileutil包支持文件基本操作。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/fileutil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ClearFile">ClearFile</span>
<p>清空文件内容</p>
<b>函数签名:</b>
```go
func ClearFile(path string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.ClearFile("./test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CreateFile">CreateFile</span>
<p>创建文件创建成功返回true, 否则返回false</p>
<b>函数签名:</b>
```go
func CreateFile(path string) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isCreatedSucceed := fileutil.CreateFile("./test.txt")
fmt.Println(isCreatedSucceed)
}
```
### <span id="CopyFile">CopyFile</span>
<p>拷贝文件,会覆盖原有的拷贝文件</p>
<b>函数签名:</b>
```go
func CopyFile(srcFilePath string, dstFilePath string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="FileMode">FileMode</span>
<p>获取文件mode信息</p>
<b>函数签名:</b>
```go
func FileMode(path string) (fs.FileMode, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
### <span id="MiMeType">MiMeType</span>
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
<b>函数签名:</b>
```go
func MiMeType(file any) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
type1 := fileutil.MiMeType("./test.txt")
fmt.Println(type1) //text/plain; charset=utf-8
f, _ := os.Open("./file.go")
type2 := fileutil.MiMeType(f)
fmt.Println(type2) //text/plain; charset=utf-8
}
```
### <span id="IsExist">IsExist</span>
<p>判断文件或目录是否存在</p>
<b>函数签名:</b>
```go
func IsExist(path string) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fileutil.CreateFile("./test.txt")
isFileExist := fileutil.IsExist("./test.txt")
fmt.Println(isFileExist) //true
}
```
### <span id="IsLink">IsLink</span>
<p>判断文件是否是符号链接</p>
<b>函数签名:</b>
```go
func IsLink(path string) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isLinkFile := fileutil.IsLink("./test.txt")
fmt.Println(isLinkFile) //false
}
```
### <span id="IsDir">IsDir</span>
<p>判断目录是否存在</p>
<b>函数签名:</b>
```go
func IsDir(path string) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
isDir := fileutil.IsDir("./")
fmt.Println(isDir) //true
isDir = fileutil.IsDir("./test.txt")
fmt.Println(isDir) //false
}
```
### <span id="ListFileNames">ListFileNames</span>
<p>返回目录下所有文件名</p>
<b>函数签名:</b>
```go
func ListFileNames(path string) ([]string, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
fileNames, _ := fileutil.ListFileNames("./")
fmt.Println(fileNames)
}
```
### <span id="RemoveFile">RemoveFile</span>
<p>删除文件</p>
<b>函数签名:</b>
```go
func RemoveFile(path string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="ReadFileToString">ReadFileToString</span>
<p>读取文件内容并返回字符串</p>
<b>函数签名:</b>
```go
func ReadFileToString(path string) (string, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
### <span id="ReadFileByLine">ReadFileByLine</span>
<p>按行读取文件内容,返回字符串切片包含每一行</p>
<b>函数签名:</b>
```go
func ReadFileByLine(path string)([]string, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
### <span id="Zip">Zip</span>
<p>zip压缩文件, fpath参数可以是文件或目录</p>
<b>函数签名:</b>
```go
func Zip(fpath string, destPath string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span>
<p>zip解压缩文件并保存在目录中</p>
<b>Signature:</b>
```go
func UnZip(zipFile string, destPath string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}
}
```

53
docs/formatter.md Normal file
View File

@@ -0,0 +1,53 @@
# Formatter
formatter contains some functions for data formatting.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/formatter"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Comma](#Comma)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Comma">Comma</span>
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
Param should be number or numberic string.</p>
<b>Signature:</b>
```go
func Comma(v any, symbol string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/formatter"
)
func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345"
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
```

52
docs/formatter_zh-CN.md Normal file
View File

@@ -0,0 +1,52 @@
# Formatter
formatter格式化器包含一些数据格式化处理方法。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/formatter"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Comma](#Comma)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Comma">Comma</span>
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
<b>函数签名:</b>
```go
func Comma(v any, symbol string) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/formatter"
)
func main() {
fmt.Println(formatter.Comma("12345", "")) // "12,345"
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
```

364
docs/function.md Normal file
View File

@@ -0,0 +1,364 @@
# Function
Package function can control the flow of function execution and support part of functional programming.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/function"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
- [Watcher](#Watcher)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="After">After</span>
<p>Creates a function that invokes given func once it's called n or more times.</p>
<b>Signature:</b>
```go
func After(n int, fn any) func(args ...any) []reflect.Value
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
arr := []string{"a", "b"}
f := function.After(len(arr), func(i int) int {
fmt.Println("last print")
return i
})
type cb func(args ...any) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("arr[%d] is %s \n", i, s)
fn(i)
}
fmt.Println("arr is", arr)
for i := 0; i < len(arr); i++ {
print(i, arr[i], f)
}
//output:
// arr is [a b]
// arr[0] is a
// arr[1] is b
// last print
}
```
### <span id="Before">Before</span>
<p>creates a function that invokes func once it's called less than n times.</p>
<b>Signature:</b>
```go
func Before(n int, fn any) func(args ...any) []reflect.Value
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
"github.com/duke-git/lancet/v2/internal"
)
func main() {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...any) []reflect.Value
appendStr := func(i int, s string, fn cb) {
v := fn(i)
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
}
```
### <span id="Curry">Curry</span>
<p>Make a curry function.</p>
<b>Signature:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
result := add1(2)
fmt.Println(result) //3
}
```
### <span id="Compose">Compose</span>
<p>Compose the function list from right to left, then return the composed function.</p>
<b>Signature:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
}
add2 := func(v ...any) any {
return v[0].(int) + 2
}
add3 := function.Compose(add1, add2)
result := add3(1)
fmt.Println(result) //4
}
```
### <span id="Debounced">Debounced</span>
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
<b>Signature:</b>
```go
func Debounced(fn func(), duration time.Duration) func()
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
add := func() {
count++
}
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
}
```
### <span id="Delay">Delay</span>
<p>Invoke function after delayed time.</p>
<b>Signature:</b>
```go
func Delay(delay time.Duration, fn any, args ...any)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var print = func(s string) {
fmt.Println(count) //test delay
}
function.Delay(2*time.Second, print, "test delay")
}
```
### <span id="Schedule">Schedule</span>
<p>Invoke function every duration time, until close the returned bool chan.</p>
<b>Signature:</b>
```go
func Schedule(d time.Duration, fn any, args ...any) chan bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var res []string
appendStr := func(s string) {
res = append(res, s)
}
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
fmt.Println(res) //[* * * * *]
}
```
### <span id="Watcher">Watcher</span>
<p>Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.</p>
<b>Signature:</b>
```go
type Watcher struct {
startTime int64
stopTime int64
excuting bool
}
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
w := &function.Watcher{}
w.Start()
longRunningTask()
fmt.Println(w.excuting) //true
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}
```

364
docs/function_zh-CN.md Normal file
View File

@@ -0,0 +1,364 @@
# Function
function函数包控制函数执行流程包含部分函数式编程。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/function"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
- [Watcher](#Watcher)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="After">After</span>
<p>创建一个函数当他被调用n或更多次之后将马上触发fn</p>
<b>函数签名:</b>
```go
func After(n int, fn any) func(args ...any) []reflect.Value
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
arr := []string{"a", "b"}
f := function.After(len(arr), func(i int) int {
fmt.Println("last print")
return i
})
type cb func(args ...any) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("arr[%d] is %s \n", i, s)
fn(i)
}
fmt.Println("arr is", arr)
for i := 0; i < len(arr); i++ {
print(i, arr[i], f)
}
//output:
// arr is [a b]
// arr[0] is a
// arr[1] is b
// last print
}
```
### <span id="Before">Before</span>
<p>创建一个函数调用次数不超过n次之后再调用这个函数将返回一次最后调用fn的结果</p>
<b>函数签名:</b>
```go
func Before(n int, fn any) func(args ...any) []reflect.Value
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
"github.com/duke-git/lancet/v2/internal"
)
func main() {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...any) []reflect.Value
appendStr := func(i int, s string, fn cb) {
v := fn(i)
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
}
```
### <span id="Curry">Curry</span>
<p>创建一个柯里化的函数</p>
<b>函数签名:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
result := add1(2)
fmt.Println(result) //3
}
```
### <span id="Compose">Compose</span>
<p>从右至左组合函数列表fnList 返回组合后的函数</p>
<b>函数签名:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
}
add2 := func(v ...any) any {
return v[0].(int) + 2
}
add3 := function.Compose(add1, add2)
result := add3(1)
fmt.Println(result) //4
}
```
### <span id="Debounced">Debounced</span>
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
<b>函数签名:</b>
```go
func Debounced(fn func(), duration time.Duration) func()
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
add := func() {
count++
}
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
}
```
### <span id="Delay">Delay</span>
<p>延迟delay时间后调用函数</p>
<b>函数签名:</b>
```go
func Delay(delay time.Duration, fn any, args ...any)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var print = func(s string) {
fmt.Println(count) //test delay
}
function.Delay(2*time.Second, print, "test delay")
}
```
### <span id="Schedule">Schedule</span>
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
<b>函数签名:</b>
```go
func Schedule(d time.Duration, fn any, args ...any) chan bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var res []string
appendStr := func(s string) {
res = append(res, s)
}
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
fmt.Println(res) //[* * * * *]
}
```
### <span id="Watcher">Watcher</span>
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
<b>函数签名:</b>
```go
type Watcher struct {
startTime int64
stopTime int64
excuting bool
}
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/function"
)
func main() {
w := &function.Watcher{}
w.Start()
longRunningTask()
fmt.Println(w.excuting) //true
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}
```

304
docs/maputil.md Normal file
View File

@@ -0,0 +1,304 @@
# Maputil
Package maputil includes some functions to manipulate map.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
<div STYLE="page-break-after: always;"></div>
## Example:
```go
import (
"github.com/duke-git/lancet/v2/maputil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ForEach](#ForEach)
- [Filter](#Filter)
- [Intersect](#Intersect)
- [Keys](#Keys)
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ForEach">ForEach</span>
<p>Executes iteratee funcation for every key and value pair in map.</p>
<b>Signature:</b>
```go
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
}
var sum int
maputil.ForEach(m, func(_ string, value int) {
sum += value
})
fmt.Println(sum) // 10
}
```
### <span id="Filter">Filter</span>
<p>Iterates over map, return a new map contains all key and value pairs pass the predicate function.</p>
<b>Signature:</b>
```go
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
maputil.Filter(m, func(_ string, value int) {
sum += value
})
res := maputil.Filter(m, isEven)
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
}
```
### <span id="Intersect">Intersect</span>
<p>Iterates over maps, return a new map of key and value pairs in all given maps.</p>
<b>Signature:</b>
```go
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 1,
"b": 2,
"c": 6,
"d": 7,
}
m3 := map[string]int{
"a": 1,
"b": 9,
"e": 9,
}
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
}
```
### <span id="Keys">Keys</span>
<p>Returns a slice of the map's keys.</p>
<b>Signature:</b>
```go
func Keys[K comparable, V any](m map[K]V) []K
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
keys := maputil.Keys(m)
sort.Ints(keys)
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
}
```
### <span id="Merge">Merge</span>
<p>Merge maps, next key will overwrite previous key.</p>
<b>Signature:</b>
```go
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[int]string{
1: "a",
2: "b",
}
m2 := map[int]string{
1: "1",
3: "2",
}
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
}
```
### <span id="Minus">Minus</span>
<p>Creates an map of whose key in mapA but not in mapB.</p>
<b>Signature:</b>
```go
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 11,
"b": 22,
"d": 33,
}
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
}
```
### <span id="Values">Values</span>
<p>Returns a slice of the map's values.</p>
<b>Signature:</b>
```go
func Values[K comparable, V any](m map[K]V) []V
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
values := maputil.Values(m)
sort.Strings(values)
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
}
```

304
docs/maputil_zh-CN.md Normal file
View File

@@ -0,0 +1,304 @@
# Maputil
maputil包包括一些操作map的函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/maputil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录:
- [ForEach](#ForEach)
- [Filter](#Filter)
- [Intersect](#Intersect)
- [Keys](#Keys)
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## API文档:
### <span id="ForEach">ForEach</span>
<p>对map中的每对key和value执行iteratee函数</p>
<b>函数签名:</b>
```go
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
}
var sum int
maputil.ForEach(m, func(_ string, value int) {
sum += value
})
fmt.Println(sum) // 10
}
```
### <span id="Filter">Filter</span>
<p>迭代map中的每对key和value, 返回符合predicate函数的key, value</p>
<b>函数签名:</b>
```go
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
maputil.Filter(m, func(_ string, value int) {
sum += value
})
res := maputil.Filter(m, isEven)
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
}
```
### <span id="Intersect">Intersect</span>
<p>多个map的交集操作</p>
<b>函数签名:</b>
```go
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 1,
"b": 2,
"c": 6,
"d": 7,
}
m3 := map[string]int{
"a": 1,
"b": 9,
"e": 9,
}
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
}
```
### <span id="Keys">Keys</span>
<p>返回map中所有key的切片</p>
<b>函数签名:</b>
```go
func Keys[K comparable, V any](m map[K]V) []K
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
keys := maputil.Keys(m)
sort.Ints(keys)
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
}
```
### <span id="Merge">Merge</span>
<p>合并多个maps, 相同的key会被后来的key覆盖</p>
<b>函数签名:</b>
```go
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[int]string{
1: "a",
2: "b",
}
m2 := map[int]string{
1: "1",
3: "2",
}
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
}
```
### <span id="Minus">Minus</span>
<p>返回一个map其中的key存在于mapA不存在于mapB.</p>
<b>函数签名:</b>
```go
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 11,
"b": 22,
"d": 33,
}
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
}
```
### <span id="Values">Values</span>
<p>返回map中所有value的切片</p>
<b>函数签名:</b>
```go
func Values[K comparable, V any](m map[K]V) []V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
values := maputil.Values(m)
sort.Strings(values)
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
}
```

400
docs/mathutil.md Normal file
View File

@@ -0,0 +1,400 @@
# Mathutil
Package mathutil implements some functions for math calculation.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
<div STYLE="page-break-after: always;"></div>
## Example:
```go
import (
"github.com/duke-git/lancet/v2/mathutil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Average](#Average)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Max](#Max)
- [MaxBy](#MaxBy)
- [Min](#Min)
- [MinBy](#MaxBy)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Average">Average</span>
<p>Return average value of numbers. Maybe call RoundToFloat to round result.</p>
<b>Signature:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Average(0, 0)) //0
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
}
```
### <span id="Exponent">Exponent</span>
<p>Calculate x to the nth power.</p>
<b>Signature:</b>
```go
func Exponent(x, n int64) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Exponent(10, 0)) //1
fmt.Println(mathutil.Exponent(10, 1)) //10
fmt.Println(mathutil.Exponent(10, 2)) //100
}
```
### <span id="Fibonacci">Fibonacci</span>
<p>Calculate the nth number of fibonacci sequence.</p>
<b>Signature:</b>
```go
func Fibonacci(first, second, n int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
}
```
### <span id="Factorial">Factorial</span>
<p>Calculate the factorial of x.</p>
<b>Signature:</b>
```go
func Factorial(x uint) uint
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Factorial(0)) //1
fmt.Println(mathutil.Factorial(1)) //1
fmt.Println(mathutil.Factorial(2)) //2
fmt.Println(mathutil.Factorial(3)) //6
}
```
### <span id="Max">Max</span>
<p>Return max value of numbers.</p>
<b>Signature:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Max(0, 0)) //0
fmt.Println(mathutil.Max(1, 2, 3)) //3
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
}
```
### <span id="MaxBy">MaxBy</span>
<p>Return the maximum value of a slice using the given comparator function.</p>
<b>Signature:</b>
```go
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res1) //abc
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res2) //abd
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res3) //“”
}
```
### <span id="Min">Min</span>
<p>Return min value of numbers.</p>
<b>Signature:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Min(0, 0)) //0
fmt.Println(mathutil.Min(1, 2, 3)) //1
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
}
```
### <span id="MinBy">MinBy</span>
<p>Return the minimum value of a slice using the given comparator function.</p>
<b>Signature:</b>
```go
func MinBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res1) //a
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res2) //ab
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res3) //“”
}
```
### <span id="Percent">Percent</span>
<p>calculate the percentage of val to total, retain n decimal places.</p>
<b>Signature:</b>
```go
func Percent(val, total float64, n int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
}
```
### <span id="RoundToFloat">RoundToFloat</span>
<p>Round float up to n decimal places.</p>
<b>Signature:</b>
```go
func RoundToFloat(x float64, n int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
}
```
### <span id="RoundToString">RoundToString</span>
<p>Round float up to n decimal places. will return string.</p>
<b>Signature:</b>
```go
func RoundToString(x float64, n int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
}
```
### <span id="TruncRound">TruncRound</span>
<p>Round float off n decimal places.</p>
<b>Signature:</b>
```go
func TruncRound(x float64, n int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.TruncRound(0, 0)) //0
fmt.Println(mathutil.TruncRound(0, 1)) //0
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
}
```

397
docs/mathutil_zh-CN.md Normal file
View File

@@ -0,0 +1,397 @@
# Mathutil
mathutil包实现了一些数学计算的函数.
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/mathutil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Average](#Average)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Max](#Max)
- [MaxBy](#MaxBy)
- [Min](#Min)
- [MinBy](#MaxBy)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Average">Average</span>
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
<b>函数签名:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Average(0, 0)) //0
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
}
```
### <span id="Exponent">Exponent</span>
<p>指数计算x的n次方</p>
<b>函数签名:</b>
```go
func Exponent(x, n int64) int64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Exponent(10, 0)) //1
fmt.Println(mathutil.Exponent(10, 1)) //10
fmt.Println(mathutil.Exponent(10, 2)) //100
}
```
### <span id="Fibonacci">Fibonacci</span>
<p>计算斐波那契数列的第n个数</p>
<b>函数签名:</b>
```go
func Fibonacci(first, second, n int) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
}
```
### <span id="Factorial">Factorial</span>
<p>计算阶乘</p>
<b>函数签名:</b>
```go
func Factorial(x uint) uint
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Factorial(0)) //1
fmt.Println(mathutil.Factorial(1)) //1
fmt.Println(mathutil.Factorial(2)) //2
fmt.Println(mathutil.Factorial(3)) //6
}
```
### <span id="Max">Max</span>
<p>返回参数中的最大数</p>
<b>函数签名:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Max(0, 0)) //0
fmt.Println(mathutil.Max(1, 2, 3)) //3
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
}
```
### <span id="MaxBy">MaxBy</span>
<p>使用给定的比较器函数返回切片的最大值</p>
<b>函数签名:</b>
```go
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res1) //abc
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res2) //abd
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(res3) //“”
}
```
### <span id="Min">Min</span>
<p>返回参数中的最小数</p>
<b>函数签名:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Min(0, 0)) //0
fmt.Println(mathutil.Min(1, 2, 3)) //1
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
}
```
### <span id="MinBy">MinBy</span>
<p>使用给定的比较器函数返回切片的最小值</p>
<b>函数签名:</b>
```go
func MinBy[T any](slice []T, comparator func(T, T) bool) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res1) //a
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res2) //ab
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(res3) //“”
}
```
### <span id="Percent">Percent</span>
<p>计算百分比保留n位小数</p>
<b>函数签名:</b>
```go
func Percent(val, total float64, n int) float64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
}
```
### <span id="RoundToFloat">RoundToFloat</span>
<p>四舍五入保留n位小数</p>
<b>函数签名:</b>
```go
func RoundToFloat(x float64, n int) float64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
}
```
### <span id="RoundToString">RoundToString</span>
<p>四舍五入保留n位小数返回字符串</p>
<b>函数签名:</b>
```go
func RoundToString(x float64, n int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
}
```
### <span id="TruncRound">TruncRound</span>
<p>截短n位小数不进行四舍五入</p>
<b>函数签名:</b>
```go
func TruncRound(x float64, n int) float64
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.TruncRound(0, 0)) //0
fmt.Println(mathutil.TruncRound(0, 1)) //0
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
}
```

511
docs/netutil.md Normal file
View File

@@ -0,0 +1,511 @@
# Netutil
Package netutil contains functions to get net information and send http request.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/netutil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ConvertMapToQueryString](#ConvertMapToQueryString)
- [GetInternalIp](#GetInternalIp)
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [IsPublicIP](#IsPublicIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span>
<p>Convert map to url query string.</p>
<b>Signature:</b>
```go
func ConvertMapToQueryString(param map[string]any) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
var m = map[string]any{
"c": 3,
"a": 1,
"b": 2,
}
qs := netutil.ConvertMapToQueryString(m)
fmt.Println(qs) //a=1&b=2&c=3
}
```
### <span id="GetInternalIp">GetInternalIp</span>
<p>Get internal ip information.</p>
<b>Signature:</b>
```go
func GetInternalIp() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
internalIp := netutil.GetInternalIp()
ip := net.ParseIP(internalIp)
fmt.Println(ip) //192.168.1.9
}
```
### <span id="GetIps">GetIps</span>
<p>Get all ipv4 list.</p>
<b>Signature:</b>
```go
func GetIps() []string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ips := netutil.GetIps()
fmt.Println(ips) //[192.168.1.9]
}
```
### <span id="GetMacAddrs">GetMacAddrs</span>
<p>Get all mac addresses list.</p>
<b>Signature:</b>
```go
func GetMacAddrs() []string {
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
addrs := netutil.GetMacAddrs()
fmt.Println(addrs)
}
```
### <span id="GetPublicIpInfo">GetPublicIpInfo</span>
<p>Get public ip information.</p>
<b>Signature:</b>
```go
func GetPublicIpInfo() (*PublicIpInfo, error)
type PublicIpInfo struct {
Status string `json:"status"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
Region string `json:"region"`
RegionName string `json:"regionName"`
City string `json:"city"`
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
Isp string `json:"isp"`
Org string `json:"org"`
As string `json:"as"`
Ip string `json:"query"`
}
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
publicIpInfo, err := netutil.GetPublicIpInfo()
if err != nil {
fmt.Println(err)
}
fmt.Println(publicIpInfo)
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>Checks if a ip is public or not.</p>
<b>Signature:</b>
```go
func IsPublicIP(IP net.IP) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("192.168.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsPublicIP(ip1)) //false
fmt.Println(netutil.IsPublicIP(ip2)) //true
}
```
### <span id="HttpGet">HttpGet</span>
<p>Send http get request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpGet(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := netutil.HttpGet(url, header)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPost">HttpPost</span>
<p>Send http post request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPost(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, "TestAddToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPut">HttpPut</span>
<p>Send http put request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPut(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, 1, "TestPutToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpDelete">HttpDelete</span>
<p>Send http delete request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpDelete(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
resp, err := netutil.HttpDelete(url)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPatch">HttpPatch</span>
<p>Send http patch request.</p>
<b>Signature:</b>
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPatch(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, 1, "TestPatchToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPatch(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="ParseHttpResponse">ParseHttpResponse</span>
<p>Decode http response to specified interface.</p>
<b>Signature:</b>
```go
func ParseHttpResponse(resp *http.Response, obj any) error
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := netutil.HttpGet(url, header)
if err != nil {
log.Fatal(err)
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
toDoResp := &Todo{}
err = netutil.ParseHttpResponse(resp, toDoResp)
if err != nil {
log.Fatal(err)
}
fmt.Println(toDoResp)
}
```

509
docs/netutil_zh-CN.md Normal file
View File

@@ -0,0 +1,509 @@
# Netutil
netutil网络包支持获取ip地址发送http请求。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/netutil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [ConvertMapToQueryString](#ConvertMapToQueryString)
- [GetInternalIp](#GetInternalIp)
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [IsPublicIP](#IsPublicIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ConvertMapToQueryString">ConvertMapToQueryString</span>
<p>将map转换成http查询字符串.</p>
<b>函数签名:</b>
```go
func ConvertMapToQueryString(param map[string]any) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
var m = map[string]any{
"c": 3,
"a": 1,
"b": 2,
}
qs := netutil.ConvertMapToQueryString(m)
fmt.Println(qs) //a=1&b=2&c=3
}
```
### <span id="GetInternalIp">GetInternalIp</span>
<p>获取内部ip</p>
<b>函数签名:</b>
```go
func GetInternalIp() string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
internalIp := netutil.GetInternalIp()
ip := net.ParseIP(internalIp)
fmt.Println(ip) //192.168.1.9
}
```
### <span id="GetIps">GetIps</span>
<p>获取ipv4地址列表</p>
<b>函数签名:</b>
```go
func GetIps() []string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ips := netutil.GetIps()
fmt.Println(ips) //[192.168.1.9]
}
```
### <span id="GetMacAddrs">GetMacAddrs</span>
<p>获取mac地址列</p>
<b>函数签名:</b>
```go
func GetMacAddrs() []string {
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
addrs := netutil.GetMacAddrs()
fmt.Println(addrs)
}
```
### <span id="GetPublicIpInfo">GetPublicIpInfo</span>
<p>获取公网ip信息</p>
<b>函数签名:</b>
```go
func GetPublicIpInfo() (*PublicIpInfo, error)
type PublicIpInfo struct {
Status string `json:"status"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
Region string `json:"region"`
RegionName string `json:"regionName"`
City string `json:"city"`
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
Isp string `json:"isp"`
Org string `json:"org"`
As string `json:"as"`
Ip string `json:"query"`
}
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
publicIpInfo, err := netutil.GetPublicIpInfo()
if err != nil {
fmt.Println(err)
}
fmt.Println(publicIpInfo)
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>判断ip是否是公共ip</p>
<b>函数签名:</b>
```go
func IsPublicIP(IP net.IP) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("192.168.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsPublicIP(ip1)) //false
fmt.Println(netutil.IsPublicIP(ip2)) //true
}
```
### <span id="HttpGet">HttpGet</span>
<p>发送http get请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpGet(url string, params ...any) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := netutil.HttpGet(url, header)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPost">HttpPost</span>
<p>发送http post请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPost(url string, params ...any) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, "TestAddToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPut">HttpPut</span>
<p>发送http put请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPut(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, 1, "TestPutToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpDelete">HttpDelete</span>
<p>发送http delete请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpDelete(url string, params ...any) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
resp, err := netutil.HttpDelete(url)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="HttpPatch">HttpPatch</span>
<p>发送http patch请求</p>
<b>函数签名:</b>
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPatch(url string, params ...any) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
}
todo := Todo{1, 1, "TestPatchToDo"}
bodyParams, _ := json.Marshal(todo)
resp, err := netutil.HttpPatch(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(body)
}
```
### <span id="ParseHttpResponse">ParseHttpResponse</span>
<p>将http请求响应解码成特定struct值</p>
<b>函数签名:</b>
```go
func ParseHttpResponse(resp *http.Response, obj any) error
```
<b>例子:</b>
```go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := netutil.HttpGet(url, header)
if err != nil {
log.Fatal(err)
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
toDoResp := &Todo{}
err = netutil.ParseHttpResponse(resp, toDoResp)
if err != nil {
log.Fatal(err)
}
fmt.Println(toDoResp)
}
```

138
docs/random.md Normal file
View File

@@ -0,0 +1,138 @@
# Random
Package random implements some basic functions to generate random int and string.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/random"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="RandBytes">RandBytes</span>
<p>Generate random byte slice.</p>
<b>Signature:</b>
```go
func RandBytes(length int) []byte
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
}
```
### <span id="RandInt">RandInt</span>
<p>Generate random int between min and max, may contain min, not max.</p>
<b>Signature:</b>
```go
func RandInt(min, max int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
}
```
### <span id="RandString">RandInt</span>
<p>Generate random given length string.</p>
<b>Signature:</b>
```go
func RandString(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
<b>Signature:</b>
```go
func UUIdV4() (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
uuid, err := random.UUIdV4()
if err != nil {
return
}
fmt.Println(uuid)
}
```

138
docs/random_zh-CN.md Normal file
View File

@@ -0,0 +1,138 @@
# Random
random随机数生成器包可以生成随机[]bytes, int, string。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/random"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="RandBytes">RandBytes</span>
<p>生成随机字节切片</p>
<b>函数签名:</b>
```go
func RandBytes(length int) []byte
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
}
```
### <span id="RandInt">RandInt</span>
<p>生成随机int, 范围[min, max)</p>
<b>函数签名:</b>
```go
func RandInt(min, max int) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
}
```
### <span id="RandString">RandInt</span>
<p>生成随机给定长度的随机字符串</p>
<b>函数签名:</b>
```go
func RandString(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr)
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>生成UUID v4字符串</p>
<b>函数签名:</b>
```go
func UUIdV4() (string, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
uuid, err := random.UUIdV4()
if err != nil {
return
}
fmt.Println(uuid)
}
```

236
docs/retry.md Normal file
View File

@@ -0,0 +1,236 @@
# Retry
Package retry is for executing a function repeatedly until it was successful or canceled by the context.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/retry"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Context](#Context)
- [Retry](#Retry)
- [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Context">Context</span>
<p>Set retry context config, can cancel the retry with context.</p>
<b>Signature:</b>
```go
func Context(ctx context.Context)
```
<b>Example:</b>
```go
import (
"context"
"errors"
"fmt"
"github.com/duke-git/lancet/v2/retry"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.TODO())
var number int
increaseNumber := func() error {
number++
if number > 3 {
cancel()
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber,
retry.RetryDuration(time.Microsecond*50),
retry.Context(ctx),
)
if err != nil {
fmt.Println(err) //retry is cancelled
}
}
```
### <span id="RetryFunc">RetryFunc</span>
<p>Function that retry executes.</p>
<b>Signature:</b>
```go
type RetryFunc func() error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
var increaseNumber retry.RetryFunc
increaseNumber = func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="RetryTimes">RetryTimes</span>
<p>Set times of retry. Default times is 5.</p>
<b>Signature:</b>
```go
func RetryTimes(n uint)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
if err != nil {
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
}
}
```
### <span id="RetryDuration">RetryDuration</span>
<p>Set duration of retries. Default duration is 3 second.</p>
<b>Signature:</b>
```go
func RetryDuration(d time.Duration)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="Retry">Retry</span>
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
<b>Signature:</b>
```go
func Retry(retryFunc RetryFunc, opts ...Option) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```

238
docs/retry_zh-CN.md Normal file
View File

@@ -0,0 +1,238 @@
# Retry
retry重试执行函数直到函数运行成功或被context cancel。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/retry"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Context](#Context)
- [Retry](#Retry)
- [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes)
<div STYLE="page-break-after: always;"></div>
## Document文档
### <span id="Context">Context</span>
<p>设置重试context参数</p>
<b>函数签名:</b>
```go
func Context(ctx context.Context)
```
<b>例子:</b>
```go
import (
"context"
"errors"
"fmt"
"lancet-demo/retry"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.TODO())
var number int
increaseNumber := func() error {
number++
if number > 3 {
cancel()
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber,
retry.RetryDuration(time.Microsecond*50),
retry.Context(ctx),
)
if err != nil {
fmt.Println(err) //retry is cancelled
}
}
```
### <span id="RetryFunc">RetryFunc</span>
<p>被重试执行的函数</p>
<b>函数签名:</b>
```go
type RetryFunc func() error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
var increaseNumber retry.RetryFunc
increaseNumber = func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="RetryTimes">RetryTimes</span>
<p>设置重试次数默认5</p>
<b>函数签名:</b>
```go
func RetryTimes(n uint)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
if err != nil {
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
}
}
```
### <span id="RetryDuration">RetryDuration</span>
<p>设置重试间隔时间默认3秒</p>
<b>函数签名:</b>
```go
func RetryDuration(d time.Duration)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="Retry">Retry</span>
<p>重试执行函数retryFunc直到函数运行成功或被context停止</p>
<b>函数签名:</b>
```go
func Retry(retryFunc RetryFunc, opts ...Option) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/v2/retry"
)
func main() {
var number int
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
fmt.Println(number) //3
}
```

1110
docs/slice.md Normal file

File diff suppressed because it is too large Load Diff

1108
docs/slice_zh-CN.md Normal file

File diff suppressed because it is too large Load Diff

612
docs/strutil.md Normal file
View File

@@ -0,0 +1,612 @@
# Strutil
Package strutil contains some functions to manipulate string.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/strutil/string.go](https://github.com/duke-git/lancet/blob/main/strutil/string.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/strutil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [After](#After)
- [AfterLast](#AfterLast)
- [Before](#Before)
- [BeforeLast](#BeforeLast)
- [CamelCase](#CamelCase)
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [SnakeCase](#SnakeCase)
- [SplitEx](#SplitEx)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="After">After</span>
<p>Creates substring in source string after position when char first appear.</p>
<b>Signature:</b>
```go
func After(s, char string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.After("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.After("github.com/test/lancet", "/")
fmt.Println(s2) //test/lancet
s3 := strutil.After("github.com/test/lancet", "test")
fmt.Println(s3) // /lancet
}
```
### <span id="AfterLast">AfterLast</span>
<p>Creates substring in source string after position when char last appear.</p>
<b>Signature:</b>
```go
func AfterLast(s, char string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.AfterLast("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.AfterLast("github.com/test/lancet", "/")
fmt.Println(s2) //lancet
s3 := strutil.AfterLast("github.com/test/test/lancet", "test")
fmt.Println(s3) // /test/lancet
}
```
### <span id="Before">Before</span>
<p>Creates substring in source string before position when char first appear.</p>
<b>Signature:</b>
```go
func Before(s, char string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Before("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.Before("github.com/test/lancet", "/")
fmt.Println(s2) //github.com
s3 := strutil.Before("github.com/test/lancet", "test")
fmt.Println(s3) // github.com/
}
```
### <span id="BeforeLast">BeforeLast</span>
<p>Creates substring in source string before position when char first appear.</p>
<b>Signature:</b>
```go
func BeforeLast(s, char string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.BeforeLast("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.BeforeLast("github.com/test/lancet", "/")
fmt.Println(s2) //github.com/test
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test")
fmt.Println(s3) //github.com/test/
}
```
### <span id="CamelCase">CamelCase</span>
<p>Covert string to camelCase string.</p>
<b>Signature:</b>
```go
func CamelCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.CamelCase("foo_bar")
fmt.Println(s1) //fooBar
s2 := strutil.CamelCase("Foo-Bar")
fmt.Println(s2) //fooBar
s3 := strutil.CamelCase("Foo&bar")
fmt.Println(s3) //fooBar
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
}
```
### <span id="Capitalize">Capitalize</span>
<p>Convert the first character of a string to upper case.</p>
<b>Signature:</b>
```go
func Capitalize(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Capitalize("foo")
fmt.Println(s1) //foo
s2 := strutil.Capitalize("Foo")
fmt.Println(s2) //foo
s3 := strutil.Capitalize("FOo"
fmt.Println(s3) //fOo
}
```
### <span id="IsString">IsString</span>
<p>Check if the value's data type is string.</p>
<b>Signature:</b>
```go
func IsString(v any) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
fmt.Println(strutil.IsString("lancet")) //true
fmt.Println(strutil.IsString("")) //true
fmt.Println(strutil.IsString(1)) //false
fmt.Println(strutil.IsString("")) //false
fmt.Println(strutil.IsString([]string{})) //false
}
```
### <span id="KebabCase">KebabCase</span>
<p>Covert string to kebab-case.</p>
<b>Signature:</b>
```go
func KebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.KebabCase("Foo Bar-")
fmt.Println(s1) //foo-bar
s2 := strutil.KebabCase("foo_Bar")
fmt.Println(s2) //foo-bar
s3 := strutil.KebabCase("fooBar")
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
}
```
### <span id="LowerFirst">LowerFirst</span>
<p>Convert the first character of string to lower case.</p>
<b>Signature:</b>
```go
func LowerFirst(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.LowerFirst("foo")
fmt.Println(s1) //foo
s2 := strutil.LowerFirst("BAR")
fmt.Println(s2) //bAR
s3 := strutil.LowerFirst("FOo")
fmt.Println(s3) //fOo
s4 := strutil.LowerFirst("fOo大")
fmt.Println(s4) //fOo大
}
```
### <span id="UpperFirst">UpperFirst</span>
<p>Convert the first character of string to upper case.</p>
<b>Signature:</b>
```go
func UpperFirst(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperFirst("foo")
fmt.Println(s1) //Foo
s2 := strutil.UpperFirst("bAR")
fmt.Println(s2) //BAR
s3 := strutil.UpperFirst("FOo")
fmt.Println(s3) //FOo
s4 := strutil.UpperFirst("fOo大")
fmt.Println(s4) //FOo大
}
```
### <span id="PadEnd">PadEnd</span>
<p>Pads string on the right side if it's shorter than size.</p>
<b>Signature:</b>
```go
func PadEnd(source string, size int, padStr string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.PadEnd("a", 1, "b")
fmt.Println(s1) //a
s2 := strutil.PadEnd("a", 2, "b")
fmt.Println(s2) //ab
s3 := strutil.PadEnd("abcd", 6, "mno")
fmt.Println(s3) //abcdmn
s4 := strutil.PadEnd("abc", 6, "ab")
fmt.Println(s4) //abcaba
}
```
### <span id="PadStart">PadStart</span>
<p>Pads string on the left side if it's shorter than size.</p>
<b>Signature:</b>
```go
func PadStart(source string, size int, padStr string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.PadStart("a", 1, "b")
fmt.Println(s1) //a
s2 := strutil.PadStart("a", 2, "b")
fmt.Println(s2) //ba
s3 := strutil.PadStart("abcd", 6, "mno")
fmt.Println(s3) //mnabcd
s4 := strutil.PadStart("abc", 6, "ab")
fmt.Println(s4) //abaabc
}
```
### <span id="ReverseStr">ReverseStr</span>
<p>Return string whose char order is reversed to the given string.</p>
<b>Signature:</b>
```go
func ReverseStr(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.ReverseStr("abc")
fmt.Println(s1) //cba
s2 := strutil.ReverseStr("12345")
fmt.Println(s2) //54321
}
```
### <span id="SnakeCase">SnakeCase</span>
<p>Covert string to snake_case.</p>
<b>Signature:</b>
```go
func SnakeCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.SnakeCase("Foo Bar-")
fmt.Println(s1) //foo_bar
s2 := strutil.SnakeCase("foo_Bar")
fmt.Println(s2) //foo_bar
s3 := strutil.SnakeCase("fooBar")
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
}
```
### <span id="SplitEx">SplitEx</span>
<p>Split a given string whether the result contains empty string.</p>
<b>Signature:</b>
```go
func SplitEx(s, sep string, removeEmptyString bool) []string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
arr1 := strutil.SplitEx(" a b c ", "", true)
fmt.Println(arr1) //[]string{}
arr2 := strutil.SplitEx(" a b c ", " ", false)
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
arr3 := strutil.SplitEx(" a b c ", " ", true)
fmt.Println(arr3) //[]string{"a", "b", "c"}
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
fmt.Println(arr5) //[]string{" a", "b", "c"}
}
```
### <span id="Wrap">Wrap</span>
<p>Wrap a string with another string.</p>
<b>Signature:</b>
```go
func Wrap(str string, wrapWith string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Wrap("ab", "")
fmt.Println(s1) //ab
s2 := strutil.Wrap("", "*")
fmt.Println(s2) //""
s3 := strutil.Wrap("ab", "*")
fmt.Println(s3) //*ab*
s4 := strutil.Wrap("ab", "\"")
fmt.Println(s4) //\"ab\"
s5 := strutil.Wrap("ab", "'")
fmt.Println(s5) //'ab'
}
```
### <span id="Wrap">Wrap</span>
<p>Unwrap a given string from anther string. will change str value.</p>
<b>Signature:</b>
```go
func Unwrap(str string, wrapToken string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Unwrap("ab", "")
fmt.Println(s1) //ab
s2 := strutil.Unwrap("ab", "*")
fmt.Println(s2) //ab
s3 := strutil.Unwrap("**ab**", "*")
fmt.Println(s3) //*ab*
s4 := strutil.Unwrap("*ab", "*")
fmt.Println(s4) //*ab
s5 := strutil.Unwrap("***", "**")
fmt.Println(s5) //***
}
```

611
docs/strutil_zh-CN.md Normal file
View File

@@ -0,0 +1,611 @@
# Strutil
strutil包含处理字符串的相关函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/strutil/string.go](https://github.com/duke-git/lancet/blob/main/strutil/string.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/strutil"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [After](#After)
- [AfterLast](#AfterLast)
- [Before](#Before)
- [BeforeLast](#BeforeLast)
- [CamelCase](#CamelCase)
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [SnakeCase](#SnakeCase)
- [SplitEx](#SplitEx)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
<div STYLE="page-break-after: always;"></div>
## Documentation文档
### <span id="After">After</span>
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
<b>函数签名:</b>
```go
func After(s, char string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.After("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.After("github.com/test/lancet", "/")
fmt.Println(s2) //test/lancet
s3 := strutil.After("github.com/test/lancet", "test")
fmt.Println(s3) // /lancet
}
```
### <span id="AfterLast">AfterLast</span>
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
<b>函数签名:</b>
```go
func AfterLast(s, char string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.AfterLast("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.AfterLast("github.com/test/lancet", "/")
fmt.Println(s2) //lancet
s3 := strutil.AfterLast("github.com/test/test/lancet", "test")
fmt.Println(s3) // /lancet
}
```
### <span id="Before">Before</span>
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
<b>函数签名:</b>
```go
func Before(s, char string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Before("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.Before("github.com/test/lancet", "/")
fmt.Println(s2) //github.com
s3 := strutil.Before("github.com/test/lancet", "test")
fmt.Println(s3) // github.com/
}
```
### <span id="BeforeLast">BeforeLast</span>
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
<b>函数签名:</b>
```go
func BeforeLast(s, char string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.BeforeLast("lancet", "")
fmt.Println(s1) //lancet
s2 := strutil.BeforeLast("github.com/test/lancet", "/")
fmt.Println(s2) //github.com/test
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test")
fmt.Println(s3) //github.com/test/
}
```
### <span id="CamelCase">CamelCase</span>
<p>将字符串转换为驼峰式字符串</p>
<b>函数签名:</b>
```go
func CamelCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.CamelCase("foo_bar")
fmt.Println(s1) //fooBar
s2 := strutil.CamelCase("Foo-Bar")
fmt.Println(s2) //fooBar
s3 := strutil.CamelCase("Foo&bar")
fmt.Println(s3) //fooBar
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
}
```
### <span id="Capitalize">Capitalize</span>
<p>将字符串的第一个字符转换为大写</p>
<b>函数签名:</b>
```go
func Capitalize(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Capitalize("foo")
fmt.Println(s1) //foo
s2 := strutil.Capitalize("Foo")
fmt.Println(s2) //foo
s3 := strutil.Capitalize("FOo"
fmt.Println(s3) //fOo
}
```
### <span id="IsString">IsString</span>
<p>检查值的数据类型是否为字符串</p>
<b>函数签名:</b>
```go
func IsString(v any) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
fmt.Println(strutil.IsString("lancet")) //true
fmt.Println(strutil.IsString("")) //true
fmt.Println(strutil.IsString(1)) //false
fmt.Println(strutil.IsString("")) //false
fmt.Println(strutil.IsString([]string{})) //false
}
```
### <span id="KebabCase">KebabCase</span>
<p>将字符串转换为kebab-case</p>
<b>函数签名:</b>
```go
func KebabCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.KebabCase("Foo Bar-")
fmt.Println(s1) //foo-bar
s2 := strutil.KebabCase("foo_Bar")
fmt.Println(s2) //foo-bar
s3 := strutil.KebabCase("fooBar")
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
}
```
### <span id="LowerFirst">LowerFirst</span>
<p>将字符串的第一个字符转换为小写</p>
<b>函数签名:</b>
```go
func LowerFirst(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.LowerFirst("foo")
fmt.Println(s1) //foo
s2 := strutil.LowerFirst("BAR")
fmt.Println(s2) //bAR
s3 := strutil.LowerFirst("FOo")
fmt.Println(s3) //fOo
s4 := strutil.LowerFirst("fOo大")
fmt.Println(s4) //fOo大
}
```
### <span id="UpperFirst">UpperFirst</span>
<p>将字符串的第一个字符转换为大写</p>
<b>函数签名:</b>
```go
func UpperFirst(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperFirst("foo")
fmt.Println(s1) //Foo
s2 := strutil.UpperFirst("bAR")
fmt.Println(s2) //BAR
s3 := strutil.UpperFirst("FOo")
fmt.Println(s3) //FOo
s4 := strutil.UpperFirst("fOo大")
fmt.Println(s4) //FOo大
}
```
### <span id="PadEnd">PadEnd</span>
<p>如果字符串长度短于size则在右侧填充字符串</p>
<b>函数签名:</b>
```go
func PadEnd(source string, size int, padStr string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.PadEnd("a", 1, "b")
fmt.Println(s1) //a
s2 := strutil.PadEnd("a", 2, "b")
fmt.Println(s2) //ab
s3 := strutil.PadEnd("abcd", 6, "mno")
fmt.Println(s3) //abcdmn
s4 := strutil.PadEnd("abc", 6, "ab")
fmt.Println(s4) //abcaba
}
```
### <span id="PadStart">PadStart</span>
<p>如果字符串长度短于size则在左侧填充字符串</p>
<b>函数签名:</b>
```go
func PadStart(source string, size int, padStr string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.PadStart("a", 1, "b")
fmt.Println(s1) //a
s2 := strutil.PadStart("a", 2, "b")
fmt.Println(s2) //ba
s3 := strutil.PadStart("abcd", 6, "mno")
fmt.Println(s3) //mnabcd
s4 := strutil.PadStart("abc", 6, "ab")
fmt.Println(s4) //abaabc
}
```
### <span id="ReverseStr">ReverseStr</span>
<p>返回字符顺序与给定字符串相反的字符串</p>
<b>函数签名:</b>
```go
func ReverseStr(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.ReverseStr("abc")
fmt.Println(s1) //cba
s2 := strutil.ReverseStr("12345")
fmt.Println(s2) //54321
}
```
### <span id="SnakeCase">SnakeCase</span>
<p>将字符串转换为snake_case形式</p>
<b>函数签名:</b>
```go
func SnakeCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.SnakeCase("Foo Bar-")
fmt.Println(s1) //foo_bar
s2 := strutil.SnakeCase("foo_Bar")
fmt.Println(s2) //foo_bar
s3 := strutil.SnakeCase("fooBar")
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
}
```
### <span id="SplitEx">SplitEx</span>
<p>分割字符串为切片removeEmptyString参数指定是否去除空字符串</p>
<b>函数签名:</b>
```go
func SplitEx(s, sep string, removeEmptyString bool) []string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
arr1 := strutil.SplitEx(" a b c ", "", true)
fmt.Println(arr1) //[]string{}
arr2 := strutil.SplitEx(" a b c ", " ", false)
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
arr3 := strutil.SplitEx(" a b c ", " ", true)
fmt.Println(arr3) //[]string{"a", "b", "c"}
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
fmt.Println(arr5) //[]string{" a", "b", "c"}
}
```
### <span id="Wrap">Wrap</span>
<p>用另一个字符串包裹一个字符串</p>
<b>函数签名:</b>
```go
func Wrap(str string, wrapWith string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Wrap("ab", "")
fmt.Println(s1) //ab
s2 := strutil.Wrap("", "*")
fmt.Println(s2) //""
s3 := strutil.Wrap("ab", "*")
fmt.Println(s3) //*ab*
s4 := strutil.Wrap("ab", "\"")
fmt.Println(s4) //\"ab\"
s5 := strutil.Wrap("ab", "'")
fmt.Println(s5) //'ab'
}
```
### <span id="Unwrap">Unwrap</span>
<p>用另一个字符串解开包裹一个字符串</p>
<b>函数签名:</b>
```go
func Unwrap(str string, wrapToken string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Unwrap("ab", "")
fmt.Println(s1) //ab
s2 := strutil.Unwrap("ab", "*")
fmt.Println(s2) //ab
s3 := strutil.Unwrap("**ab**", "*")
fmt.Println(s3) //*ab*
s4 := strutil.Unwrap("*ab", "*")
fmt.Println(s4) //*ab
s5 := strutil.Unwrap("***", "**")
fmt.Println(s5) //***
}
```

242
docs/system.md Normal file
View File

@@ -0,0 +1,242 @@
# System
Package system contains some functions about os, runtime, shell command.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/system"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [IsWindows](#IsWindows)
- [IsLinux](#IsLinux)
- [IsMac](#IsMac)
- [GetOsEnv](#GetOsEnv)
- [SetOsEnv](#SetOsEnv)
- [RemoveOsEnv](#RemoveOsEnv)
- [CompareOsEnv](#CompareOsEnv)
- [ExecCommand](#ExecCommand)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="IsWindows">IsWindows</span>
<p>Check if current os is windows.</p>
<b>Signature:</b>
```go
func IsWindows() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
}
```
### <span id="IsLinux">IsLinux</span>
<p>Check if current os is linux.</p>
<b>Signature:</b>
```go
func IsLinux() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
}
```
### <span id="IsMac">IsMac</span>
<p>Check if current os is macos.</p>
<b>Signature:</b>
```go
func IsMac() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsMac := system.IsMac
fmt.Println(isOsMac)
}
```
### <span id="GetOsEnv">GetOsEnv</span>
<p>Gets the value of the environment variable named by the key.</p>
<b>Signature:</b>
```go
func GetOsEnv(key string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
}
```
### <span id="SetOsEnv">SetOsEnv</span>
<p>Sets the value of the environment variable named by the key.</p>
<b>Signature:</b>
```go
func SetOsEnv(key, value string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
}
```
### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>Remove a single environment variable.</p>
<b>Signature:</b>
```go
func RemoveOsEnv(key string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CompareOsEnv">CompareOsEnv</span>
<p>Get env named by the key and compare it with comparedEnv.</p>
<b>Signature:</b>
```go
func CompareOsEnv(key, comparedEnv string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
system.SetOsEnv("foo", "foo_value")
res := system.CompareOsEnv("foo", "foo_value")
fmt.Println(res) //true
}
```
### <span id="ExecCommand">CompareOsEnv</span>
<p>use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
<b>Signature:</b>
```go
func ExecCommand(command string) (stdout, stderr string, err error)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
}
```

242
docs/system_zh-CN.md Normal file
View File

@@ -0,0 +1,242 @@
# System
system包含os, runtime, shell command相关函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/system"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [IsWindows](#IsWindows)
- [IsLinux](#IsLinux)
- [IsMac](#IsMac)
- [GetOsEnv](#GetOsEnv)
- [SetOsEnv](#SetOsEnv)
- [RemoveOsEnv](#RemoveOsEnv)
- [CompareOsEnv](#CompareOsEnv)
- [ExecCommand](#ExecCommand)
<div STYLE="page-break-after: always;"></div>
## Documentation文档
### <span id="IsWindows">IsWindows</span>
<p>检查当前操作系统是否是windows</p>
<b>Signature:</b>
```go
func IsWindows() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
}
```
### <span id="IsLinux">IsLinux</span>
<p>检查当前操作系统是否是linux</p>
<b>Signature:</b>
```go
func IsLinux() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
}
```
### <span id="IsMac">IsMac</span>
<p>检查当前操作系统是否是macos</p>
<b>Signature:</b>
```go
func IsMac() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsMac := system.IsMac
fmt.Println(isOsMac)
}
```
### <span id="GetOsEnv">GetOsEnv</span>
<p>获取key命名的环境变量的值</p>
<b>Signature:</b>
```go
func GetOsEnv(key string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
}
```
### <span id="SetOsEnv">SetOsEnv</span>
<p>设置由key命名的环境变量的值</p>
<b>Signature:</b>
```go
func SetOsEnv(key, value string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
}
```
### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>删除单个环境变量</p>
<b>Signature:</b>
```go
func RemoveOsEnv(key string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CompareOsEnv">CompareOsEnv</span>
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
<b>Signature:</b>
```go
func CompareOsEnv(key, comparedEnv string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
system.SetOsEnv("foo", "foo_value")
res := system.CompareOsEnv("foo", "foo_value")
fmt.Println(res) //true
}
```
### <span id="ExecCommand">ExecCommand</span>
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
<b>Signature:</b>
```go
func ExecCommand(command string) (stdout, stderr string, err error)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
}
```

799
docs/validator.md Normal file
View File

@@ -0,0 +1,799 @@
# Validator
Package validator contains some functions for data validation.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/validator/validator.go](https://github.com/duke-git/lancet/blob/main/validator/validator.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/validator"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [ContainChinese](#ContainChinese)
- [ContainLetter](#ContainLetter)
- [ContainLower](#ContainLower)
- [ContainUpper](#ContainUpper)
- [IsAlpha](#IsAlpha)
- [IsAllUpper](#IsAllUpper)
- [IsAllLower](#IsAllLower)
- [IsBase64](#IsBase64)
- [IsChineseMobile](#IsChineseMobile)
- [IsChineseIdNum](#IsChineseIdNum)
- [IsChinesePhone](#IsChinesePhone)
- [IsCreditCard](#IsCreditCard)
- [IsDns](#IsDns)
- [IsEmail](#IsEmail)
- [IsEmptyString](#IsEmptyString)
- [IsFloatStr](#IsFloatStr)
- [IsNumberStr](#IsNumberStr)
- [IsJSON](#IsJSON)
- [IsRegexMatch](#IsRegexMatch)
- [IsIntStr](#IsIntStr)
- [IsIp](#IsIp)
- [IsIpV4](#IsIpV4)
- [IsIpV6](#IsIpV6)
- [IsStrongPassword](#IsStrongPassword)
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ContainChinese">ContainChinese</span>
<p>Check if the string contain mandarin chinese.</p>
<b>Signature:</b>
```go
func ContainChinese(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainChinese("你好")
fmt.Println(res1) //true
res2 := validator.ContainChinese("你好hello")
fmt.Println(res2) //true
res3 := validator.ContainChinese("hello")
fmt.Println(res3) //false
}
```
### <span id="ContainLetter">ContainLetter</span>
<p>Check if the string contain at least one letter.</p>
<b>Signature:</b>
```go
func ContainLetter(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainLetter("1bc")
fmt.Println(res1) //true
res2 := validator.ContainLetter("123")
fmt.Println(res2) //false
res3 := validator.ContainLetter("&@#$%^&*")
fmt.Println(res3) //false
}
```
### <span id="ContainLower">ContainLower</span>
<p>Check if the string contain at least one lower case letter a-z.</p>
<b>Signature:</b>
```go
func ContainLower(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainLower("1bc")
fmt.Println(res1) //true
res2 := validator.ContainLower("123")
fmt.Println(res2) //false
res3 := validator.ContainLower("1BC")
fmt.Println(res3) //false
}
```
### <span id="ContainUpper">ContainUpper</span>
<p>Check if the string contain at least one upper case letter A-Z.</p>
<b>Signature:</b>
```go
func ContainUpper(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainUpper("1bc")
fmt.Println(res1) //false
res2 := validator.ContainUpper("123")
fmt.Println(res2) //false
res3 := validator.ContainUpper("1BC")
fmt.Println(res3) //true
}
```
### <span id="IsAlpha">IsAlpha</span>
<p>Check if the string contains only letters (a-zA-Z).</p>
<b>Signature:</b>
```go
func IsAlpha(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAlpha("abc")
fmt.Println(res1) //true
res2 := validator.IsAlpha("1bc")
fmt.Println(res2) //false
res3 := validator.IsAlpha("")
fmt.Println(res3) //false
}
```
### <span id="IsAllUpper">IsAllUpper</span>
<p>Check if string is all upper case letters A-Z.</p>
<b>Signature:</b>
```go
func IsAllUpper(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAllUpper("ABC")
fmt.Println(res1) //true
res2 := validator.IsAllUpper("aBC")
fmt.Println(res2) //false
}
```
### <span id="IsAllLower">IsAllLower</span>
<p>Check if string is all lower case letters a-z.</p>
<b>Signature:</b>
```go
func IsAllLower(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAllLower("abc")
fmt.Println(res1) //true
res2 := validator.IsAllLower("abC")
fmt.Println(res2) //false
}
```
### <span id="IsBase64">IsBase64</span>
<p>Check if the string is base64 string.</p>
<b>Signature:</b>
```go
func IsBase64(base64 string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsBase64("aGVsbG8=")
fmt.Println(res1) //true
res2 := validator.IsBase64("123456")
fmt.Println(res2) //false
}
```
### <span id="IsChineseMobile">IsChineseMobile</span>
<p>Check if the string is valid chinese mobile number.</p>
<b>Signature:</b>
```go
func IsChineseMobile(mobileNum string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChineseMobile("13263527980")
fmt.Println(res1) //true
res2 := validator.IsChineseMobile("434324324")
fmt.Println(res2) //false
}
```
### <span id="IsChineseIdNum">IsChineseIdNum</span>
<p>Check if the string is chinese id number.</p>
<b>Signature:</b>
```go
func IsChineseIdNum(id string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChineseIdNum("210911192105130715")
fmt.Println(res1) //true
res2 := validator.IsChineseIdNum("123456")
fmt.Println(res2) //false
}
```
### <span id="IsChinesePhone">IsChinesePhone</span>
<p>Check if the string is chinese phone number.</p>
<b>Signature:</b>
```go
func IsChinesePhone(phone string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChinesePhone("010-32116675")
fmt.Println(res1) //true
res2 := validator.IsChinesePhone("123-87562")
fmt.Println(res2) //false
}
```
### <span id="IsCreditCard">IsCreditCard</span>
<p>Check if the string is credit card.</p>
<b>Signature:</b>
```go
func IsCreditCard(creditCart string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsCreditCard("4111111111111111")
fmt.Println(res1) //true
res2 := validator.IsCreditCard("123456")
fmt.Println(res2) //false
}
```
### <span id="IsDns">IsDns</span>
<p>Check if the string is valid dns.</p>
<b>Signature:</b>
```go
func IsDns(dns string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsDns("abc.com")
fmt.Println(res1) //true
res2 := validator.IsDns("a.b.com")
fmt.Println(res2) //false
res3 := validator.IsDns("http://abc.com")
fmt.Println(res3) //false
}
```
### <span id="IsEmail">IsEmail</span>
<p>Check if the string is email address.</p>
<b>Signature:</b>
```go
func IsEmail(email string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsEmail("abc@xyz.com")
fmt.Println(res1) //true
res2 := validator.IsEmail("a.b@@com")
fmt.Println(res2) //false
}
```
### <span id="IsEmptyString">IsEmptyString</span>
<p>Check if the string is empty or not.</p>
<b>Signature:</b>
```go
func IsEmptyString(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsEmptyString("")
fmt.Println(res1) //true
res2 := validator.IsEmptyString("abc")
fmt.Println(res2) //false
}
```
### <span id="IsFloatStr">IsFloatStr</span>
<p>Check if the string can convert to a float.</p>
<b>Signature:</b>
```go
func IsFloatStr(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsFloatStr("")) //false
fmt.Println(validator.IsFloatStr("12a")) //false
fmt.Println(validator.IsFloatStr("3.")) //true
fmt.Println(validator.IsFloatStr("+3.")) //true
fmt.Println(validator.IsFloatStr("-3.")) //true
fmt.Println(validator.IsFloatStr("12")) //true
}
```
### <span id="IsNumberStr">IsNumberStr</span>
<p>Check if the string can convert to a number.</p>
<b>Signature:</b>
```go
func IsNumberStr(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsNumberStr("")) //false
fmt.Println(validator.IsNumberStr("12a")) //false
fmt.Println(validator.IsNumberStr("3.")) //true
fmt.Println(validator.IsNumberStr("+3.")) //true
fmt.Println(validator.IsNumberStr("-3.")) //true
fmt.Println(validator.IsNumberStr("+3e2")) //true
}
```
### <span id="IsJSON">IsJSON</span>
<p>Check if the string is valid JSON.</p>
<b>Signature:</b>
```go
func IsJSON(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsJSON("")) //false
fmt.Println(validator.IsJSON("abc")) //false
fmt.Println(validator.IsJSON("{}")) //true
fmt.Println(validator.IsJSON("[]")) //true
fmt.Println(validator.IsJSON("123")) //true
fmt.Println(validator.IsJSON("{\"name\": \"test\"}")) //true
}
```
### <span id="IsRegexMatch">IsRegexMatch</span>
<p>Check if the string match the regexp.</p>
<b>Signature:</b>
```go
func IsRegexMatch(s, regex string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsRegexMatch("abc", `^[a-zA-Z]+$`)) //true
fmt.Println(validator.IsRegexMatch("1ab", `^[a-zA-Z]+$`)) //false
fmt.Println(validator.IsRegexMatch("", `^[a-zA-Z]+$`)) //false
}
```
### <span id="IsIntStr">IsIntStr</span>
<p>Check if the string can convert to a integer.</p>
<b>Signature:</b>
```go
func IsIntStr(s string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIntStr("+3")) //true
fmt.Println(validator.IsIntStr("-3")) //true
fmt.Println(validator.IsIntStr("3.")) //false
fmt.Println(validator.IsIntStr("abc")) //false
}
```
### <span id="IsIp">IsIp</span>
<p>Check if the string is a ip address.</p>
<b>Signature:</b>
```go
func IsIp(ipstr string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIp("127.0.0.1")) //true
fmt.Println(validator.IsIp("::0:0:0:0:0:0:1")) //true
fmt.Println(validator.IsIp("127.0.0")) //false
fmt.Println(validator.IsIp("127")) //false
}
```
### <span id="IsIpV4">IsIpV4</span>
<p>Check if the string is a ipv4 address.</p>
<b>Signature:</b>
```go
func IsIpV4(ipstr string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIpV4("127.0.0.1")) //true
fmt.Println(validator.IsIpV4("::0:0:0:0:0:0:1")) //false
fmt.Println(validator.IsIpV4("127.0.0")) //false
fmt.Println(validator.IsIpV4("127")) //false
}
```
### <span id="IsIpV6">IsIpV6</span>
<p>Check if the string is a ipv6 address.</p>
<b>Signature:</b>
```go
func IsIpV6(ipstr string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIpV6("127.0.0.1")) //false
fmt.Println(validator.IsIpV6("::0:0:0:0:0:0:1")) //true
fmt.Println(validator.IsIpV6("127.0.0")) //false
fmt.Println(validator.IsIpV6("127")) //false
}
```
### <span id="IsStrongPassword">IsStrongPassword</span>
<p>Check if the string is strong password (alpha(lower+upper) + number + special chars(!@#$%^&*()?><)).</p>
<b>Signature:</b>
```go
func IsStrongPassword(password string, length int) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsStrongPassword("abc", 3)) //false
fmt.Println(validator.IsStrongPassword("abc123", 6)) //false
fmt.Println(validator.IsStrongPassword("abcABC", 6)) //false
fmt.Println(validator.IsStrongPassword("abcABC123@#$", 16)) //false
fmt.Println(validator.IsStrongPassword("abcABC123@#$", 12)) //true
}
```
### <span id="IsUrl">IsUrl</span>
<p>Check if the string is url.</p>
<b>Signature:</b>
```go
func IsUrl(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsUrl("http://abc.com")) //true
fmt.Println(validator.IsUrl("abc.com")) //true
fmt.Println(validator.IsUrl("a.b.com")) //true
fmt.Println(validator.IsUrl("abc")) //false
}
```
### <span id="IsWeakPassword">IsWeakPassword</span>
<p>Check if the string is weak passwordonly letter or only number or letter + number
.</p>
<b>Signature:</b>
```go
func IsWeakPassword(password string, length int) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsWeakPassword("abc")) //true
fmt.Println(validator.IsWeakPassword("123")) //true
fmt.Println(validator.IsWeakPassword("abc123")) //true
fmt.Println(validator.IsWeakPassword("abc123@#$")) //false
}
```

799
docs/validator_zh-CN.md Normal file
View File

@@ -0,0 +1,799 @@
# Validator
validator验证器包包含常用字符串格式验证函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/validator/validator.go](https://github.com/duke-git/lancet/blob/main/validator/validator.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/validator"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录:
- [ContainChinese](#ContainChinese)
- [ContainLetter](#ContainLetter)
- [ContainLower](#ContainLower)
- [ContainUpper](#ContainUpper)
- [IsAlpha](#IsAlpha)
- [IsAllUpper](#IsAllUpper)
- [IsAllLower](#IsAllLower)
- [IsBase64](#IsBase64)
- [IsChineseMobile](#IsChineseMobile)
- [IsChineseIdNum](#IsChineseIdNum)
- [IsChinesePhone](#IsChinesePhone)
- [IsCreditCard](#IsCreditCard)
- [IsDns](#IsDns)
- [IsEmail](#IsEmail)
- [IsEmptyString](#IsEmptyString)
- [IsFloatStr](#IsFloatStr)
- [IsNumberStr](#IsNumberStr)
- [IsJSON](#IsJSON)
- [IsRegexMatch](#IsRegexMatch)
- [IsIntStr](#IsIntStr)
- [IsIp](#IsIp)
- [IsIpV4](#IsIpV4)
- [IsIpV6](#IsIpV6)
- [IsStrongPassword](#IsStrongPassword)
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ContainChinese">ContainChinese</span>
<p>验证字符串是否包含中文字符</p>
<b>函数签名:</b>
```go
func ContainChinese(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainChinese("你好")
fmt.Println(res1) //true
res2 := validator.ContainChinese("你好hello")
fmt.Println(res2) //true
res3 := validator.ContainChinese("hello")
fmt.Println(res3) //false
}
```
### <span id="ContainLetter">ContainLetter</span>
<p>验证字符串是否包含至少一个英文字母</p>
<b>函数签名:</b>
```go
func ContainLetter(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainLetter("1bc")
fmt.Println(res1) //true
res2 := validator.ContainLetter("123")
fmt.Println(res2) //false
res3 := validator.ContainLetter("&@#$%^&*")
fmt.Println(res3) //false
}
```
### <span id="ContainLower">ContainLower</span>
<p>验证字符串是否包含至少一个英文小写字母</p>
<b>函数签名:</b>
```go
func ContainLower(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainLower("1bc")
fmt.Println(res1) //true
res2 := validator.ContainLower("123")
fmt.Println(res2) //false
res3 := validator.ContainLower("1BC")
fmt.Println(res3) //false
}
```
### <span id="ContainUpper">ContainUpper</span>
<p>验证字符串是否包含至少一个英文大写字母.</p>
<b>函数签名:</b>
```go
func ContainUpper(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.ContainUpper("1bc")
fmt.Println(res1) //false
res2 := validator.ContainUpper("123")
fmt.Println(res2) //false
res3 := validator.ContainUpper("1BC")
fmt.Println(res3) //true
}
```
### <span id="IsAlpha">IsAlpha</span>
<p>验证字符串是否只包含英文字母</p>
<b>函数签名:</b>
```go
func IsAlpha(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAlpha("abc")
fmt.Println(res1) //true
res2 := validator.IsAlpha("1bc")
fmt.Println(res2) //false
res3 := validator.IsAlpha("")
fmt.Println(res3) //false
}
```
### <span id="IsAllUpper">IsAllUpper</span>
<p>验证字符串是否全是大写英文字母</p>
<b>函数签名:</b>
```go
func IsAllUpper(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAllUpper("ABC")
fmt.Println(res1) //true
res2 := validator.IsAllUpper("aBC")
fmt.Println(res2) //false
}
```
### <span id="IsAllLower">IsAllLower</span>
<p>验证字符串是否全是小写英文字母</p>
<b>函数签名:</b>
```go
func IsAllLower(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsAllLower("abc")
fmt.Println(res1) //true
res2 := validator.IsAllLower("abC")
fmt.Println(res2) //false
}
```
### <span id="IsBase64">IsBase64</span>
<p>验证字符串是否是base64编码</p>
<b>函数签名:</b>
```go
func IsBase64(base64 string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsBase64("aGVsbG8=")
fmt.Println(res1) //true
res2 := validator.IsBase64("123456")
fmt.Println(res2) //false
}
```
### <span id="IsChineseMobile">IsChineseMobile</span>
<p>验证字符串是否是中国手机号码</p>
<b>函数签名:</b>
```go
func IsChineseMobile(mobileNum string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChineseMobile("13263527980")
fmt.Println(res1) //true
res2 := validator.IsChineseMobile("434324324")
fmt.Println(res2) //false
}
```
### <span id="IsChineseIdNum">IsChineseIdNum</span>
<p>验证字符串是否是中国身份证号码</p>
<b>函数签名:</b>
```go
func IsChineseIdNum(id string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChineseIdNum("210911192105130715")
fmt.Println(res1) //true
res2 := validator.IsChineseIdNum("123456")
fmt.Println(res2) //false
}
```
### <span id="IsChinesePhone">IsChinesePhone</span>
<p>验证字符串是否是中国电话座机号码</p>
<b>函数签名:</b>
```go
func IsChinesePhone(phone string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsChinesePhone("010-32116675")
fmt.Println(res1) //true
res2 := validator.IsChinesePhone("123-87562")
fmt.Println(res2) //false
}
```
### <span id="IsCreditCard">IsCreditCard</span>
<p>验证字符串是否是信用卡号码</p>
<b>函数签名:</b>
```go
func IsCreditCard(creditCart string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsCreditCard("4111111111111111")
fmt.Println(res1) //true
res2 := validator.IsCreditCard("123456")
fmt.Println(res2) //false
}
```
### <span id="IsDns">IsDns</span>
<p>验证字符串是否是有效dns</p>
<b>函数签名:</b>
```go
func IsDns(dns string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsDns("abc.com")
fmt.Println(res1) //true
res2 := validator.IsDns("a.b.com")
fmt.Println(res2) //false
res3 := validator.IsDns("http://abc.com")
fmt.Println(res3) //false
}
```
### <span id="IsEmail">IsEmail</span>
<p>验证字符串是否是有效电子邮件地址</p>
<b>函数签名:</b>
```go
func IsEmail(email string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsEmail("abc@xyz.com")
fmt.Println(res1) //true
res2 := validator.IsEmail("a.b@@com")
fmt.Println(res2) //false
}
```
### <span id="IsEmptyString">IsEmptyString</span>
<p>验证字符串是否是空字符串</p>
<b>函数签名:</b>
```go
func IsEmptyString(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
res1 := validator.IsEmptyString("")
fmt.Println(res1) //true
res2 := validator.IsEmptyString("abc")
fmt.Println(res2) //false
}
```
### <span id="IsFloatStr">IsFloatStr</span>
<p>验证字符串是否是可以转换为浮点数</p>
<b>函数签名:</b>
```go
func IsFloatStr(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsFloatStr("")) //false
fmt.Println(validator.IsFloatStr("12a")) //false
fmt.Println(validator.IsFloatStr("3.")) //true
fmt.Println(validator.IsFloatStr("+3.")) //true
fmt.Println(validator.IsFloatStr("-3.")) //true
fmt.Println(validator.IsFloatStr("12")) //true
}
```
### <span id="IsNumberStr">IsNumberStr</span>
<p>验证字符串是否是可以转换为数字</p>
<b>函数签名:</b>
```go
func IsNumberStr(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsNumberStr("")) //false
fmt.Println(validator.IsNumberStr("12a")) //false
fmt.Println(validator.IsNumberStr("3.")) //true
fmt.Println(validator.IsNumberStr("+3.")) //true
fmt.Println(validator.IsNumberStr("-3.")) //true
fmt.Println(validator.IsNumberStr("+3e2")) //true
}
```
### <span id="IsJSON">IsJSON</span>
<p>验证字符串是否是有效json</p>
<b>函数签名:</b>
```go
func IsJSON(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsJSON("")) //false
fmt.Println(validator.IsJSON("abc")) //false
fmt.Println(validator.IsJSON("{}")) //true
fmt.Println(validator.IsJSON("[]")) //true
fmt.Println(validator.IsJSON("123")) //true
fmt.Println(validator.IsJSON("{\"name\": \"test\"}")) //true
}
```
### <span id="IsRegexMatch">IsRegexMatch</span>
<p>验证字符串是否可以匹配正则表达式</p>
<b>函数签名:</b>
```go
func IsRegexMatch(s, regex string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsRegexMatch("abc", `^[a-zA-Z]+$`)) //true
fmt.Println(validator.IsRegexMatch("1ab", `^[a-zA-Z]+$`)) //false
fmt.Println(validator.IsRegexMatch("", `^[a-zA-Z]+$`)) //false
}
```
### <span id="IsIntStr">IsIntStr</span>
<p>验证字符串是否是可以转换为整数</p>
<b>函数签名:</b>
```go
func IsIntStr(s string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIntStr("+3")) //true
fmt.Println(validator.IsIntStr("-3")) //true
fmt.Println(validator.IsIntStr("3.")) //false
fmt.Println(validator.IsIntStr("abc")) //false
}
```
### <span id="IsIp">IsIp</span>
<p>验证字符串是否是ip地址</p>
<b>函数签名:</b>
```go
func IsIp(ipstr string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIp("127.0.0.1")) //true
fmt.Println(validator.IsIp("::0:0:0:0:0:0:1")) //true
fmt.Println(validator.IsIp("127.0.0")) //false
fmt.Println(validator.IsIp("127")) //false
}
```
### <span id="IsIpV4">IsIpV4</span>
<p>验证字符串是否是ipv4地址</p>
<b>函数签名:</b>
```go
func IsIpV4(ipstr string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIpV4("127.0.0.1")) //true
fmt.Println(validator.IsIpV4("::0:0:0:0:0:0:1")) //false
fmt.Println(validator.IsIpV4("127.0.0")) //false
fmt.Println(validator.IsIpV4("127")) //false
}
```
### <span id="IsIpV6">IsIpV6</span>
<p>验证字符串是否是ipv6地址</p>
<b>函数签名:</b>
```go
func IsIpV6(ipstr string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsIpV6("127.0.0.1")) //false
fmt.Println(validator.IsIpV6("::0:0:0:0:0:0:1")) //true
fmt.Println(validator.IsIpV6("127.0.0")) //false
fmt.Println(validator.IsIpV6("127")) //false
}
```
### <span id="IsStrongPassword">IsStrongPassword</span>
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))</p>
<b>函数签名:</b>
```go
func IsStrongPassword(password string, length int) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsStrongPassword("abc", 3)) //false
fmt.Println(validator.IsStrongPassword("abc123", 6)) //false
fmt.Println(validator.IsStrongPassword("abcABC", 6)) //false
fmt.Println(validator.IsStrongPassword("abcABC123@#$", 16)) //false
fmt.Println(validator.IsStrongPassword("abcABC123@#$", 12)) //true
}
```
### <span id="IsUrl">IsUrl</span>
<p>验证字符串是否是url</p>
<b>函数签名:</b>
```go
func IsUrl(str string) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsUrl("http://abc.com")) //true
fmt.Println(validator.IsUrl("abc.com")) //true
fmt.Println(validator.IsUrl("a.b.com")) //true
fmt.Println(validator.IsUrl("abc")) //false
}
```
### <span id="IsWeakPassword">IsWeakPassword</span>
<p>验证字符串是否是弱密码only letter or only number or letter + number
.</p>
<b>函数签名:</b>
```go
func IsWeakPassword(password string, length int) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsWeakPassword("abc")) //true
fmt.Println(validator.IsWeakPassword("123")) //true
fmt.Println(validator.IsWeakPassword("abc123")) //true
fmt.Println(validator.IsWeakPassword("abc123@#$")) //false
}
```

57
docs/xerror.md Normal file
View File

@@ -0,0 +1,57 @@
# Xerror
Package xerror implements helpers for errors.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/xerror/xerror.go](https://github.com/duke-git/lancet/blob/main/xerror/xerror.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/xerror"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Unwrap](#Unwrap)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Unwrap">Unwrap</span>
<p>Unwrap if err is nil then it returns a valid value. If err is not nil, Unwrap panics with err.</p>
<b>Signature:</b>
```go
func Unwrap[T any](val T, err error) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
_, err := strconv.Atoi("4o2")
defer func() {
v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
}()
xerror.Unwrap(strconv.Atoi("4o2"))
}
```

57
docs/xerror_zh-CN.md Normal file
View File

@@ -0,0 +1,57 @@
# Xerror
xerror错误处理逻辑封装
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/xerror/xerror.go](https://github.com/duke-git/lancet/blob/main/xerror/xerror.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/xerror"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Unwrap](#Unwrap)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Unwrap">Unwrap</span>
<p>如果err为nil则展开则它返回一个有效值。 如果err不是nil则Unwrap使用err发生恐慌。</p>
<b>函数签名:</b>
```go
func Unwrap[T any](val T, err error) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/xerror"
)
func main() {
_, err := strconv.Atoi("4o2")
defer func() {
v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
}()
xerror.Unwrap(strconv.Atoi("4o2"))
}
```

View File

@@ -5,10 +5,16 @@
package fileutil
import (
"archive/zip"
"bufio"
"errors"
"io"
"io/fs"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
)
// IsExist checks if a file or directory exists
@@ -75,6 +81,53 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
}
}
//ClearFile write empty string to path file
func ClearFile(path string) error {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString("")
return err
}
//ReadFileToString return string of file content
func ReadFileToString(path string) (string, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
return "", err
}
return string(bytes), nil
}
// ReadFileByLine read file line by line
func ReadFileByLine(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
res := make([]string, 0)
buf := bufio.NewReader(f)
for {
line, _, err := buf.ReadLine()
l := string(line)
if err == io.EOF {
break
}
if err != nil {
continue
}
res = append(res, l)
}
return res, nil
}
// ListFileNames return all file names in the path
func ListFileNames(path string) ([]string, error) {
if !IsExist(path) {
@@ -100,3 +153,146 @@ func ListFileNames(path string) ([]string, error) {
return res, nil
}
// Zip create zip file, fpath could be a single file or a directory
func Zip(fpath string, destPath string) error {
zipFile, err := os.Create(destPath)
if err != nil {
return err
}
defer zipFile.Close()
archive := zip.NewWriter(zipFile)
defer archive.Close()
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
if err != nil {
return err
}
}
return nil
})
return nil
}
// UnZip unzip the file and save it to destPath
func UnZip(zipFile string, destPath string) error {
zipReader, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer zipReader.Close()
for _, f := range zipReader.File {
path := filepath.Join(destPath, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
} else {
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
}
inFile, err := f.Open()
if err != nil {
return err
}
defer inFile.Close()
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, inFile)
if err != nil {
return err
}
}
}
return nil
}
// IsLink checks if a file is symbol link or not
func IsLink(path string) bool {
fi, err := os.Lstat(path)
if err != nil {
return false
}
return fi.Mode()&os.ModeSymlink != 0
}
// FileMode return file's mode and permission
func FileMode(path string) (fs.FileMode, error) {
fi, err := os.Lstat(path)
if err != nil {
return 0, err
}
return fi.Mode(), nil
}
// MiMeType return file mime type
// param `file` should be string(file path) or *os.File
func MiMeType(file any) string {
var mediatype string
readBuffer := func(f *os.File) ([]byte, error) {
buffer := make([]byte, 512)
_, err := f.Read(buffer)
if err != nil {
return nil, err
}
return buffer, nil
}
if filePath, ok := file.(string); ok {
f, err := os.Open(filePath)
if err != nil {
return mediatype
}
buffer, err := readBuffer(f)
if err != nil {
return mediatype
}
return http.DetectContentType(buffer)
}
if f, ok := file.(*os.File); ok {
buffer, err := readBuffer(f)
if err != nil {
return mediatype
}
return http.DetectContentType(buffer)
}
return mediatype
}

View File

@@ -2,99 +2,201 @@ package fileutil
import (
"os"
"reflect"
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestIsExist(t *testing.T) {
assert := internal.NewAssert(t, "TestIsExist")
cases := []string{"./", "./file.go", "./a.txt"}
expected := []bool{true, true, false}
for i := 0; i < len(cases); i++ {
res := IsExist(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "IsExist", cases[i], expected[i], res)
t.FailNow()
}
actual := IsExist(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestCreateFile(t *testing.T) {
assert := internal.NewAssert(t, "TestCreateFile")
f := "./text.txt"
if CreateFile(f) {
file, err := os.Open(f)
if err != nil {
utils.LogFailedTestInfo(t, "CreateFile", f, f, "create file error: "+err.Error())
t.FailNow()
}
if file.Name() != f {
utils.LogFailedTestInfo(t, "CreateFile", f, f, file.Name())
t.FailNow()
}
assert.IsNil(err)
assert.Equal(f, file.Name())
} else {
utils.LogFailedTestInfo(t, "CreateFile", f, f, "create file error")
t.FailNow()
}
os.Remove(f)
}
func TestIsDir(t *testing.T) {
assert := internal.NewAssert(t, "TestIsDir")
cases := []string{"./", "./a.txt"}
expected := []bool{true, false}
for i := 0; i < len(cases); i++ {
res := IsDir(cases[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "IsDir", cases[i], expected[i], res)
t.FailNow()
}
actual := IsDir(cases[i])
assert.Equal(expected[i], actual)
}
}
func TestRemoveFile(t *testing.T) {
assert := internal.NewAssert(t, "TestRemoveFile")
f := "./text.txt"
if CreateFile(f) {
if !IsExist(f) {
CreateFile(f)
err := RemoveFile(f)
if err != nil {
utils.LogFailedTestInfo(t, "RemoveFile", f, f, err.Error())
t.FailNow()
}
} else {
utils.LogFailedTestInfo(t, "RemoveFile", f, f, "create file error")
t.FailNow()
assert.IsNil(err)
}
}
func TestCopyFile(t *testing.T) {
assert := internal.NewAssert(t, "TestCopyFile")
srcFile := "./text.txt"
CreateFile(srcFile)
dstFile := "./text_copy.txt"
destFile := "./text_copy.txt"
err := CopyFile(srcFile, dstFile)
err := CopyFile(srcFile, destFile)
if err != nil {
file, err := os.Open(dstFile)
if err != nil {
utils.LogFailedTestInfo(t, "CopyFile", srcFile, dstFile, "create file error: "+err.Error())
t.FailNow()
}
if file.Name() != dstFile {
utils.LogFailedTestInfo(t, "CopyFile", srcFile, dstFile, file.Name())
t.FailNow()
}
file, err := os.Open(destFile)
assert.IsNil(err)
assert.Equal(destFile, file.Name())
}
os.Remove(srcFile)
os.Remove(destFile)
}
func TestListFileNames(t *testing.T) {
filesInCurrentPath, err := ListFileNames("../datetime/")
if err != nil {
t.FailNow()
}
expected := []string{"datetime.go", "datetime_test.go"}
if !reflect.DeepEqual(filesInCurrentPath, expected) {
utils.LogFailedTestInfo(t, "ToChar", "./", expected, filesInCurrentPath)
t.FailNow()
}
assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("./")
assert.IsNil(err)
expected := []string{"file.go", "file_test.go"}
assert.Equal(expected, filesInPath)
}
func TestReadFileToString(t *testing.T) {
assert := internal.NewAssert(t, "TestReadFileToString")
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := ReadFileToString(path)
assert.Equal("hello world", content)
os.Remove(path)
}
func TestClearFile(t *testing.T) {
assert := internal.NewAssert(t, "TestClearFile")
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello world")
err := ClearFile(path)
assert.IsNil(err)
content, _ := ReadFileToString(path)
assert.Equal("", content)
os.Remove(path)
}
func TestReadFileByLine(t *testing.T) {
assert := internal.NewAssert(t, "TestReadFileByLine")
path := "./text.txt"
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
expected := []string{"hello", "world"}
actual, _ := ReadFileByLine(path)
assert.Equal(expected, actual)
os.Remove(path)
}
func TestZipAndUnZip(t *testing.T) {
assert := internal.NewAssert(t, "TestZipAndUnZip")
srcFile := "./text.txt"
CreateFile(srcFile)
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
defer file.Close()
file.WriteString("hello\nworld")
zipFile := "./text.zip"
err := Zip(srcFile, zipFile)
assert.IsNil(err)
unZipPath := "./unzip"
err = UnZip(zipFile, unZipPath)
assert.IsNil(err)
unZipFile := "./unzip/text.txt"
assert.Equal(true, IsExist(unZipFile))
os.Remove(srcFile)
os.Remove(zipFile)
os.RemoveAll(unZipPath)
}
func TestFileMode(t *testing.T) {
assert := internal.NewAssert(t, "TestFileMode")
srcFile := "./text.txt"
CreateFile(srcFile)
mode, err := FileMode(srcFile)
assert.IsNil(err)
t.Log(mode)
os.Remove(srcFile)
}
func TestIsLink(t *testing.T) {
assert := internal.NewAssert(t, "TestIsLink")
srcFile := "./text.txt"
CreateFile(srcFile)
linkFile := "./text.link"
if !IsExist(linkFile) {
_ = os.Symlink(srcFile, linkFile)
}
assert.Equal(true, IsLink(linkFile))
assert.Equal(false, IsLink("./file.go"))
os.Remove(srcFile)
os.Remove(linkFile)
}
func TestMiMeType(t *testing.T) {
assert := internal.NewAssert(t, "TestMiMeType")
f, _ := os.Open("./file.go")
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
}

View File

@@ -7,7 +7,7 @@ package formatter
import "strings"
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
func Comma(v interface{}, symbol string) string {
func Comma(v any, symbol string) string {
s := numString(v)
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {

View File

@@ -14,7 +14,7 @@ func commaString(s string) string {
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
}
func numString(value interface{}) string {
func numString(value any) string {
switch reflect.TypeOf(value).Kind() {
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
return fmt.Sprintf("%v", value)

View File

@@ -3,26 +3,21 @@ package formatter
import (
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestComma(t *testing.T) {
comma(t, "", "", "")
comma(t, "aa", "", "")
comma(t, "aa.a", "", "")
comma(t, []int{1}, "", "")
comma(t, "123", "", "123")
comma(t, "12345", "", "12,345")
comma(t, 12345, "", "12,345")
comma(t, 12345, "$", "$12,345")
comma(t, 12345, "¥", "¥12,345")
comma(t, 12345.6789, "", "12,345.6789")
}
assert := internal.NewAssert(t, "TestComma")
func comma(t *testing.T, test interface{}, symbol string, expected interface{}) {
res := Comma(test, symbol)
if res != expected {
utils.LogFailedTestInfo(t, "Comma", test, expected, res)
t.FailNow()
}
assert.Equal("", Comma("", ""))
assert.Equal("", Comma("aa", ""))
assert.Equal("", Comma("aa.a", ""))
assert.Equal("", Comma([]int{1}, ""))
assert.Equal("123", Comma("123", ""))
assert.Equal("12,345", Comma("12345", ""))
assert.Equal("12,345", Comma(12345, ""))
assert.Equal("$12,345", Comma(12345, "$"))
assert.Equal("¥12,345", Comma(12345, "¥"))
assert.Equal("12,345.6789", Comma(12345.6789, ""))
}

115
function/function.go Normal file
View File

@@ -0,0 +1,115 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package function implements some functions for control the function execution and some is for functional programming.
package function
import (
"reflect"
"time"
)
// After creates a function that invokes func once it's called n or more times
func After(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure
mustBeFunction(fn)
return func(args ...any) []reflect.Value {
n--
if n < 1 {
return unsafeInvokeFunc(fn, args...)
}
return nil
}
}
// Before creates a function that invokes func once it's called less than n times
func Before(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure
mustBeFunction(fn)
var res []reflect.Value
return func(args ...any) []reflect.Value {
if n > 0 {
res = unsafeInvokeFunc(fn, args...)
}
if n <= 0 {
fn = nil
}
n--
return res
}
}
// Fn is for curry function which is func(...any) any
type Fn func(...any) any
// Curry make a curry function
func (f Fn) Curry(i any) func(...any) any {
return func(values ...any) any {
v := append([]any{i}, values...)
return f(v...)
}
}
// Compose compose the functions from right to left
func Compose(fnList ...func(...any) any) func(...any) any {
return func(s ...any) any {
f := fnList[0]
restFn := fnList[1:]
if len(fnList) == 1 {
return f(s...)
}
return f(Compose(restFn...)(s...))
}
}
// Delay make the function execution after delayed time
func Delay(delay time.Duration, fn any, args ...any) {
// Catch programming error while constructing the closure
mustBeFunction(fn)
time.Sleep(delay)
invokeFunc(fn, args...)
}
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
func Debounced(fn func(), duration time.Duration) func() {
// Catch programming error while constructing the closure
mustBeFunction(fn)
timer := time.NewTimer(duration)
timer.Stop()
go func() {
for {
select {
case <-timer.C:
go fn()
}
}
}()
return func() { timer.Reset(duration) }
}
// Schedule invoke function every duration time, util close the returned bool chan
func Schedule(d time.Duration, fn any, args ...any) chan bool {
// Catch programming error while constructing the closure
mustBeFunction(fn)
quit := make(chan bool)
go func() {
for {
unsafeInvokeFunc(fn, args...)
select {
case <-time.After(d):
case <-quit:
return
}
}
}()
return quit
}

View File

@@ -0,0 +1,39 @@
package function
import (
"fmt"
"reflect"
)
func invokeFunc(fn any, args ...any) []reflect.Value {
fv := functionValue(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
fv := reflect.ValueOf(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func functionValue(function any) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}
func mustBeFunction(function any) {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
}

132
function/function_test.go Normal file
View File

@@ -0,0 +1,132 @@
package function
import (
"fmt"
"reflect"
"strings"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestAfter(t *testing.T) {
arr := []string{"a", "b"}
f := After(len(arr), func(i int) int {
fmt.Println("print done")
return i
})
type cb func(args ...any) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("print: arr[%d] is %s \n", i, s)
v := fn(i)
if v != nil {
vv := v[0].Int()
if vv != 1 {
t.FailNow()
}
}
}
fmt.Println("print: arr is", arr)
for i := 0; i < len(arr); i++ {
print(i, arr[i], f)
}
}
func TestBefore(t *testing.T) {
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...any) []reflect.Value
appendStr := func(i int, s string, fn cb) {
v := fn(i)
res = append(res, v[0].Int())
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
}
func TestCurry(t *testing.T) {
assert := internal.NewAssert(t, "TestCurry")
add := func(a, b int) int {
return a + b
}
var addCurry Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
assert.Equal(3, add1(2))
}
func TestCompose(t *testing.T) {
assert := internal.NewAssert(t, "TestCompose")
toUpper := func(a ...any) any {
return strings.ToUpper(a[0].(string))
}
toLower := func(a ...any) any {
return strings.ToLower(a[0].(string))
}
expected := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower)
res := cf("aBCde")
assert.Equal(expected, res)
}
func TestDelay(t *testing.T) {
var print = func(s string) {
t.Log(s)
}
Delay(2*time.Second, print, "test delay")
}
func TestDebounced(t *testing.T) {
assert := internal.NewAssert(t, "TestDebounced")
count := 0
add := func() {
count++
}
debouncedAdd := Debounced(add, 50*time.Microsecond)
debouncedAdd()
debouncedAdd()
debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond)
assert.Equal(1, count)
debouncedAdd()
time.Sleep(100 * time.Millisecond)
assert.Equal(2, count)
}
func TestSchedule(t *testing.T) {
assert := internal.NewAssert(t, "TestSchedule")
var res []string
appendStr := func(s string) {
res = append(res, s)
}
stop := Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
expected := []string{"*", "*", "*", "*", "*"}
assert.Equal(expected, res)
}

37
function/watcher.go Normal file
View File

@@ -0,0 +1,37 @@
package function
import "time"
// Watcher is used for record code excution time
type Watcher struct {
startTime int64
stopTime int64
excuting bool
}
// Start the watch timer.
func (w *Watcher) Start() {
w.startTime = time.Now().UnixNano()
w.excuting = true
}
// Stop the watch timer.
func (w *Watcher) Stop() {
w.stopTime = time.Now().UnixNano()
w.excuting = false
}
// GetElapsedTime get excute elapsed time.
func (w *Watcher) GetElapsedTime() time.Duration {
if w.excuting {
return time.Duration(time.Now().UnixNano() - w.startTime)
}
return time.Duration(w.stopTime - w.startTime)
}
// Reset the watch timer.
func (w *Watcher) Reset() {
w.startTime = 0
w.stopTime = 0
w.excuting = false
}

37
function/watcher_test.go Normal file
View File

@@ -0,0 +1,37 @@
package function
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestWatcher(t *testing.T) {
assert := internal.NewAssert(t, "TestWatcher")
w := &Watcher{}
w.Start()
longRunningTask()
assert.Equal(true, w.excuting)
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
t.Log("Elapsed Time (milsecond)", eapsedTime)
assert.Equal(false, w.excuting)
w.Reset()
assert.Equal(int64(0), w.startTime)
assert.Equal(int64(0), w.stopTime)
}
func longRunningTask() {
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}

4
go.mod
View File

@@ -1,3 +1,3 @@
module github.com/duke-git/lancet
module github.com/duke-git/lancet/v2
go 1.16
go 1.18

171
internal/assert.go Normal file
View File

@@ -0,0 +1,171 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package internal is for internal use.
package internal
import (
"fmt"
"reflect"
"runtime"
"testing"
)
const (
compareNotEqual int = iota - 2
compareLess
compareEqual
compareGreater
)
// Assert is a simple implementation of assertion, only for internal usage
type Assert struct {
T *testing.T
CaseName string
}
// NewAssert return instance of Assert
func NewAssert(t *testing.T, caseName string) *Assert {
return &Assert{T: t, CaseName: caseName}
}
// Equal check if expected is equal with actual
func (a *Assert) Equal(expected, actual any) {
if compare(expected, actual) != compareEqual {
makeTestFailed(a.T, a.CaseName, expected, actual)
}
}
// NotEqual check if expected is not equal with actual
func (a *Assert) NotEqual(expected, actual any) {
if compare(expected, actual) == compareEqual {
expectedInfo := fmt.Sprintf("not %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// Greater check if expected is greate than actual
func (a *Assert) Greater(expected, actual any) {
if compare(expected, actual) != compareGreater {
expectedInfo := fmt.Sprintf("> %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// GreaterOrEqual check if expected is greate than or equal with actual
func (a *Assert) GreaterOrEqual(expected, actual any) {
isGreatOrEqual := compare(expected, actual) == compareGreater || compare(expected, actual) == compareEqual
if !isGreatOrEqual {
expectedInfo := fmt.Sprintf(">= %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// Less check if expected is less than actual
func (a *Assert) Less(expected, actual any) {
if compare(expected, actual) != compareLess {
expectedInfo := fmt.Sprintf("< %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// LessOrEqual check if expected is less than or equal with actual
func (a *Assert) LessOrEqual(expected, actual any) {
isLessOrEqual := compare(expected, actual) == compareLess || compare(expected, actual) == compareEqual
if !isLessOrEqual {
expectedInfo := fmt.Sprintf("<= %v", expected)
makeTestFailed(a.T, a.CaseName, expectedInfo, actual)
}
}
// IsNil check if value is nil
func (a *Assert) IsNil(value any) {
if value != nil {
makeTestFailed(a.T, a.CaseName, nil, value)
}
}
// IsNotNil check if value is not nil
func (a *Assert) IsNotNil(value any) {
if value == nil {
makeTestFailed(a.T, a.CaseName, "not nil", value)
}
}
// compare x and y return :
// x > y -> 1, x < y -> -1, x == y -> 0, x != y -> -2
func compare(x, y any) int {
vx := reflect.ValueOf(x)
vy := reflect.ValueOf(y)
if vx.Type() != vy.Type() {
return compareNotEqual
}
switch vx.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
xInt := vx.Int()
yInt := vy.Int()
if xInt > yInt {
return compareGreater
}
if xInt == yInt {
return compareEqual
}
if xInt < yInt {
return compareLess
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
xUint := vx.Uint()
yUint := vy.Uint()
if xUint > yUint {
return compareGreater
}
if xUint == yUint {
return compareEqual
}
if xUint < yUint {
return compareLess
}
case reflect.Float32, reflect.Float64:
xFloat := vx.Float()
yFloat := vy.Float()
if xFloat > yFloat {
return compareGreater
}
if xFloat == yFloat {
return compareEqual
}
if xFloat < yFloat {
return compareLess
}
case reflect.String:
xString := vx.String()
yString := vy.String()
if xString > yString {
return compareGreater
}
if xString == yString {
return compareEqual
}
if xString < yString {
return compareLess
}
default:
if reflect.DeepEqual(x, y) {
return compareEqual
}
return compareNotEqual
}
return compareNotEqual
}
// logFailedInfo make test failed and log error info
func makeTestFailed(t *testing.T, caseName string, expected, actual any) {
_, file, line, _ := runtime.Caller(2)
errInfo := fmt.Sprintf("Case %v failed. file: %v, line: %v, expected: %v, actual: %v.", caseName, file, line, expected, actual)
t.Error(errInfo)
t.FailNow()
}

50
internal/assert_test.go Normal file
View File

@@ -0,0 +1,50 @@
package internal
import (
"testing"
)
func TestAssert(t *testing.T) {
assert := NewAssert(t, "TestAssert")
assert.Equal(0, 0)
assert.NotEqual(1, 0)
assert.NotEqual("1", 1)
var uInt1 uint
var uInt2 uint
var uInt8 uint8
var uInt16 uint16
var uInt32 uint32
var uInt64 uint64
assert.NotEqual(uInt1, uInt8)
assert.NotEqual(uInt8, uInt16)
assert.NotEqual(uInt16, uInt32)
assert.NotEqual(uInt32, uInt64)
assert.Equal(uInt1, uInt2)
uInt1 = 1
uInt2 = 2
assert.Less(uInt1, uInt2)
assert.Greater(1, 0)
assert.GreaterOrEqual(1, 1)
assert.Less(0, 1)
assert.LessOrEqual(0, 0)
assert.Equal(0.1, 0.1)
assert.Greater(1.1, 0.1)
assert.Less(0.1, 1.1)
assert.Equal("abc", "abc")
assert.NotEqual("abc", "abd")
assert.Less("abc", "abd")
assert.Greater("abd", "abc")
assert.Equal([]int{1, 2, 3}, []int{1, 2, 3})
assert.NotEqual([]int{1, 2, 3}, []int{1, 2})
assert.IsNil(nil)
assert.IsNotNil("abc")
}

View File

@@ -0,0 +1,18 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package lancetconstraints contain some comstomer constraints.
package lancetconstraints
// Comparator is for comparing two values
type Comparator interface {
// Compare v1 and v2
// Ascending order: should return 1 -> v1 > v2, 0 -> v1 = v2, -1 -> v1 < v2
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
Compare(v1, v2 any) int
}
// Number contains all types of number and uintptr, used for generics constraint
type Number interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64
}

Some files were not shown because too many files have changed in this diff Show More