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

Compare commits

..

258 Commits

Author SHA1 Message Date
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
117 changed files with 22169 additions and 2536 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,7 +17,7 @@ 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 ./... -coverprofile=coverage.txt -covermode=atomic
- name: Upload coverage to Codecov

3
.gitignore vendored
View File

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

695
README.md
View File

@@ -1,44 +1,55 @@
<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.9-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.0-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...
- 💪 250+ 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.6. </b>
```go
go get github.com/duke-git/lancet@v1.2.6 // 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.
@@ -57,433 +68,351 @@ 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"
### 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:
### Convertor package contains some functions for data convertion.
```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/convertor"
```
#### 2. cryptor is for data encryption and decryption
- Support md5, hmac, aes, des, ras.
- Usage: import "github.com/duke-git/lancet/cryptor"
#### 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)
### Cryptor package is for data encryption and decryption.
```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/cryptor"
```
- Function list:
#### 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)
### Datetime package supports date and time format and compare.
```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/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)
#### 3. datetime parse and format datetime
- Parse and format datetime
- Usage: import "github.com/duke-git/lancet/datetime"
### Fileutil package implements some basic functions for file operations.
```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/fileutil"
```
- Function list:
#### Function list
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ClearFile)
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CreateFile)
- [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)
### Formatter contains some functions for data formatting.
```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/formatter"
```
#### Function list:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
#### 4. fileutil basic functions for file operations
- Basic functions for file operations.
- Usage: import "github.com/duke-git/lancet/fileutil"
### Function package can control the flow of function execution and support part of functional programming
```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/function"
```
- Function list
#### 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)
### Mathutil package implements some functions for math calculation.
```go
func ClearFile(path string) error //write empty string to path file
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
func ReadFileToString(path string) (string, error) //return string of file content
func ReadFileByLine(path string)([]string, error) //read file content by line
import "github.com/duke-git/lancet/v2/mathutil"
```
#### 5. formatter is for data format
#### Function list:
- [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)
- [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)
- Contain some formatting function
- Usage: import "github.com/duke-git/lancet/formatter"
### Netutil package contains functions to get net information and send http request.
```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/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)
### Random package implements some basic functions to generate random int and string.
```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/random"
```
#### 6. function can control the function execution and support functional programming
#### 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)
- Control function execution and support functional programming.
- Usage: import "github.com/duke-git/lancet/function"
### Retry package is for executing a function repeatedly until it was successful or canceled by the context.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
var print = func(s string) {
fmt.Println(s)
}
function.Delay(2*time.Second, print, "hello world")
}
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)
### Slice contains some functions to manipulate slice.
```go
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called n or more times
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //creates a function that invokes func once it's called less than n times
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //make a curryed function
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //compose the functions from right to left
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //invoke function after delayed time
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //invoke function every duration time, util close the returned bool chan
import "github.com/duke-git/lancet/v2/slice"
```
#### 7. netutil is for net process
#### 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)
- [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)
- [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)
- [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)
- Ip and http request method.
- Usage: import "github.com/duke-git/lancet/netutil".
- The Http function params orderurl, header, query string, body, httpclient.
### 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)
- [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)
### System package contain some functions about os, runtime, shell command.
```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/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:
### Validator package contains some functions for data validation.
```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
func ParseHttpResponse(resp *http.Response, obj interface{}) error //decode http response to specified interface
import "github.com/duke-git/lancet/v2/validator"
```
#### 8. random is for rand string and int generation
#### Function list:
- Generate random string and int.
- Usage: import "github.com/duke-git/lancet/random".
- [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)
### xerror package implements helpers for errors.
```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/xerror"
```
#### Function list:
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Unwrap)
- Function list:
## How to Contribute
```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
```
I really appreciate any code commits which make lancet lib powerful. Please follow the rules below to create your pull request.
#### 9. slice is for process slice
- 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.
```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]
}
```
- Function list:
```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 Every(slice, function interface{}) bool //return true if all of the values in the slice pass the predicate function, function signature should be func(index int, value interface{}) bool
func Filter(slice, function interface{}) interface{} //filter slice, function signature should be func(index int, value interface{}) bool
func Find(slice, function interface{}) interface{} //iterates over elements of slice, returning the first one that passes a truth test on function.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 Some(slice, function interface{}) bool //return true if any of the values in the list pass the predicate function, function signature should be func(index int, value interface{}) bool
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.
```
#### 10. strutil is for processing string
- Contain functions to precess string
- Usage: import "github.com/duke-git/lancet/strutil"
```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
}
```
- Function list:
```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"
```
#### 11. 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,55 @@
<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.9-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.0-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...
- 💪 250+常用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.6。</b>
```go
go get github.com/duke-git/lancet@v1.2.6 // 使用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包:
@@ -58,433 +68,353 @@ func main() {
}
```
### API文档
## API文档
#### 1. convertor数据转换包
- 转换函数支持常用数据类型之间的转换
- 导入包import "github.com/duke-git/lancet/convertor"
### 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)
- 函数列表:
### convertor转换器包支持一些常见的数据类型转换。
```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/convertor"
```
#### 2. cryptor加解密包
- 加密函数支持md5, hmac, aes, des, ras
- 导入包import "github.com/duke-git/lancet/cryptor"
#### 函数列表:
- [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)
### cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
```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/cryptor"
```
- 函数列表
#### 函数列表:
- [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)
### datetime日期时间处理包格式化日期比较日期。
```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/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)
#### 3. datetime日期时间处理包
- 处理日期时间
- 导入包import "github.com/duke-git/lancet/datetime"
### fileutil包支持文件基本操作。
```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/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)
### formatter格式化器包含一些数据格式化处理方法。
```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/formatter"
```
#### 函数列表:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
#### 4. fileutil文件处理包
- 文件处理常用函数
- 导入包import "github.com/duke-git/lancet/fileutil"
### function函数包控制函数执行流程包含部分函数式编程。
```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/function"
```
- 函数列表
#### 函数列表:
- [After](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Curry)
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
### mathutil包实现了一些数学计算的函数。
```go
func ClearFile(path string) error //清空文件内容
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) //列出目录下所有文件名称
func ReadFileToString(path string) (string, error) //读取文件内容为字符串
func ReadFileByLine(path string)([]string, error) //按行读取文件内容
import "github.com/duke-git/lancet/v2/mathutil"
```
#### 5. formatter格式化处理包
#### Function list:
- [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)
- [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)
- 格式化相关处理函数
- 导入包import "github.com/duke-git/lancet/formatter"
### netutil网络包支持获取ip地址发送http请求。
```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/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)
### random随机数生成器包可以生成随机[]bytes, int, string。
```go
func Comma(v interface{}, symbol string) string //用逗号每隔3位分割数字/字符串
import "github.com/duke-git/lancet/v2/random"
```
#### 6. function包可以控制函数执行支持部分函数式编程
- 控制函数执行,支持部分函数式编程
- 导入包import "github.com/duke-git/lancet/function"
#### 函数列表:
- [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)
### retry重试执行函数直到函数运行成功或被context cancel。
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
var print = func(s string) {
fmt.Println(s)
}
function.Delay(2*time.Second, print, "hello world")
}
import "github.com/duke-git/lancet/v2/retry"
```
- Function list:
#### 函数列表:
- [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)
### slice包包含操作切片的方法集合。
```go
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value //创建一个函数, 只有在运行了n次之后才有效果
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value //创建一个函数,调用不超过n次。 当n已经达到时最后一个函数调用的结果将被记住并返回
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} //函数柯里化
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} //从右至左组合函数
func Delay(delay time.Duration, fn interface{}, args ...interface{}) //延迟调用函数
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool //每隔duration时间调用函数, 关闭返回通道可以停止调用
import "github.com/duke-git/lancet/v2/slice"
```
#### 7. netutil网络处理包
#### 函数列表:
- [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)
- [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)
- [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)
- [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)
- 处理ip, http请求相关函数
- 导入包import "github.com/duke-git/lancet/netutil"
- http方法params参数顺序header, query string, body, httpclient
### strutil包含处理字符串的相关函数。
```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/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)
- [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)
### system包含os, runtime, shell command相关函数。
```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
func ParseHttpResponse(resp *http.Response, obj interface{}) error //将http响应解码成特定interface
import "github.com/duke-git/lancet/v2/system"
```
#### 8. random随机数处理包
#### 函数列表:
- [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/random"
### validator验证器包包含常用字符串格式验证函数。
```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/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)
### xerror包实现一些错误处理函数
```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/xerror"
```
#### 函数列表:
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)
#### 9. slice切片操作包
## 如何贡献代码
- 切片操作相关函数
- 导入包import "github.com/duke-git/lancet/slice"
- 由于go目前对范型支持不稳定slice处理函数参数和返回值大部分为interface{}, 待范型特性稳定后,会重构相关函数
非常感激任何的代码提交以使lancet的功能越来越强大。创建pull request时请遵守以下规则。
```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]
}
```
- 函数列表:
```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 Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
func Find(slice, function interface{}) interface{} //查找slice中第一个符合条件的元素函数签名func(index int, value interface{}) bool
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 Some(slice, function interface{}) bool //slice中任意一个元素都符合函数条件时返回true, 否则返回false. 函数签名func(index int, value interface{}) bool
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
```
#### 10. strutil字符串处理包
- 字符串操作相关函数
- 导入包import "github.com/duke-git/lancet/strutil"
```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
}
```
- 函数列表:
```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"
```
#### 11. validator验证器包
- 数据校验相关函数
- 导入包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
}
```
- 函数列表:
```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))
}

208
algorithm/sorter.go Normal file
View File

@@ -0,0 +1,208 @@
// 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) []T {
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)
}
}
}
return slice
}
// InsertionSort use insertion to sort slice.
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
if size <= 1 {
return slice
}
for i := 1; i < size; i++ {
currentItem := slice[i]
preIndex := i - 1
preItem := slice[preIndex]
isPreLessThanCurrent := comparator.Compare(preItem, currentItem) == -1
for preIndex >= 0 && isPreLessThanCurrent {
slice[preIndex+1] = slice[preIndex]
preIndex--
}
slice[preIndex+1] = preItem
}
return slice
}
// SelectionSort use selection to sort slice.
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
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)
}
return slice
}
// ShellSort shell sort slice.
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
if size <= 1 {
return 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 /= 3
}
return slice
}
// 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) []T {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
QuickSort(slice, lowIndex, p-1, comparator)
QuickSort(slice, p+1, highIndex, comparator)
}
return slice
}
// 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) []T {
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)
}
return slice
}
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, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T {
if lowIndex < highIndex {
mid := (lowIndex + highIndex) / 2
MergeSort(slice, lowIndex, mid, comparator)
MergeSort(slice, mid+1, highIndex, comparator)
merge(slice, lowIndex, mid, highIndex, comparator)
}
return slice
}
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]
}

177
algorithm/sorter_test.go Normal file
View File

@@ -0,0 +1,177 @@
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
//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},
}
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")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := BubbleSort(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)
}
func TestBubbleSortForIntSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
comparator := &intComparator{}
sortedInt := BubbleSort(intSlice, comparator)
expected := []int{1, 2, 3, 4, 5, 6}
asssert.Equal(expected, sortedInt)
}
func TestInsertionSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestInsertionSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := SelectionSort(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)
}
func TestSelectionSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestSelectionSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := SelectionSort(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)
}
func TestShellSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestShellSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := ShellSort(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)
}
func TestQuickSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestQuickSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := QuickSort(peoples, 0, len(peoples)-1, comparator)
t.Log(sortedPeopleByAge)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", sortedPeopleByAge)
asssert.Equal(expected, actual)
}
func TestHeapSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestHeapSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := HeapSort(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)
}
func TestMergeSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestMergeSort")
comparator := &peopleAgeComparator{}
sortedPeopleByAge := MergeSort(peoples, 0, len(peoples)-1, comparator)
t.Log(sortedPeopleByAge)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", sortedPeopleByAge)
asssert.Equal(expected, actual)
}
func TestCountSort(t *testing.T) {
asssert := internal.NewAssert(t, "TestCountSort")
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)
}

View File

@@ -21,7 +21,7 @@ func ToBool(s string) (bool, error) {
}
// ToBytes convert interface to bytes
func ToBytes(data interface{}) ([]byte, error) {
func ToBytes(data any) ([]byte, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(data)
@@ -44,59 +44,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 +113,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 +141,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 +152,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,29 +17,26 @@ 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",
@@ -49,17 +47,15 @@ func TestToBytes(t *testing.T) {
{4, 12, 0, 1, 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)
}
}
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 +63,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 +81,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 +157,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,182 @@
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)
err = link.InsertAt(0, 1)
err = link.InsertAt(1, 2)
err = link.InsertAt(2, 4)
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 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,224 @@
package datastructure
import (
"errors"
"fmt"
"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")
}
// 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,182 @@
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)
err = link.InsertAt(1, 2)
err = link.InsertAt(2, 4)
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_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{})
v, 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{})
v, 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))
}

47
datastructure/node.go Normal file
View File

@@ -0,0 +1,47 @@
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 {
Data T
Left *TreeNode[T]
Right *TreeNode[T]
}
// NewTreeNode return a TreeNode pointer
func NewTreeNode[T any](data T) *TreeNode[T] {
return &TreeNode[T]{data, nil, nil}
}

View File

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

View File

@@ -0,0 +1,90 @@
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]()
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(1, 2, 3)
val, err := queue.DeQueue()
if err != nil {
t.Fail()
}
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(1, 2, 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(1, 2, 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(1, 2, 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]()
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]()
val, 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]()
val, 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())
}

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

@@ -0,0 +1,105 @@
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
}

View File

@@ -0,0 +1,129 @@
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)
}

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]()
topItem, 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]()
topItem, 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]()
topItem, 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]()
topItem, 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,83 @@
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]
}
// NewBSTree create a BSTree pointer
func NewBSTree[T any](rootData T) *BSTree[T] {
root := datastructure.NewTreeNode(rootData)
return &BSTree[T]{root}
}
// InsertNode insert data into BSTree
func (t *BSTree[T]) InsertNode(data T, comparator lancetconstraints.Comparator) {
root := t.root
newNode := datastructure.NewTreeNode(data)
if root == nil {
t.root = newNode
} else {
insertTreeNode(root, newNode, comparator)
}
}
// DeletetNode delete data into BSTree
func (t *BSTree[T]) DeletetNode(data T, comparator lancetconstraints.Comparator) {
deleteTreeNode(t.root, data, 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)
}
// 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,142 @@
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
bstree.Print()
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
bstree := NewBSTree(6)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
bstree.Print()
bstree.DeletetNode(4, comparator)
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)
comparator := &intComparator{}
bstree.InsertNode(7, comparator)
bstree.InsertNode(5, comparator)
bstree.InsertNode(2, comparator)
bstree.InsertNode(4, comparator)
bstree.Print()
assert.Equal(bstree.Depth(), 4)
}

View File

@@ -0,0 +1,224 @@
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.Data)
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.Data)
}
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.Data)
data = append(data, inOrderTraverse(node.Right)...)
}
return data
}
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
fmt.Printf("%v, ", node.Data)
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.Data)
}
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
inOrderPrint(node.Left)
fmt.Printf("%v, ", node.Data)
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.Data)
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.Data, rootNode.Data) == -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.Data) == -1 {
node.Left = deleteTreeNode(node.Left, data, comparator)
} else if comparator.Compare(data, node.Data) == 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.Data)
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 max(a, b int) int {
if a > b {
return a
}
return b
}

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

593
docs/algorithm.md Normal file
View File

@@ -0,0 +1,593 @@
# 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
- [BubbleSort](#BubbleSort)
- [CountSort](#CountSort)
- [HeapSort](#HeapSort)
- [InsertionSort](#InsertionSort)
- [MergeSort](#MergeSort)
- [QuickSort](#QuickSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#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) []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.BubbleSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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) []T
```
<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{}
sortedPeople := algorithm.InsertionSort(peoples, comparator)
fmt.Println(sortedSlice) //[{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) []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.SelectionSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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) []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.ShellSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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) []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.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(sortedSlice) //[]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) []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.HeapSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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, 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{}
sortedSlice := algorithm.MergeSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(sortedSlice) //[]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
}
```

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

@@ -0,0 +1,593 @@
# 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>
## 目录
- [BubbleSort](#BubbleSort)
- [CountSort](#CountSort)
- [HeapSort](#HeapSort)
- [InsertionSort](#InsertionSort)
- [MergeSort](#MergeSort)
- [QuickSort](#QuickSort)
- [SelectionSort](#SelectionSort)
- [ShellSort](#ShellSort)
- [BinarySearch](#BinarySearch)
- [BinaryIterativeSearch](#BinaryIterativeSearch)
- [LinearSearch](#LinearSearch)
- [LRUCache](#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) []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.BubbleSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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) []T
```
<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{}
sortedPeople := algorithm.InsertionSort(peoples, comparator)
fmt.Println(sortedSlice) //[{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) []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.SelectionSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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) []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.ShellSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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{}
sortedSlice := algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(sortedSlice) //[]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{}
sortedSlice := algorithm.HeapSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]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, 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{}
sortedSlice := algorithm.MergeSort(intSlice, 0, len(intSlice)-1, comparator)
fmt.Println(sortedSlice) //[]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
}
```

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

669
docs/datetime.md Normal file
View File

@@ -0,0 +1,669 @@
# 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)
<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)
<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)
}
```

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

@@ -0,0 +1,668 @@
# 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)
<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)
}
```

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

233
docs/mathutil.md Normal file
View File

@@ -0,0 +1,233 @@
# 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
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <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="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
}
```

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

@@ -0,0 +1,234 @@
# 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>
## 目录
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <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="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
}
```

992
docs/slice.md Normal file
View File

@@ -0,0 +1,992 @@
# Slice
Package slice implements some functions to manipulate slice.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/slice"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
- [Compact](#Compact)
- [Concat](#Concat)
- [Count](#Count)
- [Difference](#Difference)
- [DifferenceBy](#DifferenceBy)
- [DifferenceWith](#DifferenceWith)
- [DeleteAt](#DeleteAt)
- [Drop](#Drop)
- [Every](#Every)
- [Filter](#Filter)
- [Find](#Find)
- [FindLast](#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [GroupBy](#GroupBy)
- [IntSlice](#IntSlice)
- [InterfaceSlice](#InterfaceSlice)
- [Intersection](#Intersection)
- [InsertAt](#InsertAt)
- [Map](#Map)
- [Reverse](#Reverse)
- [Reduce](#Reduce)
- [Shuffle](#Shuffle)
- [SortByField](#SortByField)
- [Some](#Some)
- [StringSlice](#StringSlice)
- [Unique](#Unique)
- [Union](#Union)
- [UpdateAt](#UpdateAt)
- [Without](#Without)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Contain">Contain</span>
<p>Check if the value is in the slice or not.</p>
<b>Signature:</b>
```go
func Contain[T any](slice []T, value T) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Contain([]string{"a", "b", "c"}, "a")
fmt.Println(res) //true
}
```
### <span id="ContainSubSlice">ContainSubSlice</span>
<p>Check if the slice contain subslice or not.</p>
<b>Signature:</b>
```go
func ContainSubSlice[T any](slice, subslice []T) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"})
fmt.Println(res) //true
}
```
### <span id="Chunk">Chunk</span>
<p>Creates an slice of elements split into groups the length of `size`.</p>
<b>Signature:</b>
```go
func Chunk[T any](slice []T, size int) [][]T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
arr := []string{"a", "b", "c", "d", "e"}
res := slice.Chunk(InterfaceSlice(arr), 3)
fmt.Println(res) //[][]any{{"a", "b", "c"}, {"d", "e"}}
}
```
### <span id="Compact">Compact</span>
<p>Creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey.</p>
<b>Signature:</b>
```go
func Compact[T any](slice []T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Compact([]int{0, 1, 2, 3})
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="Concat">Concat</span>
<p>Creates a new slice concatenating slice with any additional slices and/or values.</p>
<b>Signature:</b>
```go
func Concat[T any](slice []T, values ...[]T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.Concat([]int{1, 2, 3}, 4, 5)
fmt.Println(res1) //[]int{1, 2, 3, 4, 5}
res2 := slice.Concat([]int{1, 2, 3}, []int{4, 5})
fmt.Println(res2) //[]int{1, 2, 3, 4, 5}
}
```
### <span id="Count">Count</span>
<p>Count iterates over elements of slice, returns a count of all matched elements.</p>
<b>Signature:</b>
```go
func Count[T any](slice []T, predicate func(index int, t T) bool) int
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
evenFunc := func(i, num int) bool {
return (num % 2) == 0
}
res := slice.Count(nums, evenFunc)
fmt.Println(res) //3
}
```
### <span id="Difference">Difference</span>
<p>Creates an slice of whose element not included in the other given slice.</p>
<b>Signature:</b>
```go
func Difference[T comparable](slice, comparedSlice []T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6}
res := slice.Difference(s1, s2)
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="DifferenceBy">DifferenceBy</span>
<p>DifferenceBy accepts iteratee func which is invoked for each element of slice and values to generate the criterion by which they're compared.</p>
<b>Signature:</b>
```go
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, t T) T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6}
addOne := func(i int, v int) int {
return v + 1
}
res := slice.DifferenceBy(s1, s2, addOne)
fmt.Println(res) //[]int{1, 2}
}
```
### <span id="DifferenceWith">DifferenceWith</span>
<p>DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice.</p>
<b>Signature:</b>
```go
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value, otherValue T) bool) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6, 7, 8}
isDouble := func(v1, v2 int) bool {
return v2 == 2*v1
}
res := slice.DifferenceWith(s1, s2, isDouble)
fmt.Println(res) //[]int{1, 5}
}
```
### <span id="DeleteAt">DeleteAt</span>
<p>Delete the element of slice from start index to end index - 1.</p>
<b>Signature:</b>
```go
func DeleteAt[T any](slice []T, start int, end ...int)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.DeleteAt([]string{"a", "b", "c", "d", "e"}, 3)
fmt.Println(res1) //[]string{"a", "b", "c", "e"}
res2 := slice.DeleteAt([]string{"a", "b", "c", "d", "e"}, 0, 2)
fmt.Println(res2) //[]string{"c", "d", "e"}
}
```
### <span id="Drop">Drop</span>
<p>Creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.</p>
<b>Signature:</b>
```go
func Drop[T any](slice []T, n int) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.Drop([]int{}, 0)
fmt.Println(res1) //[]int{}
res2 := slice.Drop([]int{1, 2, 3, 4, 5}, 1)
fmt.Println(res2) //[]int{2, 3, 4, 5}
res3 := slice.Drop([]int{1, 2, 3, 4, 5}, -1)
fmt.Println(res3) //[]int{1, 2, 3, 4}
}
```
### <span id="Every">Every</span>
<p>Return true if all of the values in the slice pass the predicate function.</p>
<b>Signature:</b>
```go
func Every[T any](slice []T, predicate func(index int, t T) bool) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Every(nums, isEven)
fmt.Println(res) //false
}
```
### <span id="Filter">Filter</span>
<p>Return all elements which match the function.</p>
<b>Signature:</b>
```go
func Filter[T any](slice []T, predicate func(index int, t T) bool) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Filter(nums, isEven)
fmt.Println(res) //[]int{2, 4}
}
```
### <span id="Find">Find</span>
<p>Iterates over elements of slice, returning the first one that passes a truth test on function.</p>
<b>Signature:</b>
```go
func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res, ok := slice.Find(nums, even)
fmt.Println(res) //2
fmt.Println(ok) //true
}
```
### <span id="FindLast">FindLast</span>
<p>iterates over elements of slice from end to begin, returning the last one that passes a truth test on function.</p>
<b>Signature:</b>
```go
func FindLast[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res, ok := slice.FindLast(nums, even)
fmt.Println(res) //4
fmt.Println(ok) //true
}
```
### <span id="FlattenDeep">FlattenDeep</span>
<p>flattens slice recursive.</p>
<b>Signature:</b>
```go
func FlattenDeep(slice any) any
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
arr := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
res := slice.FlattenDeep(arr)
fmt.Println(res) //[]string{"a", "b", "c", "d"}
}
```
### <span id="ForEach">ForEach</span>
<p>Iterates over elements of slice and invokes function for each element.</p>
<b>Signature:</b>
```go
func ForEach[T any](slice []T, iteratee func(index int, t T))
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
var numbersAddTwo []int
slice.ForEach(numbers, func(index int, value int) {
numbersAddTwo = append(numbersAddTwo, value+2)
})
fmt.Println(numbersAddTwo) //[]int{3, 4, 5, 6, 7}
}
```
### <span id="GroupBy">GroupBy</span>
<p>Iterates over elements of the slice, each element will be group by criteria, returns two slices.</p>
<b>Signature:</b>
```go
func GroupBy[T any](slice []T, groupFn func(index int, t T) bool) ([]T, []T)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
evenFunc := func(i, num int) bool {
return (num % 2) == 0
}
even, odd := slice.GroupBy(nums, evenFunc)
fmt.Println(even) //[]int{2, 4, 6}
fmt.Println(odd) //]int{1, 3, 5}
}
```
### <span id="IntSlice">IntSlice</span>
<p>Convert interface slice to int slice.</p>
<b>Signature:</b>
```go
func IntSlice(slice any) []int
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var nums = []any{1, 2, 3}
res := slice.IntSlice(nums)
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="InterfaceSlice">InterfaceSlice</span>
<p>Convert value to interface slice.</p>
<b>Signature:</b>
```go
func InterfaceSlice(slice any) []any
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var nums = []int{}{1, 2, 3}
res := slice.InterfaceSlice(nums)
fmt.Println(res) //[]any{1, 2, 3}
}
```
### <span id="Intersection">Intersection</span>
<p>Creates a slice of unique values that included by all slices.</p>
<b>Signature:</b>
```go
func Intersection[T any](slices ...[]T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 2, 3}
s2 := []int{1, 2, 3, 4}
res := slice.Intersection(s1, s2),
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="InsertAt">InsertAt</span>
<p>insert the element into slice at index.</p>
<b>Signature:</b>
```go
func InsertAt[T any](slice []T, index int, value any) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s := []string{"a", "b", "c"}
res1, _ := slice.InsertAt(s, 0, "1")
fmt.Println(res1) //[]string{"1", "a", "b", "c"}
res2, _ := slice.InsertAt(s, 3, []string{"1", "2", "3"})
fmt.Println(res2) //[]string{"a", "b", "c", "1", "2", "3"}
}
```
### <span id="Map">Map</span>
<p>Creates an slice of values by running each element in slice thru function.</p>
<b>Signature:</b>
```go
func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
multiplyTwo := func(i, num int) int {
return num * 2
}
res := slice.Map(nums, multiplyTwo)
fmt.Println(res) //[]int{2, 4, 6, 8}
}
```
### <span id="Reverse">Reverse</span>
<p>Reverse the elements order in slice.</p>
<b>Signature:</b>
```go
func Reverse[T any](slice []T)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
slice.Reverse(nums)
fmt.Println(res) //[]int{4, 3, 2, 1}
}
```
### <span id="Reduce">Reduce</span>
<p>Reduce slice.</p>
<b>Signature:</b>
```go
func Reduce[T any](slice []T, iteratee func(index int, t1, t2 T) T, initial T) T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
reduceFunc := func(i, v1, v2 int) int {
return v1 + v2
}
res := slice.Reduce(nums, reduceFunc, 0)
fmt.Println(res) //10
}
```
### <span id="Shuffle">Shuffle</span>
<p>Creates an slice of shuffled values.</p>
<b>Signature:</b>
```go
func Shuffle[T any](slice []T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
res := slice.Shuffle(nums)
fmt.Println(res) //3,1,5,4,2
}
```
### <span id="SortByField">SortByField</span>
<p>Sort struct slice by field. Slice element should be struct, field type should be int, uint, string, or bool. Default sort type is ascending (asc), if descending order, set sortType to desc</p>
<b>Signature:</b>
```go
func SortByField(slice any, field string, sortType ...string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
type student struct {
name string
age int
}
students := []student{
{"a", 10},
{"b", 15},
{"c", 5},
{"d", 6},
}
err := slice.SortByField(students, "age", "desc")
if err != nil {
fmt.Println(err)
}
fmt.Println(students)
// []students{
// {"b", 15},
// {"a", 10},
// {"d", 6},
// {"c", 5},
// }
}
```
### <span id="Some">Some</span>
<p>Return true if any of the values in the list pass the predicate function.</p>
<b>Signature:</b>
```go
func Some[T any](slice []T, predicate func(index int, t T) bool) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Some(nums, isEven)
fmt.Println(res) //true
}
```
### <span id="StringSlice">StringSlice</span>
<p>Convert interface slice to string slice.</p>
<b>Signature:</b>
```go
func StringSlice(slice any) []string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var s = []any{"a", "b", "c"}
res := slice.StringSlice(s)
fmt.Println(res) //[]string{"a", "b", "c"}
}
```
### <span id="Unique">Unique</span>
<p>Remove duplicate elements in slice.</p>
<b>Signature:</b>
```go
func Unique[T any](slice []T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Unique([]int{1, 2, 2, 3})
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="Union">Unique</span>
<p>Creates a slice of unique values, in order, from all given slices. using == for equality comparisons.</p>
<b>Signature:</b>
```go
func Union[T any](slices ...[]T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 3, 4, 6}
s2 := []int{1, 2, 5, 6}
res := slice.Union(s1, s2)
fmt.Println(res) //[]int{1, 3, 4, 6, 2, 5}
}
```
### <span id="UpdateAt">UpdateAt</span>
<p>Update the slice element at index. if param index < 0 or index >= len(slice), will return error. </p>
<b>Signature:</b>
```go
func UpdateAt[T any](slice []T, index int, value T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s := []string{"a", "b", "c"}
res1, _ := slice.UpdateAt(s, 0, "1")
fmt.Println(res1) //[]string{"1", "b", "c"}
}
```
### <span id="Without">Without</span>
<p>Creates a slice excluding all given values. </p>
<b>Signature:</b>
```go
func Without[T any](slice []T, values ...T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Without([]int{1, 2, 3, 4, 5}, 1, 2)
fmt.Println(res) //[]int{3, 4, 5}
}
```

994
docs/slice_zh-CN.md Normal file
View File

@@ -0,0 +1,994 @@
# Slice
slice包包含操作切片的方法集合。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/slice"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
- [Compact](#Compact)
- [Concat](#Concat)
- [Count](#Count)
- [Difference](#Difference)
- [DifferenceBy](#DifferenceBy)
- [DifferenceWith](#DifferenceWith)
- [DeleteAt](#DeleteAt)
- [Drop](#Drop)
- [Every](#Every)
- [Filter](#Filter)
- [Find](#Find)
- [FindLast](#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [GroupBy](#GroupBy)
- [IntSlice](#IntSlice)
- [InterfaceSlice](#InterfaceSlice)
- [Intersection](#Intersection)
- [InsertAt](#InsertAt)
- [Map](#Map)
- [Reverse](#Reverse)
- [Reduce](#Reduce)
- [Shuffle](#Shuffle)
- [SortByField](#SortByField)
- [Some](#Some)
- [StringSlice](#StringSlice)
- [Unique](#Unique)
- [Union](#Union)
- [UpdateAt](#UpdateAt)
- [Without](#Without)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Contain">Contain</span>
<p>判断slice是否包含value</p>
<b>函数签名:</b>
```go
func Contain[T any](slice []T, value T) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Contain([]string{"a", "b", "c"}, "a")
fmt.Println(res) //true
}
```
### <span id="ContainSubSlice">ContainSubSlice</span>
<p>判断slice是否包含subslice</p>
<b>函数签名:</b>
```go
func ContainSubSlice[T any](slice, subslice []T) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"})
fmt.Println(res) //true
}
```
### <span id="Chunk">Chunk</span>
<p>按照size参数均分slice</p>
<b>函数签名:</b>
```go
func Chunk[T any](slice []T, size int) [][]T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
arr := []string{"a", "b", "c", "d", "e"}
res := slice.Chunk(InterfaceSlice(arr), 3)
fmt.Println(res) //[][]any{{"a", "b", "c"}, {"d", "e"}}
}
```
### <span id="Compact">Compact</span>
<p>去除slice中的假值false values are false, nil, 0, ""</p>
<b>函数签名:</b>
```go
func Compact[T any](slice []T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Compact([]int{0, 1, 2, 3})
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="Concat">Concat</span>
<p>连接values到slice中values类型可以是切片或多个值</p>
<b>函数签名:</b>
```go
func Concat[T any](slice []T, values ...[]T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.Concat([]int{1, 2, 3}, 4, 5)
fmt.Println(res1) //[]int{1, 2, 3, 4, 5}
res2 := slice.Concat([]int{1, 2, 3}, []int{4, 5})
fmt.Println(res2) //[]int{1, 2, 3, 4, 5}
}
```
### <span id="Count">Count</span>
<p>遍历切片对每个元素执行函数function. 返回符合函数返回值为true的元素的个数</p>
<b>函数签名:</b>
```go
func Count[T any](slice []T, predicate func(index int, t T) bool) int
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
evenFunc := func(i, num int) bool {
return (num % 2) == 0
}
res := slice.Count(nums, evenFunc)
fmt.Println(res) //3
}
```
### <span id="Difference">Difference</span>
<p>创建一个切片,其元素不包含在另一个给定切片中</p>
<b>函数签名:</b>
```go
func Difference[T comparable](slice, comparedSlice []T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6}
res := slice.Difference(s1, s2)
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="DifferenceBy">DifferenceBy</span>
<p>在slice和comparedSlice中的每个元素调用iteratee函数并比较它们的返回值如果不想等返回在slice中对应的值</p>
<b>函数签名:</b>
```go
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, t T) T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6}
addOne := func(i int, v int) int {
return v + 1
}
res := slice.DifferenceBy(s1, s2, addOne)
fmt.Println(res) //[]int{1, 2}
}
```
### <span id="DifferenceWith">DifferenceWith</span>
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
<b>函数签名:</b>
```go
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value, otherValue T) bool) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{4, 5, 6, 7, 8}
isDouble := func(v1, v2 int) bool {
return v2 == 2*v1
}
res := slice.DifferenceWith(s1, s2, isDouble)
fmt.Println(res) //[]int{1, 5}
}
```
### <span id="DeleteAt">DeleteAt</span>
<p>删除切片中从开始索引到结束索引-1的元素</p>
<b>函数签名:</b>
```go
func DeleteAt[T any](slice []T, start int, end ...int)
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.DeleteAt([]string{"a", "b", "c", "d", "e"}, 3)
fmt.Println(res1) //[]string{"a", "b", "c", "e"}
res2 := slice.DeleteAt([]string{"a", "b", "c", "d", "e"}, 0, 2)
fmt.Println(res2) //[]string{"c", "d", "e"}
}
```
### <span id="Drop">Drop</span>
<p>创建一个切片,当 n > 0 时从开头删除 n 个元素,或者当 n < 0 时从结尾删除 n 个元素</p>
<b>函数签名:</b>
```go
func Drop[T any](slice []T, n int) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res1 := slice.Drop([]int{}, 0)
fmt.Println(res1) //[]int{}
res2 := slice.Drop([]int{1, 2, 3, 4, 5}, 1)
fmt.Println(res2) //[]int{2, 3, 4, 5}
res3 := slice.Drop([]int{1, 2, 3, 4, 5}, -1)
fmt.Println(res3) //[]int{1, 2, 3, 4}
}
```
### <span id="Every">Every</span>
<p>如果切片中的所有值都通过谓词函数则返回true。 函数签名应该是func(index int, value any) bool</p>
<b>函数签名:</b>
```go
func Every[T any](slice []T, predicate func(index int, t T) bool) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Every(nums, isEven)
fmt.Println(res) //false
}
```
### <span id="Filter">Filter</span>
<p>返回与函数匹配的所有元素。 函数签名应该是 func(index int, value any) bool</p>
<b>函数签名:</b>
```go
func Filter[T any](slice []T, predicate func(index int, t T) bool) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Filter(nums, isEven)
fmt.Println(res) //[]int{2, 4}
}
```
### <span id="Find">Find</span>
<p>遍历slice的元素返回第一个通过function真值测试的元素</p>
<b>函数签名:</b>
```go
func Find[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res, ok := slice.Find(nums, even)
fmt.Println(res) //2
fmt.Println(ok) //true
}
```
### <span id="FindLast">FindLast</span>
<p>从头到尾遍历 slice 的元素,返回最后一个通过函数真值测试的元素。</p>
<b>函数签名:</b>
```go
func FindLast[T any](slice []T, predicate func(index int, t T) bool) (*T, bool)
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res, ok := slice.FindLast(nums, even)
fmt.Println(res) //4
fmt.Println(ok) //true
}
```
### <span id="FlattenDeep">FlattenDeep</span>
<p>flattens slice recursive.</p>
<b>函数签名:</b>
```go
func FlattenDeep(slice any) any
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
arr := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
res := slice.FlattenDeep(arr)
fmt.Println(res) //[]string{"a", "b", "c", "d"}
}
```
### <span id="ForEach">ForEach</span>
<p>遍历slice的元素并为每个元素调用函数</p>
<b>函数签名:</b>
```go
func ForEach[T any](slice []T, iteratee func(index int, t T))
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
var numbersAddTwo []int
slice.ForEach(numbers, func(index int, value int) {
numbersAddTwo = append(numbersAddTwo, value+2)
})
fmt.Println(numbersAddTwo) //[]int{3, 4, 5, 6, 7}
}
```
### <span id="GroupBy">GroupBy</span>
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
<b>函数签名:</b>
```go
func GroupBy[T any](slice []T, groupFn func(index int, t T) bool) ([]T, []T)
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
evenFunc := func(i, num int) bool {
return (num % 2) == 0
}
even, odd := slice.GroupBy(nums, evenFunc)
fmt.Println(even) //[]int{2, 4, 6}
fmt.Println(odd) //]int{1, 3, 5}
}
```
### <span id="IntSlice">IntSlice</span>
<p>将接口切片转换为int切片</p>
<b>函数签名:</b>
```go
func IntSlice(slice any) []int
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var nums = []any{1, 2, 3}
res := slice.IntSlice(nums)
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="InterfaceSlice">InterfaceSlice</span>
<p>将值转换为接口切片</p>
<b>函数签名:</b>
```go
func InterfaceSlice(slice any) []any
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var nums = []int{}{1, 2, 3}
res := slice.InterfaceSlice(nums)
fmt.Println(res) //[]any{1, 2, 3}
}
```
### <span id="Intersection">Intersection</span>
<p>多个切片的交集</p>
<b>函数签名:</b>
```go
func Intersection[T any](slices ...[]T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 2, 2, 3}
s2 := []int{1, 2, 3, 4}
res := slice.Intersection(s1, s2),
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="InsertAt">InsertAt</span>
<p>将元素插入到索引处的切片中</p>
<b>函数签名:</b>
```go
func InsertAt[T any](slice []T, index int, value any) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s := []string{"a", "b", "c"}
res1, _ := slice.InsertAt(s, 0, "1")
fmt.Println(res1) //[]string{"1", "a", "b", "c"}
res2, _ := slice.InsertAt(s, 3, []string{"1", "2", "3"})
fmt.Println(res2) //[]string{"a", "b", "c", "1", "2", "3"}
}
```
### <span id="Map">Map</span>
<p>通过运行函数slice中的每个元素来创建一个新切片</p>
<b>函数签名:</b>
```go
func Map[T any, U any](slice []T, iteratee func(index int, t T) U) []U
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
multiplyTwo := func(i, num int) int {
return num * 2
}
res := slice.Map(nums, multiplyTwo)
fmt.Println(res) //[]int{2, 4, 6, 8}
}
```
### <span id="Reverse">Reverse</span>
<p>反转切片中的元素顺序</p>
<b>函数签名:</b>
```go
func Reverse[T any](slice []T)
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
slice.Reverse(nums)
fmt.Println(res) //[]int{4, 3, 2, 1}
}
```
### <span id="Reduce">Reduce</span>
<p>将slice中的元素依次运行函数返回运行结果</p>
<b>函数签名:</b>
```go
func Reduce[T any](slice []T, iteratee func(index int, t1, t2 T) T, initial T) T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4}
reduceFunc := func(i, v1, v2 int) int {
return v1 + v2
}
res := slice.Reduce(nums, reduceFunc, 0)
fmt.Println(res) //10
}
```
### <span id="Shuffle">Shuffle</span>
<p>随机打乱切片中的元素顺序</p>
<b>函数签名:</b>
```go
func Shuffle[T any](slice []T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
res := slice.Shuffle(nums)
fmt.Println(res) //3,1,5,4,2
}
```
### <span id="SortByField">SortByField</span>
<p>按字段对结构切片进行排序。slice元素应为struct字段类型应为int、uint、string或bool。 默认排序类型是升序asc如果是降序设置 sortType 为 desc</p>
<b>函数签名:</b>
```go
func SortByField(slice any, field string, sortType ...string) error
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
type student struct {
name string
age int
}
students := []student{
{"a", 10},
{"b", 15},
{"c", 5},
{"d", 6},
}
err := slice.SortByField(students, "age", "desc")
if err != nil {
fmt.Println(err)
}
fmt.Println(students)
// []students{
// {"b", 15},
// {"a", 10},
// {"d", 6},
// {"c", 5},
// }
}
```
### <span id="Some">Some</span>
<p>如果列表中的任何值通过谓词函数则返回true</p>
<b>函数签名:</b>
```go
func Some[T any](slice []T, predicate func(index int, t T) bool) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
res := slice.Some(nums, isEven)
fmt.Println(res) //true
}
```
### <span id="StringSlice">StringSlice</span>
<p>将接口切片转换为字符串切片</p>
<b>函数签名:</b>
```go
func StringSlice(slice any) []string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
var s = []any{"a", "b", "c"}
res := slice.StringSlice(s)
fmt.Println(res) //[]string{"a", "b", "c"}
}
```
### <span id="Unique">Unique</span>
<p>删除切片中的重复元素</p>
<b>函数签名:</b>
```go
func Unique[T any](slice []T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Unique([]int{1, 2, 2, 3})
fmt.Println(res) //[]int{1, 2, 3}
}
```
### <span id="Union">Unique</span>
<p>从所有给定的切片按顺序创建一个唯一值切片。 使用 == 进行相等比较。</p>
<b>函数签名:</b>
```go
func Union[T any](slices ...[]T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s1 := []int{1, 3, 4, 6}
s2 := []int{1, 2, 5, 6}
res := slice.Union(s1, s2)
fmt.Println(res) //[]int{1, 3, 4, 6, 2, 5}
}
```
### <span id="UpdateAt">UpdateAt</span>
<p>更新索引处的切片元素。 如果 param index < 0 或 index >= len(slice),将返回错误</p>
<b>函数签名:</b>
```go
func UpdateAt[T any](slice []T, index int, value T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
s := []string{"a", "b", "c"}
res1, _ := slice.UpdateAt(s, 0, "1")
fmt.Println(res1) //[]string{"1", "b", "c"}
}
```
### <span id="Without">Without</span>
<p>创建一个不包括所有给定值的切片</p>
<b>函数签名:</b>
```go
func Without[T any](slice []T, values ...T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
res := slice.Without([]int{1, 2, 3, 4, 5}, 1, 2)
fmt.Println(res) //[]int{3, 4, 5}
}
```

574
docs/strutil.md Normal file
View File

@@ -0,0 +1,574 @@
# 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)
- [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="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) //***
}
```

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

@@ -0,0 +1,575 @@
# 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)
- [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="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">CompareOsEnv</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,11 +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
@@ -148,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,137 +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()
}
assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("../datetime/")
assert.IsNil(err)
expected := []string{"datetime.go", "datetime_test.go"}
if !reflect.DeepEqual(filesInCurrentPath, expected) {
utils.LogFailedTestInfo(t, "ToChar", "./", expected, filesInCurrentPath)
t.FailNow()
}
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")
res, _ := ReadFileToString(path)
if res != "hello world" {
utils.LogFailedTestInfo(t, "ReadFileToString", path, "hello world", res)
}
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")
CreateFile(path)
err := ClearFile(path)
assert.IsNil(err)
res, _ := ReadFileToString(path)
if res != "" {
utils.LogFailedTestInfo(t, "CreateFile", path, "", res)
}
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"}
res, _ := ReadFileByLine(path)
if !reflect.DeepEqual(res, expected) {
utils.LogFailedTestInfo(t, "ReadFileByLine", path, expected, res)
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, ""))
}

View File

@@ -2,7 +2,6 @@
// 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 (
@@ -11,23 +10,27 @@ import (
)
// After creates a function that invokes func once it's called n or more times
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
return func(args ...interface{}) []reflect.Value {
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 invokeFunc(fn, args...)
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 interface{}) func(args ...interface{}) []reflect.Value {
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 ...interface{}) []reflect.Value {
return func(args ...any) []reflect.Value {
if n > 0 {
res = invokeFunc(fn, args...)
res = unsafeInvokeFunc(fn, args...)
}
if n <= 0 {
fn = nil
@@ -37,19 +40,20 @@ func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
}
}
type Fn func(...interface{}) interface{}
// Fn is for curry function which is func(...any) any
type Fn func(...any) any
// Curry make a curryed function
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} {
return func(values ...interface{}) interface{} {
v := append([]interface{}{i}, values...)
// 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(...interface{}) interface{}) func(...interface{}) interface{} {
return func(s... interface{}) interface{} {
func Compose(fnList ...func(...any) any) func(...any) any {
return func(s ...any) any {
f := fnList[0]
restFn := fnList[1:]
@@ -61,20 +65,44 @@ func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) in
}
}
// Delay make the function execution after delayed time
func Delay(delay time.Duration, fn interface{}, args ...interface{}) {
func Delay(delay time.Duration, fn any, args ...any) {
// Catch programming error while constructing the closure
mustBeFunction(fn)
time.Sleep(delay)
invokeFunc(fn, args...)
}
// Schedule invoke function every duration time, util close the returned bool chan
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
quit := make(chan bool)
// 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 {
invokeFunc(fn, args...)
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:

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

View File

@@ -6,6 +6,8 @@ import (
"strings"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
func TestAfter(t *testing.T) {
@@ -14,7 +16,7 @@ func TestAfter(t *testing.T) {
fmt.Println("print done")
return i
})
type cb func(args ...interface{}) []reflect.Value
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)
@@ -32,15 +34,16 @@ func TestAfter(t *testing.T) {
}
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 ...interface{}) []reflect.Value
type cb func(args ...any) []reflect.Value
appendStr := func(i int, s string, fn cb) {
fmt.Printf("appendStr: arr[%d] is %s \n", i, s)
v := fn(i)
res = append(res, v[0].Int())
}
@@ -49,56 +52,74 @@ func TestBefore(t *testing.T) {
appendStr(i, arr[i], f)
}
expect := []int64{0, 1, 2, 2, 2}
if !reflect.DeepEqual(expect, res) {
t.FailNow()
}
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 ...interface{}) interface{} {
var addCurry Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
v := add1(2)
if v != 3 {
t.FailNow()
}
assert.Equal(3, add1(2))
}
func TestCompose(t *testing.T) {
toUpper := func(a ...interface{}) interface{} {
assert := internal.NewAssert(t, "TestCompose")
toUpper := func(a ...any) any {
return strings.ToUpper(a[0].(string))
}
toLower := func(a ...interface{}) interface{} {
toLower := func(a ...any) any {
return strings.ToLower(a[0].(string))
}
expect := toUpper(toLower("aBCde"))
expected := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower)
res := cf("aBCde")
if res != expect {
t.FailNow()
}
assert.Equal(expected, res)
}
func TestDelay(t *testing.T) {
var print = func(s string) {
fmt.Println(s)
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) {
fmt.Println(s)
res = append(res, s)
}
@@ -106,9 +127,6 @@ func TestSchedule(t *testing.T) {
time.Sleep(5 * time.Second)
close(stop)
expect := []string{"*", "*", "*", "*", "*"}
if !reflect.DeepEqual(expect, res) {
t.FailNow()
}
fmt.Println("done")
expected := []string{"*", "*", "*", "*", "*"}
assert.Equal(expected, res)
}

View File

@@ -1,23 +0,0 @@
package function
import (
"fmt"
"reflect"
)
func invokeFunc(fn interface{}, args ...interface{}) []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 functionValue(function interface{}) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}

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,13 @@
// 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
}

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

92
mathutil/mathutil.go Normal file
View File

@@ -0,0 +1,92 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package mathutil implements some functions for math calculation.
package mathutil
import (
"fmt"
"math"
"strconv"
"strings"
)
// Exponent calculate x^n
func Exponent(x, n int64) int64 {
if n == 0 {
return 1
}
t := Exponent(x, n/2)
if n%2 == 1 {
return t * t * x
}
return t * t
}
// Fibonacci calculate fibonacci number before n
func Fibonacci(first, second, n int) int {
if n <= 0 {
return 0
}
if n < 3 {
return 1
} else if n == 3 {
return first + second
} else {
return Fibonacci(second, first+second, n-1)
}
}
// Factorial calculate x!
func Factorial(x uint) uint {
var f uint = 1
for ; x > 1; x-- {
f *= x
}
return f
}
// Percent calculate the percentage of val to total
func Percent(val, total float64, n int) float64 {
if total == 0 {
return float64(0)
}
tmp := val / total * 100
res := RoundToFloat(tmp, n)
return res
}
// RoundToString round up to n decimal places
func RoundToString(x float64, n int) string {
tmp := math.Pow(10.0, float64(n))
x *= tmp
x = math.Round(x)
res := strconv.FormatFloat(x/tmp, 'f', n, 64)
return res
}
// RoundToFloat round up to n decimal places
func RoundToFloat(x float64, n int) float64 {
tmp := math.Pow(10.0, float64(n))
x *= tmp
x = math.Round(x)
return x / tmp
}
// TruncRound round off n decimal places
func TruncRound(x float64, n int) float64 {
floatStr := fmt.Sprintf("%."+strconv.Itoa(n+1)+"f", x)
temp := strings.Split(floatStr, ".")
var newFloat string
if len(temp) < 2 || n >= len(temp[1]) {
newFloat = floatStr
} else {
newFloat = temp[0] + "." + temp[1][:n]
}
res, _ := strconv.ParseFloat(newFloat, 64)
return res
}

72
mathutil/mathutil_test.go Normal file
View File

@@ -0,0 +1,72 @@
package mathutil
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestExponent(t *testing.T) {
assert := internal.NewAssert(t, "TestExponent")
assert.Equal(int64(1), Exponent(10, 0))
assert.Equal(int64(10), Exponent(10, 1))
assert.Equal(int64(100), Exponent(10, 2))
}
func TestFibonacci(t *testing.T) {
assert := internal.NewAssert(t, "TestFibonacci")
assert.Equal(0, Fibonacci(1, 1, 0))
assert.Equal(1, Fibonacci(1, 1, 1))
assert.Equal(1, Fibonacci(1, 1, 2))
assert.Equal(5, Fibonacci(1, 1, 5))
}
func TestFactorial(t *testing.T) {
assert := internal.NewAssert(t, "TestFactorial")
assert.Equal(uint(1), Factorial(0))
assert.Equal(uint(1), Factorial(1))
assert.Equal(uint(2), Factorial(2))
assert.Equal(uint(6), Factorial(3))
}
func TestPercent(t *testing.T) {
assert := internal.NewAssert(t, "TestPercent")
assert.Equal(float64(50), Percent(1, 2, 2))
assert.Equal(float64(33.33), Percent(0.1, 0.3, 2))
}
func TestRoundToFloat(t *testing.T) {
assert := internal.NewAssert(t, "TestRoundToFloat")
assert.Equal(RoundToFloat(0, 0), float64(0))
assert.Equal(RoundToFloat(0, 1), float64(0))
assert.Equal(RoundToFloat(0.124, 2), float64(0.12))
assert.Equal(RoundToFloat(0.125, 2), float64(0.13))
assert.Equal(RoundToFloat(0.125, 3), float64(0.125))
assert.Equal(RoundToFloat(33.33333, 2), float64(33.33))
}
func TestRoundToString(t *testing.T) {
assert := internal.NewAssert(t, "TestRoundToString")
assert.Equal(RoundToString(0, 0), "0")
assert.Equal(RoundToString(0, 1), "0.0")
assert.Equal(RoundToString(0.124, 2), "0.12")
assert.Equal(RoundToString(0.125, 2), "0.13")
assert.Equal(RoundToString(0.125, 3), "0.125")
}
func TestTruncRound(t *testing.T) {
assert := internal.NewAssert(t, "TestTruncRound")
assert.Equal(TruncRound(0, 0), float64(0))
assert.Equal(TruncRound(0, 1), float64(0))
assert.Equal(TruncRound(0.124, 2), float64(0.12))
assert.Equal(TruncRound(0.125, 2), float64(0.12))
assert.Equal(TruncRound(0.125, 3), float64(0.125))
assert.Equal(TruncRound(33.33333, 2), float64(33.33))
}

View File

@@ -6,7 +6,7 @@
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `url` is required.
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `params` is variable, the order is:
// 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]interface{},
// 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.
package netutil
@@ -21,32 +21,32 @@ import (
)
//HttpGet send get http request
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodGet, url, params...)
func HttpGet(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodGet, url, params...)
}
//HttpPost send post http request
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodPost, url, params...)
func HttpPost(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPost, url, params...)
}
//HttpPut send put http request
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodPut, url, params...)
func HttpPut(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPut, url, params...)
}
//HttpDelete send delete http request
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodDelete, url, params...)
func HttpDelete(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodDelete, url, params...)
}
// HttpPatch send patch http request
func HttpPatch(url string, params ...interface{}) (*http.Response, error) {
return request(http.MethodPatch, url, params...)
func HttpPatch(url string, params ...any) (*http.Response, error) {
return doHttpRequest(http.MethodPatch, url, params...)
}
// ParseHttpResponse decode http response to specified interface
func ParseHttpResponse(resp *http.Response, obj interface{}) error {
func ParseHttpResponse(resp *http.Response, obj any) error {
if resp == nil {
return errors.New("InvalidResp")
}
@@ -55,7 +55,7 @@ func ParseHttpResponse(resp *http.Response, obj interface{}) error {
}
// ConvertMapToQueryString convert map to sorted url query string
func ConvertMapToQueryString(param map[string]interface{}) string {
func ConvertMapToQueryString(param map[string]any) string {
if param == nil {
return ""
}

141
netutil/http_test.go Normal file
View File

@@ -0,0 +1,141 @@
package netutil
import (
"encoding/json"
"io/ioutil"
"log"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHttpGet(t *testing.T) {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestHttpPost(t *testing.T) {
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 := HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestHttpPut(t *testing.T) {
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 := HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestHttpPatch(t *testing.T) {
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 := HttpPatch(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestHttpDelete(t *testing.T) {
url := "https://jsonplaceholder.typicode.com/todos/1"
resp, err := HttpDelete(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestConvertMapToQueryString(t *testing.T) {
assert := internal.NewAssert(t, "TestConvertMapToQueryString")
var m = map[string]any{
"c": 3,
"a": 1,
"b": 2,
}
assert.Equal("a=1&b=2&c=3", ConvertMapToQueryString(m))
}
func TestParseResponse(t *testing.T) {
url := "https://jsonplaceholder.typicode.com/todos/1"
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
type Todo struct {
Id int `json:"id"`
UserId int `json:"userId"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
toDoResp := &Todo{}
err = ParseHttpResponse(resp, toDoResp)
if err != nil {
log.Fatal(err)
t.FailNow()
}
t.Log("response: ", toDoResp)
}

View File

@@ -47,6 +47,46 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
return &ip, nil
}
// GetIps return all ipv4 of system
func GetIps() []string {
var ips []string
addrs, err := net.InterfaceAddrs()
if err != nil {
return ips
}
for _, addr := range addrs {
ipNet, isValid := addr.(*net.IPNet)
if isValid && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ips = append(ips, ipNet.IP.String())
}
}
}
return ips
}
// GetMacAddrs get mac address
func GetMacAddrs() []string {
var macAddrs []string
nets, err := net.Interfaces()
if err != nil {
return macAddrs
}
for _, net := range nets {
macAddr := net.HardwareAddr.String()
if len(macAddr) == 0 {
continue
}
macAddrs = append(macAddrs, macAddr)
}
return macAddrs
}
// PublicIpInfo public ip info: country, region, isp, city, lat, lon, ip
type PublicIpInfo struct {
Status string `json:"status"`

View File

@@ -10,7 +10,7 @@ import (
"strings"
)
func request(method, reqUrl string, params ...interface{}) (*http.Response, error) {
func doHttpRequest(method, reqUrl string, params ...any) (*http.Response, error) {
if len(reqUrl) == 0 {
return nil, errors.New("url should be specified")
}
@@ -24,53 +24,29 @@ func request(method, reqUrl string, params ...interface{}) (*http.Response, erro
}
client := &http.Client{}
err := setUrl(req, reqUrl)
if err != nil {
return nil, err
}
switch len(params) {
case 0:
err := setUrl(req, reqUrl)
if err != nil {
return nil, err
}
case 1:
err := setUrl(req, reqUrl)
if err != nil {
return nil, err
}
err = setHeader(req, params[0])
if err != nil {
return nil, err
}
case 2:
err := setHeader(req, params[0])
if err != nil {
return nil, err
}
err = setQueryParam(req, reqUrl, params[1])
err := setHeaderAndQueryParam(req, reqUrl, params[0], params[1])
if err != nil {
return nil, err
}
case 3:
err := setHeader(req, params[0])
if err != nil {
return nil, err
}
err = setQueryParam(req, reqUrl, params[1])
if err != nil {
return nil, err
}
err = setBodyByte(req, params[2])
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
if err != nil {
return nil, err
}
case 4:
err := setHeader(req, params[0])
if err != nil {
return nil, err
}
err = setQueryParam(req, reqUrl, params[1])
if err != nil {
return nil, err
}
err = setBodyByte(req, params[2])
err := setHeaderAndQueryAndBody(req, reqUrl, params[0], params[1], params[2])
if err != nil {
return nil, err
}
@@ -78,14 +54,41 @@ func request(method, reqUrl string, params ...interface{}) (*http.Response, erro
if err != nil {
return nil, err
}
}
resp, e := client.Do(req)
return resp, e
}
func setHeader(req *http.Request, header interface{}) error {
func setHeaderAndQueryParam(req *http.Request, reqUrl string, header, queryParam any) error {
err := setHeader(req, header)
if err != nil {
return err
}
err = setQueryParam(req, reqUrl, queryParam)
if err != nil {
return err
}
return nil
}
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body any) error {
err := setHeader(req, header)
if err != nil {
return err
}
err = setQueryParam(req, reqUrl, queryParam)
if err != nil {
return err
}
err = setBodyByte(req, body)
if err != nil {
return err
}
return nil
}
func setHeader(req *http.Request, header any) error {
if header != nil {
switch v := header.(type) {
case map[string]string:
@@ -109,6 +112,7 @@ func setHeader(req *http.Request, header interface{}) error {
return nil
}
func setUrl(req *http.Request, reqUrl string) error {
u, err := url.Parse(reqUrl)
if err != nil {
@@ -117,11 +121,12 @@ func setUrl(req *http.Request, reqUrl string) error {
req.URL = u
return nil
}
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
func setQueryParam(req *http.Request, reqUrl string, queryParam any) error {
var values url.Values
if queryParam != nil {
switch v := queryParam.(type) {
case map[string]interface{}:
case map[string]any:
values = url.Values{}
for k := range v {
values.Set(k, fmt.Sprintf("%v", v[k]))
@@ -129,7 +134,7 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) err
case url.Values:
values = v
default:
return errors.New("query params type should be url.Values or map[string]interface{}")
return errors.New("query params type should be url.Values or map[string]any")
}
}
@@ -150,23 +155,20 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) err
return nil
}
func setBodyByte(req *http.Request, body interface{}) error {
func setBodyByte(req *http.Request, body any) error {
if body != nil {
var bodyByte []byte
if body != nil {
switch v := body.(type) {
case []byte:
bodyByte = v
default:
return errors.New("body type should be []byte")
}
switch b := body.(type) {
case []byte:
req.Body = ioutil.NopCloser(bytes.NewReader(b))
req.ContentLength = int64(len(b))
default:
return errors.New("body type should be []byte")
}
req.Body = ioutil.NopCloser(bytes.NewReader(bodyByte))
}
return nil
}
func getClient(client interface{}) (*http.Client, error) {
func getClient(client any) (*http.Client, error) {
c := http.Client{}
if client != nil {
switch v := client.(type) {

View File

@@ -1,31 +1,32 @@
package netutil
import (
"fmt"
"net"
"testing"
"github.com/duke-git/lancet/utils"
"github.com/duke-git/lancet/v2/internal"
)
func TestGetInternalIp(t *testing.T) {
assert := internal.NewAssert(t, "TestGetInternalIp")
internalIp := GetInternalIp()
ip := net.ParseIP(internalIp)
if ip == nil {
utils.LogFailedTestInfo(t, "GetInternalIp", "GetInternalIp", "", ip)
t.FailNow()
}
assert.IsNotNil(ip)
}
func TestGetPublicIpInfo(t *testing.T) {
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
publicIpInfo, err := GetPublicIpInfo()
if err != nil {
t.FailNow()
}
fmt.Printf("public ip info is: %+v \n", *publicIpInfo)
assert.IsNil(err)
t.Logf("public ip info is: %+v \n", *publicIpInfo)
}
func TestIsPublicIP(t *testing.T) {
assert := internal.NewAssert(t, "TestIsPublicIP")
ips := []net.IP{
net.ParseIP("127.0.0.1"),
net.ParseIP("192.168.0.1"),
@@ -37,11 +38,17 @@ func TestIsPublicIP(t *testing.T) {
expected := []bool{false, false, false, false, true}
for i := 0; i < len(ips); i++ {
res := IsPublicIP(ips[i])
if res != expected[i] {
utils.LogFailedTestInfo(t, "IsPublicIP", ips[i], expected[i], res)
t.FailNow()
}
actual := IsPublicIP(ips[i])
assert.Equal(expected[i], actual)
}
}
func TestGetIps(t *testing.T) {
ips := GetIps()
t.Log(ips)
}
func TestGetMacAddrs(t *testing.T) {
macAddrs := GetMacAddrs()
t.Log(macAddrs)
}

View File

@@ -1,128 +0,0 @@
package netutil
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"testing"
"github.com/duke-git/lancet/utils"
)
func TestHttpGet(t *testing.T) {
_, e := HttpGet("", nil)
if e == nil {
t.FailNow()
}
url := "https://gutendex.com/books?"
queryParams := make(map[string]interface{})
queryParams["ids"] = "1"
resp, err := HttpGet(url, nil, queryParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
func TestHttpPost(t *testing.T) {
url := "http://public-api-v1.aspirantzhang.com/users"
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
user := User{
"test",
"test@test.com",
}
bodyParams, _ := json.Marshal(user)
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
func TestHttpPut(t *testing.T) {
url := "http://public-api-v1.aspirantzhang.com/users/10420"
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
user := User{
"test",
"test@test.com",
}
bodyParams, _ := json.Marshal(user)
header := map[string]string{
"Content-Type": "application/json",
}
resp, err := HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
func TestHttpDelete(t *testing.T) {
url := "http://public-api-v1.aspirantzhang.com/users/10420"
resp, err := HttpDelete(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response: ", resp.StatusCode, string(body))
}
func TestConvertMapToQueryString(t *testing.T) {
var m = map[string]interface{}{
"c": 3,
"a": 1,
"b": 2,
}
expected := "a=1&b=2&c=3"
r := ConvertMapToQueryString(m)
if r != expected {
utils.LogFailedTestInfo(t, "ConvertMapToQueryString", m, expected, r)
t.FailNow()
}
}
func TestParseResponse(t *testing.T) {
url := "http://public-api-v1.aspirantzhang.com/users"
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
type UserResp struct {
Data []User `json:"data"`
}
resp, err := HttpGet(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
userResp := &UserResp{}
err = ParseHttpResponse(resp, userResp)
if err != nil {
log.Fatal(err)
t.FailNow()
}
fmt.Println(userResp.Data)
}

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