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

Compare commits

..

186 Commits

Author SHA1 Message Date
dudaodong
f24ad26692 release: v2.0.6 2022-05-12 10:13:13 +08:00
dudaodong
88de9bfac2 docs: add doc for SplitEx function 2022-05-12 10:12:19 +08:00
dudaodong
e4777a0986 docs: add doc for SplitEx function 2022-05-12 10:11:12 +08:00
franktz
84a69d1fa5 feat: strutil.SplitEx. Split a given string whether the result contains empty string (#31)
Co-authored-by: Frank.Town <tangzhi21@sfmail.sf-express.com>
2022-05-11 15:19:53 +08:00
dudaodong
5eb056277d update readme file 2022-04-27 11:51:02 +08:00
dudaodong
4e6d586251 update readme file 2022-04-27 11:42:06 +08:00
dudaodong
61c7012e17 test: add unit test TestBSTree_IsSubTree 2022-04-27 11:36:51 +08:00
dudaodong
0d48778886 feat: add HasSubTree func for BSTree 2022-04-27 10:43:01 +08:00
dudaodong
e98c46c903 feat: add IsSubTree func for BSTree 2022-04-27 10:36:11 +08:00
dudaodong
155f287ab0 refactor: add param comparator in NewBSTree func 2022-04-26 11:04:04 +08:00
dudaodong
652916b7d7 test: add unit test for PriorityQueue Dequeue function 2022-04-26 10:56:24 +08:00
dudaodong
955de2bdbf feat: add Dequeue function 2022-04-26 10:50:27 +08:00
dudaodong
a4c1d40faa test: add unit test for PriorityQueue Enqueue function 2022-04-26 10:45:19 +08:00
dudaodong
f155e0caa6 test: add unit test for PriorityQueue Enqueue function 2022-04-26 10:40:48 +08:00
dudaodong
fb0332449c feat: add IsEmpty and IsFull for PriorityQueue 2022-04-26 10:24:10 +08:00
dudaodong
68f0fd1d4c feat: add PriorityQueue 2022-04-26 10:19:31 +08:00
dudaodong
70995c5098 feat: add PriorityQueue 2022-04-26 10:18:43 +08:00
dudaodong
55e62ed8ca feat: add PriorityQueue 2022-04-26 10:18:06 +08:00
dudaodong
e614274f07 release v2.0.5 2022-04-24 10:34:25 +08:00
dudaodong
c524eb04a1 docs: add doc for concurrency in readme file 2022-04-24 10:32:55 +08:00
dudaodong
985b3cddd8 fix: fix TestTee func 2022-04-24 10:26:07 +08:00
dudaodong
abadeec007 docs: add doc for channel.go 2022-04-24 10:17:34 +08:00
dudaodong
3ab05154aa docs: add doc for channel.go 2022-04-22 17:12:41 +08:00
dudaodong
9f1c89bf0e refactor: refact FanIn func in channel.go 2022-04-21 14:31:43 +08:00
dudaodong
9444582e44 fix: fix OrDone func 2022-04-21 14:19:38 +08:00
dudaodong
c27ccad2b9 refactor: refact Or func in channel.go 2022-04-21 14:13:19 +08:00
dudaodong
d1c6c57700 feat: add func Bridge 2022-04-21 11:26:02 +08:00
dudaodong
922999037f feat: add func Tee 2022-04-21 11:18:45 +08:00
dudaodong
046e90486d feat: add func in channel.go 2022-04-19 16:21:23 +08:00
dudaodong
fc6dee9e77 feat: add func in channel.go 2022-04-19 16:03:12 +08:00
dudaodong
980ff2c363 feat: add FanIn for channel 2022-04-19 15:34:26 +08:00
dudaodong
763aa8e10d refactor: replace param done channel with ctx context 2022-04-19 14:42:55 +08:00
dudaodong
83c0d1d6e6 fix: fix misspellings 2022-04-15 17:02:34 +08:00
dudaodong
dfc6b868fb feat: add RepeateFn function 2022-04-15 16:32:55 +08:00
dudaodong
f66c0938e5 feat: add Take function to generate a chan of values taken from another chan 2022-04-15 16:22:19 +08:00
dudaodong
a4900fecb4 feat: add Repeate function to generate a chan of repeate values 2022-04-15 16:08:14 +08:00
dudaodong
dc25bdab2f feat: add Generate chan function in concurrency package 2022-04-15 15:56:06 +08:00
dudaodong
bb23c9eef8 release v2.0.4 2022-04-14 11:51:34 +08:00
dudaodong
b4cd0750e4 fix: fix http post to support multipart/form-data header 2022-04-14 11:48:39 +08:00
dudaodong
c960841491 docs: update sort function doc 2022-04-12 14:45:22 +08:00
dudaodong
5d6f9443fd refactor: rewrite sort function 2022-04-12 14:30:43 +08:00
dudaodong
5483380066 refactor: rewrite arrayqueue 2022-04-08 17:39:54 +08:00
dudaodong
20b9e5353e fix: fix goreport issue 2022-04-06 11:33:48 +08:00
dudaodong
1ec3a5af87 release v2.0.3 2022-04-06 10:54:54 +08:00
dudaodong
f31dde97b1 docs: add maputil docs in read me file 2022-04-05 14:24:33 +08:00
dudaodong
1718fd1cf1 docs: add doc for maputil package 2022-04-05 14:16:58 +08:00
dudaodong
513c0f829c docs: add doc for SymmetricDifference fun in slice doc 2022-04-05 13:47:13 +08:00
dudaodong
c51a806aff feat: add SymmetricDifference func for set 2022-04-01 18:06:34 +08:00
dudaodong
3c16d50c4b refactor: rename ReverseIntersect to SymmetricDifference 2022-04-01 18:05:02 +08:00
dudaodong
21dd6ab8aa feat: add SymmetricDifference func for set 2022-04-01 18:02:12 +08:00
dudaodong
f5bf5183cc feat: add Minus func for set 2022-04-01 16:48:37 +08:00
dudaodong
f28b5b2f92 feat: add Minus func for set 2022-04-01 16:44:25 +08:00
dudaodong
79867e8a63 feat: add ReverseIntersect function 2022-03-31 19:42:27 +08:00
dudaodong
19939c2b03 feat: add Minus func 2022-03-31 18:00:11 +08:00
dudaodong
bf7ffbfa8d feat: add Intersect func 2022-03-31 16:56:12 +08:00
dudaodong
cbb46f9cb4 feat: add Filter func 2022-03-30 19:52:43 +08:00
dudaodong
3ad142d5d7 feat: add ForEach func 2022-03-30 19:41:55 +08:00
dudaodong
1a436aeb41 feat: add Merge func 2022-03-30 18:06:22 +08:00
dudaodong
1af8fe8daf test: add unit test for Keys and Values func 2022-03-30 17:45:17 +08:00
dudaodong
ae54c8db6f feat: add Values func 2022-03-30 17:34:01 +08:00
dudaodong
be942ec33e feat: add package maputil and Keys func 2022-03-30 17:27:50 +08:00
dudaodong
fafb59dad6 update readme file 2022-03-29 11:02:27 +08:00
dudaodong
e36c01cac9 release v2.0.2 2022-03-29 11:01:31 +08:00
dudaodong
aa0afa8d94 release v1.2.7 2022-03-29 11:01:06 +08:00
dudaodong
18e0031e0e fix: fix TestInsertionSort 2022-03-26 21:06:05 +08:00
dudaodong
a5018c110c fix: fix bug in ToBytes func 2022-03-26 20:54:37 +08:00
dudaodong
142deb83b2 fix: fix InsertionSort bug 2022-03-26 18:25:42 +08:00
dudaodong
ccc0188352 feat: add DeleteValue for SinglyLink 2022-03-24 17:56:45 +08:00
dudaodong
98dba83107 release v2.0.1 2022-03-22 14:47:23 +08:00
dudaodong
9c6aff9030 fix: fix lint warning 'ineffassign' 2022-03-22 14:45:16 +08:00
dudaodong
7fd9a94922 fix: fix lint warning 'ineffassign' 2022-03-22 14:36:35 +08:00
dudaodong
dd3b1f3aed docs: add doc for some new funcs 2022-03-22 14:10:58 +08:00
dudaodong
f9dce592e8 docs: add doc for Min, Max, and Average 2022-03-22 10:43:00 +08:00
dudaodong
c4b0967623 feat: add Max, Min, and Average function 2022-03-22 10:26:43 +08:00
dudaodong
41613061d5 docs: add GroupWith doc 2022-03-21 20:10:39 +08:00
dudaodong
50ef63e27d feat: add GroupWith func 2022-03-21 15:29:10 +08:00
dudaodong
3ae4a35d04 fix: format timezone issue 2022-03-19 19:24:28 +08:00
dudaodong
89ea0ee15a fix: format timezone issue 2022-03-19 19:08:34 +08:00
dudaodong
85399e23ed fix: format timezone issue 2022-03-19 18:42:22 +08:00
dudaodong
19a6f218e6 fix: format time in local timezone 2022-03-19 18:23:06 +08:00
dudaodong
ccaf290b63 docs: add doc for datetime/conversion.go 2022-03-18 18:18:28 +08:00
dudaodong
54745d512c test: add unit test and func comment for time conversion 2022-03-18 17:48:57 +08:00
dudaodong
39234d4722 Merge branch 'main' of github.com:duke-git/lancet into main 2022-03-17 19:46:31 +08:00
dudaodong
4b4310265b fix: update TestListFileNames 2022-03-17 19:46:19 +08:00
wangxudong123
d8a982bf07 增加时间转换 (#25)
Co-authored-by: wangxd01 <wangxd01@mingyuanyun.com>
2022-03-17 19:44:24 +08:00
dudaodong
0334a6f02b docs: fix some issues 2022-03-17 11:55:52 +08:00
dudaodong
ae0c613b8e add package comment 2022-03-17 11:55:08 +08:00
dudaodong
40b2560752 docs: add v2 in import path 2022-03-17 11:33:45 +08:00
dudaodong
50c6e51393 upgrade go module v2 2022-03-17 10:57:35 +08:00
dudaodong
1434e00712 docs: add func HeapSort 2022-03-17 10:11:34 +08:00
dudaodong
76c941cff0 update readme file 2022-03-16 19:39:21 +08:00
dudaodong
bb03f31a8b release v2.0.0 2022-03-16 19:16:43 +08:00
dudaodong
c939b26cb8 refactor: interface{} -> any 2022-03-16 18:41:40 +08:00
dudaodong
af480efa8c docs: add xerror package doc 2022-03-16 18:21:30 +08:00
dudaodong
bc913d70b1 docs: update doc style 2022-03-16 18:06:06 +08:00
dudaodong
2bc87d8a6b docs: add docs/algorithm.md 2022-03-16 18:00:38 +08:00
dudaodong
2185c48eab docs: add docs/algorithm.md 2022-03-16 18:00:29 +08:00
dudaodong
59b5046a15 docs: update slice.md 2022-03-16 16:59:15 +08:00
dudaodong
569902b528 fix: fix lru cache bug 2022-03-14 11:19:30 +08:00
dudaodong
78519088ab feat: add lru cache 2022-03-11 17:05:55 +08:00
dudaodong
0c06cdb29f Merge branch 'main' into v2 2022-03-04 17:42:18 +08:00
dudaodong
e8b8ff8927 merge main branch 2022-03-01 15:00:02 +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
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
1dfd1ec1d3 Merge branch 'main' into v2 2022-02-19 21:55:09 +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
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
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
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
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
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
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
8868fcabed Merge branch 'main' into v2 2022-01-19 17:35:48 +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
912f7052a3 gofmt 2022-01-17 10:29:42 +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
dudaodong
d46d12f949 feat: add func ContainSubSlice 2022-01-13 11:52:21 +08:00
dudaodong
c6fc92a94c update go version to v1.18 2022-01-12 10:23:04 +08:00
dudaodong
f4fa790b72 Merge branch 'main' into v2 2022-01-12 10:05:35 +08:00
dudaodong
22798fd750 fix: fix some go report issue 2022-01-12 10:01:48 +08:00
dudaodong
907df56f86 update: make func comment consistent 2022-01-11 20:27:06 +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
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
134 changed files with 13366 additions and 16550 deletions

View File

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

1
.gitignore vendored
View File

@@ -6,5 +6,4 @@ fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
slice/testdata/*
cryptor/*.pem

774
README.md
View File

@@ -3,14 +3,13 @@
<br/>
![Go version](https://img.shields.io/badge/go-v1.16-9cf)
[![Release](https://img.shields.io/badge/release-1.3.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)
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-2.0.6-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/v1/LICENSE)
[![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>
@@ -23,15 +22,22 @@ English | [简体中文](./README_zh-CN.md)
## Feature
- 👏 Comprehensive, efficient and reusable.
- 💪 400+ go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depend on the go standard library.
- 🌍 Unit test for every exported function.
- 👏 Comprehensive, efficient and reusable.
- 💪 300+ go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depend on the go standard library.
- 🌍 Unit test for every exported function.
## 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
```
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.2.9. </b>
```go
go get github.com/duke-git/lancet@v1.2.9 // below go1.18, install latest version of v1.x.x
```
## Usage
@@ -39,454 +45,414 @@ go get github.com/duke-git/lancet
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
Here takes the string function Reverse (reverse order string) as an example, and the strutil package needs to be imported.
Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported.
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/strutil"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s := "hello"
rs := strutil.Reverse(s)
rs := strutil.ReverseStr(s)
fmt.Println(rs) //olleh
}
```
## API Documentation
### 1. Compare package provides a lightweight comparison function on any type.
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
```go
import "github.com/duke-git/lancet/compare"
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)
### 2. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
```go
import "github.com/duke-git/lancet/v2/concurrency"
```
#### Function list:
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#NewChannel)
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Bridge)
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#FanIn)
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Generate)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Or)
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#OrDone)
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Repeat)
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#RepeatFn)
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)
### 3. Convertor package contains some functions for data convertion.
```go
import "github.com/duke-git/lancet/v2/convertor"
```
#### Function list:
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
### 4. Cryptor package is for data encryption and decryption.
```go
import "github.com/duke-git/lancet/v2/cryptor"
```
#### 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)
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#Equal)
- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#EqualValue)
- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessThan)
- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterThan)
- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#LessOrEqual)
- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare.md#GreaterOrEqual)
### 5. Datetime package supports date and time format and compare.
### 2. Convertor package contains some functions for data convertion.
```go
import "github.com/duke-git/lancet/convertor"
import "github.com/duke-git/lancet/v2/datetime"
```
#### Function list:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddMinute)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#ToIso8601)
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToChar)
- [ToChannel](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToChannel)
- [ToInt](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#StructToMap)
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#EncodeByte)
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DecodeByte)
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone)
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#CopyProperties)
### 3. Cryptor package is for data encryption and decryption.
### 6. Fileutil package implements some basic functions for file operations.
```go
import "github.com/duke-git/lancet/cryptor"
```
#### Function list:
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesEcbEncrypt)
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesEcbDecrypt)
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCbcEncrypt)
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCbcDecrypt)
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCtrCrypt)
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCfbEncrypt)
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesCfbDecrypt)
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesOfbEncrypt)
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#AesOfbDecrypt)
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Base64StdEncode)
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Base64StdDecode)
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesEcbEncrypt)
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesEcbDecrypt)
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCbcEncrypt)
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCbcDecrypt)
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCtrCrypt)
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCfbEncrypt)
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesCfbDecrypt)
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbEncrypt)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacMd5)
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha1)
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256)
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha512)
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5String)
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha1)
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha256)
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#Sha512)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#RsaDecrypt)
### 4. Datetime package supports date and time format and compare.
```go
import "github.com/duke-git/lancet/datetime"
```
#### Function list:
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddMinute)
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#AddYear)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#ToIso8601)
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsLeapYear)
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BetweenSeconds)
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#DayOfYear)
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#IsWeekend)
### 5. Fileutil package implements some basic functions for file operations.
```go
import "github.com/duke-git/lancet/fileutil"
import "github.com/duke-git/lancet/v2/fileutil"
```
#### Function list
- [ClearFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ClearFile)
- [CreateFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CreateFile)
- [CreateDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CreateDir)
- [CopyFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CopyFile)
- [FileMode](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#FileMode)
- [MiMeType](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MiMeType)
- [IsExist](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsExist)
- [IsLink](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsLink)
- [IsDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsDir)
- [ListFileNames](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ListFileNames)
- [RemoveFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#RemoveFile)
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#UnZip)
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CurrentPath)
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsZipFile)
- [FileSize](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#FileSize)
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MTime)
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha)
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadCsvFile)
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteStringToFile)
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteBytesToFile)
- [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)
### 6. Formatter contains some functions for data formatting.
### 7. Formatter contains some functions for data formatting.
```go
import "github.com/duke-git/lancet/formatter"
import "github.com/duke-git/lancet/v2/formatter"
```
#### Function list:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
### 8. Function package can control the flow of function execution and support part of functional programming
```go
import "github.com/duke-git/lancet/v2/function"
```
#### 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)
### 9. Maputil package includes some functions to manipulate map.
```go
import "github.com/duke-git/lancet/v2/maputil"
```
#### Function list:
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Filter)
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Intersect)
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Keys)
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Merge)
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Minus)
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#Values)
### 10. Mathutil package implements some functions for math calculation.
```go
import "github.com/duke-git/lancet/v2/mathutil"
```
#### Function list:
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Average)
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Factorial)
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Max)
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Min)
- [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)
### 11. Netutil package contains functions to get net information and send http request.
```go
import "github.com/duke-git/lancet/v2/netutil"
```
#### Function list:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
### 12. Random package implements some basic functions to generate random int and string.
```go
import "github.com/duke-git/lancet/v2/random"
```
#### 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)
### 13. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
```go
import "github.com/duke-git/lancet/v2/retry"
```
#### Function list:
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)
### 14. Slice contains some functions to manipulate slice.
```go
import "github.com/duke-git/lancet/v2/slice"
```
#### Function list:
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceBy)
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DeleteAt)
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Every)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice.md#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupWith)
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#IntSlice)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Intersection)
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#InsertAt)
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Map)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reverse)
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#StringSlice)
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice.md#SymmetricDifference)
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Unique)
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Union)
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
### 15. Strutil package contains some functions to manipulate string.
```go
import "github.com/duke-git/lancet/v2/strutil"
```
#### Function list:
- [Comma](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#Comma)
- [Pretty](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#Pretty)
- [PrettyToWriter](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#PrettyToWriter)
- [DecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#DecimalBytes)
- [BinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#BinaryBytes)
- [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseDecimalBytes)
- [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter.md#ParseBinaryBytes)
### 7. Function package can control the flow of function execution and support part of functional programming
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#KebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReverseStr)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
### 16. System package contain some functions about os, runtime, shell command.
```go
import "github.com/duke-git/lancet/function"
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)
### 17. Validator package contains some functions for data validation.
```go
import "github.com/duke-git/lancet/v2/validator"
```
#### Function list:
- [After](https://github.com/duke-git/lancet/blob/v1/docs/function.md#After)
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Before)
- [Curry](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Curry)
- [Compose](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Compose)
- [Debounced](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Debounced)
- [Delay](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Delay)
- [Pipeline](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Pipeline)
- [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Schedule)
- [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function.md#Watcher)
### 8. Mathutil package implements some functions for math calculation.
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainChinese)
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLetter)
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainLower)
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#ContainUpper)
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAlpha)
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllUpper)
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsAllLower)
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsBase64)
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseMobile)
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChineseIdNum)
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsChinesePhone)
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsCreditCard)
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsDns)
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmail)
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsEmptyString)
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsJSON)
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsRegexMatch)
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIp)
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV4)
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIpV6)
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
### 18. xerror package implements helpers for errors.
```go
import "github.com/duke-git/lancet/mathutil"
import "github.com/duke-git/lancet/v2/xerror"
```
#### Function list:
- [Exponent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Factorial)
- [Percent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Percent)
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#TruncRound)
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#AngleToRadian)
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#RadianToAngle)
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#PointDistance)
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#IsPrime)
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#GCD)
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#LCM)
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Cos)
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Sin)
### 9. Netutil package contains functions to get net information and send http request.
```go
import "github.com/duke-git/lancet/netutil"
```
#### Function list:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#ConvertMapToQueryString)
- [EncodeUrl](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#EncodeUrl)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetPublicIpInfo)
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#ParseHttpResponse)
- [UploadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#UploadFile)
- [DownloadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#DownloadFile)
- [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsPingConnected)
- [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#IsTelnetConnected)
### 10. Random package implements some basic functions to generate random int and string.
```go
import "github.com/duke-git/lancet/random"
```
#### Function list:
- [RandBytes](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandBytes)
- [RandInt](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandString)
- [RandUpper](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUpper)
- [RandLower](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandLower)
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeral)
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeralOrLetter)
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
### 11. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
```go
import "github.com/duke-git/lancet/retry"
```
#### Function list:
- [Context](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry.md#RetryTimes)
### 12. Slice contains some functions to manipulate slice.
```go
import "github.com/duke-git/lancet/slice"
```
#### Function list:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#DifferenceBy)
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#DeleteByIndex)
- [Drop](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Every)
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Equal)
- [EqualWith](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#EqualWith)
- [Filter](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FindLast)
- [FlattenDeep](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#GroupBy)
- [IntSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#IntSlice)
- [IndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#IndexOf)
- [LastIndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#LastIndexOf)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Intersection)
- [InsertByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#InsertByIndex)
- [Map](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Map)
- [ReverseSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ReverseSlice)
- [Reduce](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#StringSlice)
- [ToSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ToSlice)
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#ToSlice)
- [Unique](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Unique)
- [UniqueBy](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UniqueBy)
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Union)
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#UpdateByIndex)
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#Without)
### 13. Strutil package contains some functions to manipulate string.
```go
import "github.com/duke-git/lancet/strutil"
```
#### Function list:
- [After](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Capitalize)
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAll)
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ContainsAny)
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#KebabCase)
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperKebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperFirst)
- [Pad](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Pad)
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#PadStart)
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SnakeCase)
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#UpperSnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Unwrap)
- [SplitWords](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitWords)
- [WordCount](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#WordCount)
- [RemoveNonPrintable](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveNonPrintable)
- [StringToBytes](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#StringToBytes)
- [BytesToString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#BytesToString)
- [IsBlank](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IsBlank)
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasPrefixAny)
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HasSuffixAny)
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#IndexOffset)
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#ReplaceWithMap)
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Trim)
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitAndTrim)
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HideString)
### 14. System package contain some functions about os, runtime, shell command.
```go
import "github.com/duke-git/lancet/system"
```
#### Function list:
- [IsWindows](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsWindows)
- [IsLinux](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsLinux)
- [IsMac](https://github.com/duke-git/lancet/blob/v1/docs/system.md#IsMac)
- [GetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#GetOsEnv)
- [SetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#SetOsEnv)
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#RemoveOsEnv)
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system.md#CompareOsEnv)
- [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system.md#ExecCommand)
- [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system.md#GetOsBits)
### 15. Validator package contains some functions for data validation.
```go
import "github.com/duke-git/lancet/validator"
```
#### Function list:
- [ContainChinese](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainChinese)
- [ContainLetter](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainLetter)
- [ContainLower](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainLower)
- [ContainUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#ContainUpper)
- [IsAlpha](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAlpha)
- [IsAllUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAllUpper)
- [IsAllLower](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsAllLower)
- [IsBase64](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsBase64)
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChineseMobile)
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChineseIdNum)
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsChinesePhone)
- [IsCreditCard](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsCreditCard)
- [IsDns](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsDns)
- [IsEmail](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsEmail)
- [IsEmptyString](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsEmptyString)
- [IsInt](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsInt)
- [IsFloat](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsFloat)
- [IsNumber](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsNumber)
- [IsIntStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIntStr)
- [IsFloatStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsFloatStr)
- [IsNumberStr](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsNumberStr)
- [IsJSON](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsJSON)
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsRegexMatch)
- [IsIp](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIp)
- [IsIpV4](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIpV4)
- [IsIpV6](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsIpV6)
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsWeakPassword)
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsZeroValue)
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsGBK)
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsASCII)
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator.md#IsPrintable)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror.md#Unwrap)
## How to Contribute

View File

@@ -3,14 +3,13 @@
<br/>
![Go version](https://img.shields.io/badge/go-v1.16-9cf)
[![Release](https://img.shields.io/badge/release-1.3.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)
![Go version](https://img.shields.io/badge/go-%3E%3D1.16<recommend>-9cf)
[![Release](https://img.shields.io/badge/release-2.0.6-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/v1/LICENSE)
[![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>
@@ -20,479 +19,449 @@
简体中文 | [English](./README.md)
## 特性
- 👏 全面、高效、可复用
- 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
- 💅 只依赖 go 标准库
- 🌍 所有导出函数单元测试覆盖率 100%
- 👏 全面、高效、可复用
- 💪 300+常用go工具函数支持string、slice、datetime、net、crypt...
- 💅 只依赖go标准库
- 🌍 所有导出函数单元测试覆盖率100%
## 安装
### Note:
1. <b>对于使用go1.18及以上的用户建议安装v2.x.x。 因为v2.x.x用go1.18的泛型重写了大部分函数。</b>
```go
go get github.com/duke-git/lancet
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
```
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.2.9。</b>
```go
go get github.com/duke-git/lancet@v1.2.9 // 使用go1.18以下版本, 必须安装v1.x.x版本
```
## 用法
lancet 是以包的结构组织代码的,使用时需要导入相应的包名。例如:如果使用字符串相关函数,需要导入 strutil 包:
lancet是以包的结构组织代码的使用时需要导入相应的包名。例如如果使用字符串相关函数需要导入strutil包:
```go
import "github.com/duke-git/lancet/strutil"
import "github.com/duke-git/lancet/v2/strutil"
```
## 例子
此处以字符串工具函数 Reverse逆序字符串为例需要导入 strutil 包:
此处以字符串工具函数ReverseStr逆序字符串为例需要导入strutil包:
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/strutil"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s := "hello"
rs := strutil.Reverse(s)
rs := strutil.ReverseStr(s)
fmt.Println(rs) //olleh
}
```
## API 文档
## API文档
### 1. algorithm算法包实现一些基本算法。eg. sort, search.
### 1. compare包提供几个轻量级的类型比较函数。
```go
import "github.com/duke-git/lancet/compare"
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)
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#Equal)
- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#EqualValue)
- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessThan)
- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterThan)
- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessOrEqual)
- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterOrEqual)
### 2. convertor转换器包支持一些常见的数据类型转换
### 2. 并发包包含一些支持并发编程的功能。例如goroutine, channel, async等
```go
import "github.com/duke-git/lancet/convertor"
import "github.com/duke-git/lancet/v2/concurrency"
```
#### Function list:
- [NewChannel](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)
- [Bridge](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Bridge)
- [FanIn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#FanIn)
- [Generate](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Generate)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Or)
- [OrDone](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#OrDone)
- [Repeat](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Repeat)
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
### 3. convertor转换器包支持一些常见的数据类型转换。
```go
import "github.com/duke-git/lancet/v2/convertor"
```
#### 函数列表:
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
### 4. cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
```go
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)
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorHexToRGB)
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorRGBToHex)
- [ToBool](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChar)
- [ToChannel](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChannel)
- [ToInt](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToJson)
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#StructToMap)
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#EncodeByte)
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DecodeByte)
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties)
### 5. datetime日期时间处理包格式化日期比较日期。
### 3. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
```go
import "github.com/duke-git/lancet/cryptor"
import "github.com/duke-git/lancet/v2/datetime"
```
#### 函数列表:
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbEncrypt)
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbDecrypt)
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcEncrypt)
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcDecrypt)
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCtrCrypt)
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbEncrypt)
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbDecrypt)
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbEncrypt)
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbDecrypt)
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdEncode)
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdDecode)
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbEncrypt)
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbDecrypt)
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcEncrypt)
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcDecrypt)
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCtrCrypt)
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbEncrypt)
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbDecrypt)
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbEncrypt)
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbDecrypt)
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5)
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1)
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha256)
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512)
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5String)
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5File)
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1)
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256)
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512)
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKey)
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecrypt)
### 4. datetime 日期时间处理包,格式化日期,比较日期。
### 6. fileutil包支持文件基本操作。
```go
import "github.com/duke-git/lancet/datetime"
```
#### 函数列表:
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddDay)
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddHour)
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddMinute)
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddYear)
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfWeek)
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMonth)
- [BeginOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfYear)
- [EndOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMinute)
- [EndOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfHour)
- [EndOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfDay)
- [EndOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfWeek)
- [EndOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMonth)
- [EndOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfYear)
- [GetNowDate](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDate)
- [GetNowTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowTime)
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDateTime)
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNightTimestamp)
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatTimeToStr)
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatStrToTime)
- [NewUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnix)
- [NewUnixNow](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnixNow)
- [NewFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewFormat)
- [NewISO8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewISO8601)
- [ToUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToUnix)
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormat)
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormatForTpl)
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToIso8601)
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsLeapYear)
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#BetweenSeconds)
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#DayOfYear)
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsWeekend)
### 5. fileutil 包支持文件基本操作。
```go
import "github.com/duke-git/lancet/fileutil"
import "github.com/duke-git/lancet/v2/fileutil"
```
#### 函数列表:
- [ClearFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ClearFile)
- [CreateFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateFile)
- [CreateDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateDir)
- [CopyFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CopyFile)
- [FileMode](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileMode)
- [MiMeType](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MiMeType)
- [IsExist](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsExist)
- [IsLink](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsLink)
- [IsDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsDir)
- [ListFileNames](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ListFileNames)
- [RemoveFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#RemoveFile)
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileToString)
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileByLine)
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#UnZip)
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CurrentPath)
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsZipFile)
- [FileSize](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileSize)
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MTime)
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile)
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteStringToFile)
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteBytesToFile)
- [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)
### 6. formatter 格式化器包含一些数据格式化处理方法。
### 7. formatter格式化器包含一些数据格式化处理方法。
```go
import "github.com/duke-git/lancet/formatter"
import "github.com/duke-git/lancet/v2/formatter"
```
#### 函数列表:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
### 8. function函数包控制函数执行流程包含部分函数式编程。
```go
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)
- [Comma](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Comma)
- [Pretty](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Pretty)
- [PrettyToWriter](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#PrettyToWriter)
- [DecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#DecimalBytes)
- [BinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#BinaryBytes)
- [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseDecimalBytes)
- [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseBinaryBytes)
### 7. function 函数包控制函数执行流程,包含部分函数式编程。
### 9. maputil包包括一些操作map的函数.
```go
import "github.com/duke-git/lancet/function"
import "github.com/duke-git/lancet/v2/maputil"
```
#### 函数列表:
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
- [After](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#After)
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Before)
- [Curry](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Curry)
- [Compose](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Compose)
- [Debounced](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Debounced)
- [Delay](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Delay)
- [Pipeline](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Pipeline)
- [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Schedule)
- [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Watcher)
### 8. mathutil 包实现了一些数学计算的函数。
### 10. mathutil包实现了一些数学计算的函数。
```go
import "github.com/duke-git/lancet/mathutil"
import "github.com/duke-git/lancet/v2/mathutil"
```
#### Function list:
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)
- [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)
- [Exponent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Exponent)
- [Fibonacci](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Fibonacci)
- [Factorial](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Factorial)
- [Percent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Percent)
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToFloat)
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#TruncRound)
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#AngleToRadian)
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RadianToAngle)
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance)
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#IsPrime)
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#GCD)
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#LCM)
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Cos)
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Sin)
### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。
### 11. netutil网络包支持获取ip地址发送http请求。
```go
import "github.com/duke-git/lancet/netutil"
import "github.com/duke-git/lancet/v2/netutil"
```
#### 函数列表:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
### 12. random随机数生成器包可以生成随机[]bytes, int, string。
```go
import "github.com/duke-git/lancet/v2/random"
```
#### 函数列表:
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
### 13. retry重试执行函数直到函数运行成功或被context cancel。
```go
import "github.com/duke-git/lancet/v2/retry"
```
#### 函数列表:
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
### 14. slice包包含操作切片的方法集合。
```go
import "github.com/duke-git/lancet/v2/slice"
```
#### 函数列表:
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)
- [FlattenDeep](#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SymmetricDifference)
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateAt)
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
### 15. strutil包含处理字符串的相关函数。
```go
import "github.com/duke-git/lancet/v2/strutil"
```
#### 函数列表:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ConvertMapToQueryString)
- [EncodeUrl](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#EncodeUrl)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetPublicIpInfo)
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ParseHttpResponse)
- [UploadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#UploadFile)
- [DownloadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#DownloadFile)
- [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPingConnected)
- [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsTelnetConnected)
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
### 10. random 随机数生成器包,可以生成随机[]bytes, int, string
### 16. system包含os, runtime, shell command相关函数
```go
import "github.com/duke-git/lancet/random"
import "github.com/duke-git/lancet/v2/system"
```
#### 函数列表:
- [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)
- [RandBytes](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandBytes)
- [RandInt](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandString)
- [RandUpper](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandUpper)
- [RandLower](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandLower)
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeral)
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter)
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
### 11. retry 重试执行函数直到函数运行成功或被 context cancel。
### 17. validator验证器包包含常用字符串格式验证函数。
```go
import "github.com/duke-git/lancet/retry"
import "github.com/duke-git/lancet/v2/validator"
```
#### 函数列表:
- [Context](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Context)
- [Retry](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Retry)
- [RetryFunc](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryFunc)
- [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryTimes)
- [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)
### 12. slice 包包含操作切片的方法集合。
validator.md#IsWeakPassword)
### 18. xerror包实现一些错误处理函数
```go
import "github.com/duke-git/lancet/slice"
import "github.com/duke-git/lancet/v2/xerror"
```
#### 函数列表:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Chunk)
- [Compact](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Compact)
- [Concat](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Concat)
- [Count](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Count)
- [Difference](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Difference)
- [DifferenceBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DifferenceBy)
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DeleteByIndex)
- [Drop](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Drop)
- [Every](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Every)
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Equal)
- [EqualWith](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#EqualWith)
- [Filter](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Filter)
- [Find](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Find)
- [FindLast](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#FindLast)
- [FlattenDeep](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FlattenDeep)
- [ForEach](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ForEach)
- [GroupBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#GroupBy)
- [IntSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IntSlice)
- [IndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IndexOf)
- [LastIndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#LastIndexOf)
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InterfaceSlice)
- [Intersection](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Intersection)
- [InsertByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InsertByIndex)
- [Map](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Map)
- [ReverseSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ReverseSlice)
- [Reduce](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Reduce)
- [Shuffle](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Shuffle)
- [SortByField](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#SortByField)
- [Some](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Some)
- [StringSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#StringSlice)
- [ToSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
- [Unique](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Unique)
- [UniqueBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UniqueBy)
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Union)
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UpdateByIndex)
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Without)
### 13. strutil 包含处理字符串的相关函数。
```go
import "github.com/duke-git/lancet/strutil"
```
#### 函数列表:
- [After](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#After)
- [AfterLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#AfterLast)
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Before)
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BeforeLast)
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#CamelCase)
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Capitalize)
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAll)
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAny)
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsString)
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#KebabCase)
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperKebabCase)
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#LowerFirst)
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperFirst)
- [Pad](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Pad)
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadStart)
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SnakeCase)
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperSnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Unwrap)
- [SplitWords](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitWords)
- [WordCount](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#WordCount)
- [RemoveNonPrintable](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveNonPrintable)
- [StringToBytes](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#StringToBytes)
- [BytesToString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BytesToString)
- [IsBlank](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsBlank)
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasPrefixAny)
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasSuffixAny)
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IndexOffset)
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ReplaceWithMap)
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Trim)
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HideString)
### 14. system 包含 os, runtime, shell command 相关函数。
```go
import "github.com/duke-git/lancet/system"
```
#### 函数列表:
- [IsWindows](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsWindows)
- [IsLinux](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsLinux)
- [IsMac](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsMac)
- [GetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsEnv)
- [SetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#SetOsEnv)
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#RemoveOsEnv)
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#CompareOsEnv)
- [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#ExecCommand)
- [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsBits)
### 15. validator 验证器包,包含常用字符串格式验证函数。
```go
import "github.com/duke-git/lancet/validator"
```
#### 函数列表:
- [ContainChinese](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainChinese)
- [ContainLetter](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLetter)
- [ContainLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLower)
- [ContainUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainUpper)
- [IsAlpha](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAlpha)
- [IsAllUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllUpper)
- [IsAllLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllLower)
- [IsBase64](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64)
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseMobile)
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseIdNum)
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinesePhone)
- [IsCreditCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsCreditCard)
- [IsDns](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsDns)
- [IsEmail](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmail)
- [IsEmptyString](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmptyString)
- [IsInt](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsInt)
- [IsFloat](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloat)
- [IsNumber](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumber)
- [IsIntStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIntStr)
- [IsFloatStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloatStr)
- [IsNumberStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumberStr)
- [IsJSON](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJSON)
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsRegexMatch)
- [IsIp](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIp)
- [IsIpV4](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV4)
- [IsIpV6](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV6)
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsWeakPassword)
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsZeroValue)
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsGBK)
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsASCII)
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsPrintable)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)
## 如何贡献代码
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
非常感激任何的代码提交以使lancet的功能越来越强大。创建pull request时请遵守以下规则。
1. Fork lancet 仓库。
1. Fork lancet仓库。
2. 创建自己的特性分支。
3. 提交变更。
4. Push 分支。
5. 创建新的 pull request。
4. Push分支。
5. 创建新的pull request。

102
algorithm/lru_cache.go Normal file
View File

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

View File

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

63
algorithm/search.go Normal file
View File

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

33
algorithm/search_test.go Normal file
View File

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

188
algorithm/sorter.go Normal file
View File

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

218
algorithm/sorter_test.go Normal file
View File

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

View File

@@ -1,58 +0,0 @@
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
// Use of this source code is governed by MIT license
// Package compare provides a lightweight comparison function on interface{} type.
// reference: https://github.com/stretchr/testify
package compare
import (
"reflect"
"time"
"github.com/duke-git/lancet/convertor"
)
// operator type
const (
equal = "eq"
lessThan = "lt"
greaterThan = "gt"
lessOrEqual = "le"
greaterOrEqual = "ge"
)
var (
timeType = reflect.TypeOf(time.Time{})
bytesType = reflect.TypeOf([]byte{})
)
// Equal checks if two values are equal or not. (check both type and value)
func Equal(left, right interface{}) bool {
return compareValue(equal, left, right)
}
// EqualValue checks if two values are equal or not. (check value only)
func EqualValue(left, right interface{}) bool {
ls, rs := convertor.ToString(left), convertor.ToString(right)
return ls == rs
}
// LessThan checks if value `left` less than value `right`.
func LessThan(left, right interface{}) bool {
return compareValue(lessThan, left, right)
}
// GreaterThan checks if value `left` greater than value `right`.
func GreaterThan(left, right interface{}) bool {
return compareValue(greaterThan, left, right)
}
// LessOrEqual checks if value `left` less than or equal to value `right`.
func LessOrEqual(left, right interface{}) bool {
return compareValue(lessOrEqual, left, right)
}
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
func GreaterOrEqual(left, right interface{}) bool {
return compareValue(greaterOrEqual, left, right)
}

View File

@@ -1,170 +0,0 @@
package compare
import (
"fmt"
"time"
)
func ExampleEqual() {
result1 := Equal(1, 1)
result2 := Equal("1", "1")
result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3})
result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
result5 := Equal(1, "1")
result6 := Equal(1, int64(1))
result7 := Equal([]int{1, 2}, []int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
func ExampleEqualValue() {
result1 := EqualValue(1, 1)
result2 := EqualValue(int(1), int64(1))
result3 := EqualValue(1, "1")
result4 := EqualValue(1, "2")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
func ExampleLessThan() {
result1 := LessThan(1, 2)
result2 := LessThan(1.1, 2.2)
result3 := LessThan("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := LessThan(time1, time2)
result5 := LessThan(2, 1)
result6 := LessThan(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
func ExampleGreaterThan() {
result1 := GreaterThan(2, 1)
result2 := GreaterThan(2.2, 1.1)
result3 := GreaterThan("b", "a")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := GreaterThan(time2, time1)
result5 := GreaterThan(1, 2)
result6 := GreaterThan(int64(2), 1)
result7 := GreaterThan("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
func ExampleLessOrEqual() {
result1 := LessOrEqual(1, 1)
result2 := LessOrEqual(1.1, 2.2)
result3 := LessOrEqual("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := LessOrEqual(time1, time2)
result5 := LessOrEqual(2, 1)
result6 := LessOrEqual(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
func ExampleGreaterOrEqual() {
result1 := GreaterOrEqual(1, 1)
result2 := GreaterOrEqual(2.2, 1.1)
result3 := GreaterOrEqual("b", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := GreaterOrEqual(time2, time1)
result5 := GreaterOrEqual(1, 2)
result6 := GreaterOrEqual(int64(2), 1)
result7 := GreaterOrEqual("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}

View File

@@ -1,323 +0,0 @@
package compare
import (
"bytes"
"encoding/json"
"reflect"
"time"
"github.com/duke-git/lancet/convertor"
)
func compareValue(operator string, left, right interface{}) bool {
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
if leftType.Kind() != rightType.Kind() {
return false
}
switch leftType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
return compareBasicValue(operator, left, right)
case reflect.Struct, reflect.Slice, reflect.Map:
return compareRefValue(operator, left, right, leftType.Kind())
}
return false
}
func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflect.Kind) bool {
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
switch kind {
case reflect.Struct:
// compare time
if leftVal.CanConvert(timeType) {
timeObj1, ok := leftObj.(time.Time)
if !ok {
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
}
timeObj2, ok := rightObj.(time.Time)
if !ok {
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
}
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
}
// for other struct type, only process equal operator
switch operator {
case equal:
return objectsAreEqualValues(leftObj, rightObj)
}
case reflect.Slice:
// compare []byte
if leftVal.CanConvert(bytesType) {
bytesObj1, ok := leftObj.([]byte)
if !ok {
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
}
bytesObj2, ok := rightObj.([]byte)
if !ok {
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
}
switch operator {
case equal:
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
return true
}
case lessThan:
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
return true
}
case greaterThan:
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
return true
}
case lessOrEqual:
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
return true
}
case greaterOrEqual:
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
return true
}
}
}
// for other type slice, only process equal operator
switch operator {
case equal:
return reflect.DeepEqual(leftObj, rightObj)
}
case reflect.Map:
// only process equal operator
switch operator {
case equal:
return reflect.DeepEqual(leftObj, rightObj)
}
}
return false
}
func objectsAreEqualValues(expected, actual interface{}) bool {
if objectsAreEqual(expected, actual) {
return true
}
actualType := reflect.TypeOf(actual)
if actualType == nil {
return false
}
expectedValue := reflect.ValueOf(expected)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
}
return false
}
func objectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
// compareBasic compare basic value: integer, float, string, bool
func compareBasicValue(operator string, leftValue, rightValue interface{}) bool {
if leftValue == nil && rightValue == nil && operator == equal {
return true
}
switch leftVal := leftValue.(type) {
case json.Number:
if left, err := leftVal.Float64(); err == nil {
switch rightVal := rightValue.(type) {
case json.Number:
if right, err := rightVal.Float64(); err == nil {
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
right, err := convertor.ToFloat(rightValue)
if err != nil {
return false
}
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
left, err := convertor.ToFloat(leftValue)
if err != nil {
return false
}
switch rightVal := rightValue.(type) {
case json.Number:
if right, err := rightVal.Float64(); err == nil {
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
right, err := convertor.ToFloat(rightValue)
if err != nil {
return false
}
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case string:
left := leftVal
switch right := rightValue.(type) {
case string:
switch operator {
case equal:
if left == right {
return true
}
case lessThan:
if left < right {
return true
}
case greaterThan:
if left > right {
return true
}
case lessOrEqual:
if left <= right {
return true
}
case greaterOrEqual:
if left >= right {
return true
}
}
}
case bool:
left := leftVal
switch right := rightValue.(type) {
case bool:
switch operator {
case equal:
if left == right {
return true
}
}
}
}
return false
}

View File

@@ -1,134 +0,0 @@
package compare
import (
"testing"
"time"
"github.com/duke-git/lancet/internal"
)
func TestEqual(t *testing.T) {
assert := internal.NewAssert(t, "TestEqual")
assert.Equal(true, Equal(1, 1))
assert.Equal(true, Equal(int64(1), int64(1)))
assert.Equal(true, Equal("a", "a"))
assert.Equal(true, Equal(true, true))
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
assert.Equal(false, Equal(1, 2))
assert.Equal(false, Equal(1, int64(1)))
assert.Equal(false, Equal("a", "b"))
assert.Equal(false, Equal(true, false))
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
time1 := time.Now()
time2 := time1.Add(time.Second)
time3 := time1.Add(time.Second)
assert.Equal(false, Equal(time1, time2))
assert.Equal(true, Equal(time2, time3))
st1 := struct {
A string
B string
}{
A: "a",
B: "b",
}
st2 := struct {
A string
B string
}{
A: "a",
B: "b",
}
st3 := struct {
A string
B string
}{
A: "a1",
B: "b",
}
assert.Equal(true, Equal(st1, st2))
assert.Equal(false, Equal(st1, st3))
}
func TestEqualValue(t *testing.T) {
assert := internal.NewAssert(t, "TestEqualValue")
assert.Equal(true, EqualValue(1, 1))
assert.Equal(true, EqualValue(int(1), int64(1)))
assert.Equal(true, EqualValue(1, "1"))
assert.Equal(false, EqualValue(1, "2"))
}
func TestLessThan(t *testing.T) {
assert := internal.NewAssert(t, "TestLessThan")
assert.Equal(true, LessThan(1, 2))
assert.Equal(true, LessThan(1.1, 2.2))
assert.Equal(true, LessThan("a", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, LessThan(time1, time2))
assert.Equal(false, LessThan(1, 1))
assert.Equal(false, LessThan(1, int64(1)))
}
func TestGreaterThan(t *testing.T) {
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterThan(2, 1))
assert.Equal(true, GreaterThan(2.2, 1.1))
assert.Equal(true, GreaterThan("b", "a"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, GreaterThan(time2, time1))
assert.Equal(false, GreaterThan(1, 2))
assert.Equal(false, GreaterThan(int64(2), 1))
assert.Equal(false, GreaterThan("b", "c"))
}
func TestLessOrEqual(t *testing.T) {
assert := internal.NewAssert(t, "TestLessOrEqual")
assert.Equal(true, LessOrEqual(1, 2))
assert.Equal(true, LessOrEqual(1, 1))
assert.Equal(true, LessOrEqual(1.1, 2.2))
assert.Equal(true, LessOrEqual("a", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, LessOrEqual(time1, time2))
assert.Equal(false, LessOrEqual(2, 1))
assert.Equal(false, LessOrEqual(1, int64(2)))
}
func TestGreaterOrEqual(t *testing.T) {
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterOrEqual(2, 1))
assert.Equal(true, GreaterOrEqual(1, 1))
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
assert.Equal(true, GreaterOrEqual("b", "b"))
time1 := time.Now()
time2 := time1.Add(time.Second)
assert.Equal(true, GreaterOrEqual(time2, time1))
assert.Equal(false, GreaterOrEqual(1, 2))
assert.Equal(false, GreaterOrEqual(int64(2), 1))
assert.Equal(false, GreaterOrEqual("b", "c"))
}

243
concurrency/channel.go Normal file
View File

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

206
concurrency/channel_test.go Normal file
View File

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

View File

@@ -7,9 +7,7 @@ package convertor
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"math"
"reflect"
@@ -24,7 +22,7 @@ func ToBool(s string) (bool, error) {
}
// ToBytes convert interface to bytes
func ToBytes(value interface{}) ([]byte, error) {
func ToBytes(value any) ([]byte, error) {
v := reflect.ValueOf(value)
switch value.(type) {
@@ -77,7 +75,7 @@ func ToChar(s string) []string {
}
// ToString convert value to string
func ToString(value interface{}) string {
func ToString(value any) string {
res := ""
if value == nil {
return res
@@ -109,7 +107,7 @@ func ToString(value interface{}) string {
}
// 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 {
return "", err
@@ -119,7 +117,7 @@ func ToJson(value interface{}) (string, error) {
}
// 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
@@ -146,7 +144,7 @@ func ToFloat(value interface{}) (float64, error) {
}
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
func ToInt(value interface{}) (int64, error) {
func ToInt(value any) (int64, error) {
v := reflect.ValueOf(value)
var res int64
@@ -174,7 +172,7 @@ func ToInt(value interface{}) (int64, error) {
// StructToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value
func StructToMap(value interface{}) (map[string]interface{}, error) {
func StructToMap(value any) (map[string]any, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
@@ -185,7 +183,7 @@ func StructToMap(value interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
}
res := make(map[string]interface{})
res := make(map[string]any)
fieldNum := t.NumField()
pattern := `^[A-Z]`
@@ -231,146 +229,3 @@ func ColorRGBToHex(red, green, blue int) string {
return "#" + r + g + b
}
// ToChannel convert a array of elements to a read-only channels
func ToChannel(array []interface{}) <-chan interface{} {
ch := make(chan interface{})
go func() {
for _, item := range array {
ch <- item
}
close(ch)
}()
return ch
}
// EncodeByte encode data to byte
func EncodeByte(data interface{}) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(data)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// DecodeByte decode byte data to target object
func DecodeByte(data []byte, target interface{}) error {
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
return decoder.Decode(target)
}
// DeepClone creates a deep copy of passed item.
// can't clone unexported field of struct
func DeepClone(src interface{}) interface{} {
c := cloner{
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
}
result := c.clone(reflect.ValueOf(src))
if result.Kind() == reflect.Invalid {
return nil
}
return result.Interface()
}
// // CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// func CopyProperties(dst, src interface{}) (err error) {
// defer func() {
// if e := recover(); e != nil {
// err = errors.New(fmt.Sprintf("%v", e))
// }
// }()
// dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
// srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
// if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
// return errors.New("CopyProperties: param dst should be struct pointer")
// }
// if srcType.Kind() == reflect.Ptr {
// srcType, srcValue = srcType.Elem(), srcValue.Elem()
// }
// if srcType.Kind() != reflect.Struct {
// return errors.New("CopyProperties: param src should be a struct or struct pointer")
// }
// dstType, dstValue = dstType.Elem(), dstValue.Elem()
// propertyNums := dstType.NumField()
// for i := 0; i < propertyNums; i++ {
// property := dstType.Field(i)
// propertyValue := srcValue.FieldByName(property.Name)
// if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
// continue
// }
// if dstValue.Field(i).CanSet() {
// dstValue.Field(i).Set(propertyValue)
// }
// }
// return nil
// }
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
func CopyProperties(dst, src interface{}) error {
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("CopyProperties: parameter dst should be struct pointer")
}
if srcType.Kind() == reflect.Ptr {
srcType = srcType.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
}
bytes, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
}
err = json.Unmarshal(bytes, dst)
if err != nil {
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
}
return nil
}
// ToInterface converts reflect value to its interface type.
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
if v.IsValid() && v.CanInterface() {
return v.Interface(), true
}
switch v.Kind() {
case reflect.Bool:
return v.Bool(), true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int(), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint(), true
case reflect.Float32, reflect.Float64:
return v.Float(), true
case reflect.Complex64, reflect.Complex128:
return v.Complex(), true
case reflect.String:
return v.String(), true
case reflect.Ptr:
return ToInterface(v.Elem())
case reflect.Interface:
return ToInterface(v.Elem())
default:
return nil, false
}
}

View File

@@ -1,216 +0,0 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package convertor implements some functions to convert data.
package convertor
import "reflect"
type cloner struct {
ptrs map[reflect.Type]map[uintptr]reflect.Value
}
// clone return a duplicate of passed item.
func (c *cloner) clone(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Invalid:
return reflect.ValueOf(nil)
// bool
case reflect.Bool:
return reflect.ValueOf(v.Bool())
//int
case reflect.Int:
return reflect.ValueOf(int(v.Int()))
case reflect.Int8:
return reflect.ValueOf(int8(v.Int()))
case reflect.Int16:
return reflect.ValueOf(int16(v.Int()))
case reflect.Int32:
return reflect.ValueOf(int32(v.Int()))
case reflect.Int64:
return reflect.ValueOf(v.Int())
// uint
case reflect.Uint:
return reflect.ValueOf(uint(v.Uint()))
case reflect.Uint8:
return reflect.ValueOf(uint8(v.Uint()))
case reflect.Uint16:
return reflect.ValueOf(uint16(v.Uint()))
case reflect.Uint32:
return reflect.ValueOf(uint32(v.Uint()))
case reflect.Uint64:
return reflect.ValueOf(v.Uint())
// float
case reflect.Float32:
return reflect.ValueOf(float32(v.Float()))
case reflect.Float64:
return reflect.ValueOf(v.Float())
// complex
case reflect.Complex64:
return reflect.ValueOf(complex64(v.Complex()))
case reflect.Complex128:
return reflect.ValueOf(v.Complex())
// string
case reflect.String:
return reflect.ValueOf(v.String())
// array
case reflect.Array, reflect.Slice:
return c.cloneArray(v)
// map
case reflect.Map:
return c.cloneMap(v)
// Ptr
case reflect.Ptr:
return c.clonePtr(v)
// struct
case reflect.Struct:
return c.cloneStruct(v)
// func
case reflect.Func:
return v
// interface
case reflect.Interface:
return c.clone(v.Elem())
}
return reflect.Zero(v.Type())
}
func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
arr := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
val := c.clone(v.Index(i))
if val.IsValid() {
continue
}
item := arr.Index(i)
if !item.CanSet() {
continue
}
item.Set(val.Convert(item.Type()))
}
return arr
}
func (c *cloner) cloneMap(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
clonedMap := reflect.MakeMap(v.Type())
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
clonedKey := c.clone(key)
clonedValue := c.clone(value)
if !isNillable(clonedKey) || !clonedKey.IsNil() {
clonedKey = clonedKey.Convert(key.Type())
}
if (!isNillable(clonedValue) || !clonedValue.IsNil()) && clonedValue.IsValid() {
clonedValue = clonedValue.Convert(value.Type())
}
if !clonedValue.IsValid() {
clonedValue = reflect.Zero(clonedMap.Type().Elem())
}
clonedMap.SetMapIndex(clonedKey, clonedValue)
}
return clonedMap
}
func isNillable(v reflect.Value) bool {
switch v.Kind() {
case reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func:
return true
}
return false
}
func (c *cloner) clonePtr(v reflect.Value) reflect.Value {
if v.IsNil() {
return reflect.Zero(v.Type())
}
var newVal reflect.Value
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
newVal = c.clone(v.Elem())
if v.Elem().CanAddr() {
ptrs, exists := c.ptrs[v.Type()]
if exists {
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
return newVal
}
}
}
clonedPtr := reflect.New(newVal.Type())
clonedPtr.Elem().Set(newVal)
return clonedPtr
}
func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
clonedStructPtr := reflect.New(v.Type())
clonedStruct := clonedStructPtr.Elem()
if v.CanAddr() {
ptrs := c.ptrs[clonedStructPtr.Type()]
if ptrs == nil {
ptrs = make(map[uintptr]reflect.Value)
c.ptrs[clonedStructPtr.Type()] = ptrs
}
ptrs[v.UnsafeAddr()] = clonedStructPtr
}
for i := 0; i < v.NumField(); i++ {
newStructValue := clonedStruct.Field(i)
if !newStructValue.CanSet() {
continue
}
clonedVal := c.clone(v.Field(i))
if !clonedVal.IsValid() {
continue
}
newStructValue.Set(clonedVal.Convert(newStructValue.Type()))
}
return clonedStruct
}

View File

@@ -2,10 +2,9 @@ package convertor
import (
"fmt"
"reflect"
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestToChar(t *testing.T) {
@@ -37,7 +36,7 @@ func TestToBool(t *testing.T) {
func TestToBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestToBytes")
cases := []interface{}{
cases := []any{
0,
false,
"1",
@@ -63,7 +62,7 @@ func TestToBytes(t *testing.T) {
func TestToInt(t *testing.T) {
assert := internal.NewAssert(t, "TestToInt")
cases := []interface{}{"123", "-123", 123,
cases := []any{"123", "-123", 123,
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
float32(12.3), float64(12.3),
"abc", false, "111111111111111111111111111111111111111"}
@@ -79,7 +78,7 @@ func TestToInt(t *testing.T) {
func TestToFloat(t *testing.T) {
assert := internal.NewAssert(t, "TestToFloat")
cases := []interface{}{
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),
@@ -107,7 +106,7 @@ func TestToString(t *testing.T) {
}
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),
@@ -155,7 +154,7 @@ func TestStructToMap(t *testing.T) {
100,
}
pm, _ := StructToMap(p)
var expected = map[string]interface{}{"name": "test"}
var expected = map[string]any{"name": "test"}
assert.Equal(expected, pm)
}
@@ -179,163 +178,3 @@ func TestColorRGBToHex(t *testing.T) {
assert := internal.NewAssert(t, "TestColorRGBToHex")
assert.Equal(expected, colorHex)
}
func TestToChannel(t *testing.T) {
assert := internal.NewAssert(t, "TestToChannel")
ch := ToChannel([]interface{}{1, 2, 3})
val1, _ := <-ch
assert.Equal(1, val1)
val2, _ := <-ch
assert.Equal(2, val2)
val3, _ := <-ch
assert.Equal(3, val3)
_, ok := <-ch
assert.Equal(false, ok)
}
func TestEncodeByte(t *testing.T) {
assert := internal.NewAssert(t, "TestEncodeByte")
byteData, _ := EncodeByte("abc")
expected := []byte{6, 12, 0, 3, 97, 98, 99}
assert.Equal(expected, byteData)
}
func TestDecodeByte(t *testing.T) {
assert := internal.NewAssert(t, "TestDecodeByte")
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
DecodeByte(byteData, &obj)
assert.Equal("abc", obj)
}
func TestDeepClone(t *testing.T) {
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for i, item := range cases {
cloned := DeepClone(item)
t.Log(cloned)
if &cloned == &item {
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
}
if !reflect.DeepEqual(item, cloned) {
t.Fatalf("[TestDeepClone case #%d failed] unequal objects", i)
}
}
}
func TestCopyProperties(t *testing.T) {
assert := internal.NewAssert(t, "TestCopyProperties")
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := CopyProperties(&indicatorVO, indicator)
assert.IsNil(err)
assert.Equal("001", indicatorVO.Id)
assert.Equal("127.0.0.1", indicatorVO.Ip)
assert.Equal(3, len(indicatorVO.Disk))
}
func TestToInterface(t *testing.T) {
assert := internal.NewAssert(t, "TestToInterface")
cases := []reflect.Value{
reflect.ValueOf("abc"),
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
reflect.ValueOf(true), reflect.ValueOf(false),
}
expected := []interface{}{
"abc",
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,
}
for i := 0; i < len(cases); i++ {
actual, _ := ToInterface(cases[i])
assert.Equal(expected[i], actual)
}
nilVal, ok := ToInterface(reflect.ValueOf(nil))
assert.EqualValues(nil, nilVal)
assert.Equal(false, ok)
}

View File

@@ -17,23 +17,14 @@ import (
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbEncrypt(data, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
cipher, _ := aes.NewCipher(generateAesKey(key))
length := (len(data) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.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])
@@ -45,14 +36,9 @@ func AesEcbEncrypt(data, key []byte) []byte {
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
// len(key) should be 16, 24 or 32
func AesEcbDecrypt(encrypted, key []byte) []byte {
size := len(key)
if size != 16 && size != 24 && size != 32 {
panic("key length shoud be 16 or 24 or 32")
}
cipher, _ := aes.NewCipher(generateAesKey(key, size))
cipher, _ := aes.NewCipher(generateAesKey(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])
}
@@ -68,18 +54,14 @@ func AesEcbDecrypt(encrypted, key []byte) []byte {
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
// len(key) should be 16, 24 or 32
func AesCbcEncrypt(data, key []byte) []byte {
// len(key) should be 16, 24 or 32
block, _ := aes.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
encrypted := make([]byte, aes.BlockSize+len(data))
iv := encrypted[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
blockSize := block.BlockSize()
data = pkcs7Padding(data, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, len(data))
blockMode.CryptBlocks(encrypted, data)
return encrypted
}
@@ -87,14 +69,12 @@ func AesCbcEncrypt(data, key []byte) []byte {
// len(key) should be 16, 24 or 32
func AesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := aes.NewCipher(key)
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
iv := encrypted[:aes.BlockSize]
encrypted = encrypted[aes.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
decrypted := make([]byte, len(encrypted))
blockMode.CryptBlocks(decrypted, encrypted)
decrypted = pkcs7UnPadding(decrypted)
return decrypted
}

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestAesEcbEncrypt(t *testing.T) {

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestBase64StdEncode(t *testing.T) {

View File

@@ -2,15 +2,15 @@ package cryptor
import "bytes"
func generateAesKey(key []byte, size int) []byte {
aesKey := make([]byte, size)
copy(aesKey, key)
for i := size; i < len(key); {
for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
aesKey[j] ^= key[i]
func generateAesKey(key []byte) []byte {
genKey := make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return aesKey
return genKey
}
func generateDesKey(key []byte) []byte {

View File

@@ -55,16 +55,12 @@ func DesEcbDecrypt(encrypted, key []byte) []byte {
// len(key) should be 8
func DesCbcEncrypt(data, key []byte) []byte {
block, _ := des.NewCipher(key)
data = pkcs7Padding(data, block.BlockSize())
blockSize := block.BlockSize()
data = pkcs7Padding(data, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, des.BlockSize+len(data))
iv := encrypted[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(encrypted[des.BlockSize:], data)
encrypted := make([]byte, len(data))
blockMode.CryptBlocks(encrypted, data)
return encrypted
}
@@ -73,14 +69,13 @@ func DesCbcEncrypt(data, key []byte) []byte {
// len(key) should be 8
func DesCbcDecrypt(encrypted, key []byte) []byte {
block, _ := des.NewCipher(key)
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
iv := encrypted[:des.BlockSize]
encrypted = encrypted[des.BlockSize:]
decrypted := make([]byte, len(encrypted))
blockMode.CryptBlocks(decrypted, encrypted)
decrypted = pkcs7UnPadding(decrypted)
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypted, encrypted)
decrypted := pkcs7UnPadding(encrypted)
return decrypted
}

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestDesEcbEncrypt(t *testing.T) {

View File

@@ -3,7 +3,7 @@ package cryptor
import (
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestRsaEncrypt(t *testing.T) {

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

51
datastructure/node.go Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ package datetime
import (
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestToUnix(t *testing.T) {
@@ -19,10 +19,10 @@ func TestToUnix(t *testing.T) {
func TestToFormat(t *testing.T) {
assert := internal.NewAssert(t, "TestToFormat")
tm, err := NewFormat("2022/03/18 17:04:05")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err = NewFormat("2022-03-18 17:04:05")
tm, err := NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormat -> ", tm.ToFormat())
@@ -31,23 +31,22 @@ func TestToFormat(t *testing.T) {
func TestToFormatForTpl(t *testing.T) {
assert := internal.NewAssert(t, "TestToFormatForTpl")
tm, err := NewFormat("2022/03/18 17:04:05")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err = NewFormat("2022-03-18 17:04:05")
tm, err := NewFormat("2022-03-18 17:04:05")
assert.IsNil(err)
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
}
func TestToIso8601(t *testing.T) {
assert := internal.NewAssert(t, "TestToIso8601")
tm, err := NewISO8601("2022-03-18 17:04:05")
_, err := NewISO8601("2022-03-18 17:04:05")
assert.IsNotNil(err)
tm, err = NewISO8601("2006-01-02T15:04:05.999Z")
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
assert.IsNil(err)
t.Log("ToIso8601 -> ", tm.ToIso8601())

View File

@@ -4,24 +4,24 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
// "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"
//"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"
package datetime
import (
@@ -35,7 +35,7 @@ func init() {
timeFormat = map[string]string{
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
"yyyy-mm-dd hh": "2006-01-02 15",
"yyyy-mm-dd hh": "2006-01-02 15:04",
"yyyy-mm-dd": "2006-01-02",
"yyyy-mm": "2006-01",
"mm-dd": "01-02",
@@ -69,11 +69,6 @@ func AddDay(t time.Time, day int64) time.Time {
return t.Add(24 * time.Hour * time.Duration(day))
}
// AddYear add or sub year to the time.
func AddYear(t time.Time, year int64) time.Time {
return t.Add(365 * 24 * time.Hour * time.Duration(year))
}
// GetNowDate return format yyyy-mm-dd of current date
func GetNowDate() string {
return time.Now().Format("2006-01-02")
@@ -185,28 +180,3 @@ func BeginOfYear(t time.Time) time.Time {
func EndOfYear(t time.Time) time.Time {
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
}
// IsLeapYear check if param year is leap year or not.
func IsLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
// BetweenSeconds returns the number of seconds between two times.
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
index := t2.Unix() - t1.Unix()
return index
}
// DayOfYear returns which day of the year the parameter date `t` is.
func DayOfYear(t time.Time) int {
y, m, d := t.Date()
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
return int(nowDate.Sub(firstDay).Hours() / 24)
}
// IsWeekend checks if passed time is weekend or not.
func IsWeekend(t time.Time) bool {
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}

View File

@@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestAddDay(t *testing.T) {
@@ -46,19 +46,6 @@ func TestAddMinute(t *testing.T) {
assert.Equal(float64(-2), diff2.Minutes())
}
func TestAddYear(t *testing.T) {
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
after2Years := AddYear(now, 1)
diff1 := after2Years.Sub(now)
assert.Equal(float64(8760), diff1.Hours())
before2Years := AddYear(now, -1)
diff2 := before2Years.Sub(now)
assert.Equal(float64(-8760), diff2.Hours())
}
func TestGetNowDate(t *testing.T) {
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
@@ -244,57 +231,3 @@ func TestEndOfYear(t *testing.T) {
assert.Equal(expected, actual)
}
func TestIsLeapYear(t *testing.T) {
assert := internal.NewAssert(t, "TestEndOfYear")
result1 := IsLeapYear(2000)
result2 := IsLeapYear(2001)
assert.Equal(true, result1)
assert.Equal(false, result2)
}
func TestBetweenSeconds(t *testing.T) {
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
tomorrow := AddDay(today, 1)
yesterday := AddDay(today, -1)
result1 := BetweenSeconds(today, tomorrow)
result2 := BetweenSeconds(today, yesterday)
assert.Equal(int64(86400), result1)
assert.Equal(int64(-86400), result2)
}
func TestDayOfYear(t *testing.T) {
assert := internal.NewAssert(t, "TestDayOfYear")
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
assert.Equal(31, result1)
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
result2 := DayOfYear(date2)
assert.Equal(1, result2)
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
result3 := DayOfYear(date3)
assert.Equal(0, result3)
}
func TestIsWeekend(t *testing.T) {
assert := internal.NewAssert(t, "TestIsWeekend")
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
result := IsWeekend(date)
assert.Equal(true, result)
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
result1 := IsWeekend(date1)
assert.Equal(true, result1)
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
result2 := IsWeekend(date2)
assert.Equal(false, result2)
}

598
docs/algorithm.md Normal file
View File

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

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

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

View File

@@ -1,326 +0,0 @@
# Compare
Package compare provides a lightweight comparison function on any type.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Equal](#Equal)
- [EqualValue](#EqualValue)
- [LessThan](#LessThan)
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Equal">Equal</span>
<p>Checks if two values are equal or not. (check both type and value)</p>
<b>Signature:</b>
```go
func Equal(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.Equal(1, 1)
result2 := compare.Equal("1", "1")
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
result5 := compare.Equal(1, "1")
result6 := compare.Equal(1, int64(1))
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="EqualValue">EqualValue</span>
<p>Checks if two values are equal or not. (check value only)</p>
<b>Signature:</b>
```go
func EqualValue(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.EqualValue(1, 1)
result2 := compare.EqualValue(int(1), int64(1))
result3 := compare.EqualValue(1, "1")
result4 := compare.EqualValue(1, "2")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
```
### <span id="LessThan">LessThan</span>
<p>Checks if value `left` less than value `right`.</p>
<b>Signature:</b>
```go
func LessThan(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.LessThan(1, 2)
result2 := compare.LessThan(1.1, 2.2)
result3 := compare.LessThan("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessThan(time1, time2)
result5 := compare.LessThan(2, 1)
result6 := compare.LessThan(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterThan">GreaterThan</span>
<p>Checks if value `left` greater than value `right`.</p>
<b>Signature:</b>
```go
func GreaterThan(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.GreaterThan(2, 1)
result2 := compare.GreaterThan(2.2, 1.1)
result3 := compare.GreaterThan("b", "a")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterThan(time2, time1)
result5 := compare.GreaterThan(1, 2)
result6 := compare.GreaterThan(int64(2), 1)
result7 := compare.GreaterThan("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="LessOrEqual">LessOrEqual</span>
<p>Checks if value `left` less than or equal than value `right`.</p>
<b>Signature:</b>
```go
func LessOrEqual(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.LessOrEqual(1, 1)
result2 := compare.LessOrEqual(1.1, 2.2)
result3 := compare.LessOrEqual("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessOrEqual(time1, time2)
result5 := compare.LessOrEqual(2, 1)
result6 := compare.LessOrEqual(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterOrEqual">GreaterOrEqual</span>
<p>Checks if value `left` less greater or equal than value `right`.</p>
<b>Signature:</b>
```go
func GreaterOrEqual(left, right any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.GreaterOrEqual(1, 1)
result2 := compare.GreaterOrEqual(2.2, 1.1)
result3 := compare.GreaterOrEqual("b", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterOrEqual(time2, time1)
result5 := compare.GreaterOrEqual(1, 2)
result6 := compare.GreaterOrEqual(int64(2), 1)
result7 := compare.GreaterOrEqual("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```

View File

@@ -1,326 +0,0 @@
# Compare
compare包提供几个轻量级的类型比较函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Equal](#Equal)
- [EqualValue](#EqualValue)
- [LessThan](#LessThan)
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Equal">Equal</span>
<p>检查两个值是否相等(检查类型和值)</p>
<b>函数签名:</b>
```go
func Equal(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.Equal(1, 1)
result2 := compare.Equal("1", "1")
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
result5 := compare.Equal(1, "1")
result6 := compare.Equal(1, int64(1))
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="EqualValue">EqualValue</span>
<p>检查两个值是否相等(只检查值)</p>
<b>函数签名:</b>
```go
func EqualValue(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.EqualValue(1, 1)
result2 := compare.EqualValue(int(1), int64(1))
result3 := compare.EqualValue(1, "1")
result4 := compare.EqualValue(1, "2")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// true
// true
// true
// false
}
```
### <span id="LessThan">LessThan</span>
<p>验证参数`left`的值是否小于参数`right`的值。</p>
<b>函数签名:</b>
```go
func LessThan(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.LessThan(1, 2)
result2 := compare.LessThan(1.1, 2.2)
result3 := compare.LessThan("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessThan(time1, time2)
result5 := compare.LessThan(2, 1)
result6 := compare.LessThan(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterThan">GreaterThan</span>
<p>验证参数`left`的值是否大于参数`right`的值。</p>
<b>函数签名:</b>
```go
func GreaterThan(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.GreaterThan(2, 1)
result2 := compare.GreaterThan(2.2, 1.1)
result3 := compare.GreaterThan("b", "a")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterThan(time2, time1)
result5 := compare.GreaterThan(1, 2)
result6 := compare.GreaterThan(int64(2), 1)
result7 := compare.GreaterThan("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```
### <span id="LessOrEqual">LessOrEqual</span>
<p>验证参数`left`的值是否小于或等于参数`right`的值。</p>
<b>函数签名:</b>
```go
func LessOrEqual(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.LessOrEqual(1, 1)
result2 := compare.LessOrEqual(1.1, 2.2)
result3 := compare.LessOrEqual("a", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.LessOrEqual(time1, time2)
result5 := compare.LessOrEqual(2, 1)
result6 := compare.LessOrEqual(1, int64(2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// true
// true
// true
// false
// false
}
```
### <span id="GreaterOrEqual">GreaterOrEqual</span>
<p>验证参数`left`的值是否大于或参数`right`的值。</p>
<b>函数签名:</b>
```go
func GreaterOrEqual(left, right any) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/compare"
)
func main() {
result1 := compare.GreaterOrEqual(1, 1)
result2 := compare.GreaterOrEqual(2.2, 1.1)
result3 := compare.GreaterOrEqual("b", "b")
time1 := time.Now()
time2 := time1.Add(time.Second)
result4 := compare.GreaterOrEqual(time2, time1)
result5 := compare.GreaterOrEqual(1, 2)
result6 := compare.GreaterOrEqual(int64(2), 1)
result7 := compare.GreaterOrEqual("b", "c")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// true
// false
// false
// false
}
```

390
docs/concurrency.md Normal file
View File

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

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

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

View File

@@ -1,51 +1,41 @@
# 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/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
- [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/convertor"
"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)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [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>
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>Convert color hex to color rgb.</p>
<b>Signature:</b>
@@ -53,7 +43,6 @@ import (
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>Example:</b>
```go
@@ -61,16 +50,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
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>
@@ -80,7 +71,6 @@ func main() {
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>Example:</b>
```go
@@ -88,19 +78,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
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>
@@ -110,7 +102,6 @@ func main() {
```go
func ToBool(s string) (bool, error)
```
<b>Example:</b>
```go
@@ -118,7 +109,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -136,6 +127,8 @@ func main() {
}
```
### <span id="ToBytes">ToBytes</span>
<p>Convert interface to byte slice.</p>
@@ -143,9 +136,8 @@ func main() {
<b>Signature:</b>
```go
func ToBytes(data interface{}) ([]byte, error)
func ToBytes(data any) ([]byte, error)
```
<b>Example:</b>
```go
@@ -153,7 +145,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -165,6 +157,8 @@ func main() {
}
```
### <span id="ToChar">ToChar</span>
<p>Convert string to char slice.</p>
@@ -174,7 +168,6 @@ func main() {
```go
func ToChar(s string) []string
```
<b>Example:</b>
```go
@@ -182,7 +175,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -197,42 +190,7 @@ func main() {
}
```
### <span id="ToChannel">ToChannel</span>
<p>Convert a collection of elements to a read-only channels.</p>
<b>Signature:</b>
```go
func ToChannel(array []interface{}) <-chan interface{}
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
@@ -241,9 +199,8 @@ func main() {
<b>Signature:</b>
```go
func ToFloat(value interface{}) (float64, error)
func ToFloat(value any) (float64, error)
```
<b>Example:</b>
```go
@@ -251,7 +208,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -266,6 +223,8 @@ func main() {
}
```
### <span id="ToInt">ToInt</span>
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
@@ -273,9 +232,8 @@ func main() {
<b>Signature:</b>
```go
func ToInt(value interface{}) (int64, error)
func ToInt(value any) (int64, error)
```
<b>Example:</b>
```go
@@ -283,7 +241,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -298,6 +256,8 @@ func main() {
}
```
### <span id="ToJson">ToJson</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
@@ -305,9 +265,8 @@ func main() {
<b>Signature:</b>
```go
func ToJson(value interface{}) (string, error)
func ToJson(value any) (string, error)
```
<b>Example:</b>
```go
@@ -315,7 +274,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -325,6 +284,8 @@ func main() {
}
```
### <span id="ToString">ToString</span>
<p>Convert interface to string. </p>
@@ -332,9 +293,8 @@ func main() {
<b>Signature:</b>
```go
func ToString(value interface{}) string
func ToString(value any) string
```
<b>Example:</b>
```go
@@ -342,7 +302,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -352,6 +312,8 @@ func main() {
}
```
### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
@@ -359,9 +321,8 @@ func main() {
<b>Signature:</b>
```go
func StructToMap(value interface{}) (map[string]interface{}, error)
func StructToMap(value any) (map[string]any, error)
```
<b>Example:</b>
```go
@@ -369,7 +330,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -385,236 +346,4 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>Encode data to byte slice.</p>
<b>Signature:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>Decode byte data to target object. target should be a pointer instance.</p>
<b>Signature:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```
### <span id="DeepClone">DeepClone</span>
<p>Creates a deep copy of passed item, can't clone unexported field of struct.</p>
<b>Signature:</b>
```go
func DeepClone[T any](src T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
<b>Signature:</b>
```go
func CopyProperties(dst, src interface{}) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>Converts reflect value to its interface type.</p>
<b>Signature:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```

View File

@@ -1,12 +1,11 @@
# Convertor
convertor 转换器包支持一些常见的数据类型转换
convertor转换器包支持一些常见的数据类型转换
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
- [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>
@@ -14,7 +13,7 @@ convertor 转换器包支持一些常见的数据类型转换
```go
import (
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
```
@@ -22,29 +21,23 @@ import (
## 目录
- [ColorHexToRGB](#ColorHexToRGB)
- [ColorRGBToHex](#ColorRGBToHex)
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
- [DeepClone](#DeepClone)
- [CopyProperties](#CopyProperties)
- [ToInterface](#ToInterface)
- [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>
### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb</p>
<b>函数签名:</b>
@@ -52,7 +45,6 @@ import (
```go
func ColorHexToRGB(colorHex string) (red, green, blue int)
```
<b>列子:</b>
```go
@@ -60,16 +52,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
}
```
### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制</p>
@@ -79,7 +73,6 @@ func main() {
```go
func ColorRGBToHex(red, green, blue int) string
```
<b>列子:</b>
```go
@@ -87,19 +80,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
r := 0
g := 51
b := 102
colorHex := ColorRGBToHex(r, g, b)
colorHex := convertor.ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366
}
```
### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型使用strconv.ParseBool</p>
@@ -109,7 +104,6 @@ func main() {
```go
func ToBool(s string) (bool, error)
```
<b>列子:</b>
```go
@@ -117,7 +111,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -135,6 +129,8 @@ func main() {
}
```
### <span id="ToBytes">ToBytes</span>
<p>interface转字节切片.</p>
@@ -142,9 +138,8 @@ func main() {
<b>函数签名:</b>
```go
func ToBytes(data interface{}) ([]byte, error)
func ToBytes(data any) ([]byte, error)
```
<b>列子:</b>
```go
@@ -152,7 +147,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -164,6 +159,8 @@ func main() {
}
```
### <span id="ToChar">ToChar</span>
<p>字符串转字符切片</p>
@@ -173,7 +170,6 @@ func main() {
```go
func ToChar(s string) []string
```
<b>列子:</b>
```go
@@ -181,7 +177,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -196,42 +192,7 @@ func main() {
}
```
### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel</p>
<b>函数签名:</b>
```go
func ToChannel(array []interface{}) <-chan interface{}
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
@@ -240,9 +201,8 @@ func main() {
<b>函数签名:</b>
```go
func ToFloat(value interface{}) (float64, error)
func ToFloat(value any) (float64, error)
```
<b>列子:</b>
```go
@@ -250,7 +210,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -265,6 +225,8 @@ func main() {
}
```
### <span id="ToInt">ToInt</span>
<p>将interface转成intt64类型如果参数无法转换会返回0和error</p>
@@ -272,9 +234,8 @@ func main() {
<b>函数签名:</b>
```go
func ToInt(value interface{}) (int64, error)
func ToInt(value any) (int64, error)
```
<b>例子:</b>
```go
@@ -282,7 +243,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -297,6 +258,8 @@ func main() {
}
```
### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串如果参数无法转换会返回""和error</p>
@@ -304,9 +267,8 @@ func main() {
<b>函数签名:</b>
```go
func ToJson(value interface{}) (string, error)
func ToJson(value any) (string, error)
```
<b>列子:</b>
```go
@@ -314,7 +276,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -324,6 +286,8 @@ func main() {
}
```
### <span id="ToString">ToString</span>
<p>将interface转成字符串</p>
@@ -331,9 +295,8 @@ func main() {
<b>函数签名:</b>
```go
func ToString(value interface{}) string
func ToString(value any) string
```
<b>例子:</b>
```go
@@ -341,7 +304,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -351,6 +314,8 @@ func main() {
}
```
### <span id="StructToMap">StructToMap</span>
<p>将struct转成map只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
@@ -358,9 +323,8 @@ func main() {
<b>函数签名:</b>
```go
func StructToMap(value interface{}) (map[string]interface{}, error)
func StructToMap(value any) (map[string]any, error)
```
<b>列子:</b>
```go
@@ -368,7 +332,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
@@ -384,237 +348,4 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片</p>
<b>函数签名:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
<b>函数签名:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```
### <span id="DeepClone">DeepClone</span>
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
<b>函数签名:</b>
```go
func DeepClone[T any](src T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Struct struct {
Str string
Int int
Float float64
Bool bool
Nil interface{}
unexported string
}
cases := []interface{}{
true,
1,
0.1,
map[string]int{
"a": 1,
"b": 2,
},
&Struct{
Str: "test",
Int: 1,
Float: 0.1,
Bool: true,
Nil: nil,
// unexported: "can't be cloned",
},
}
for _, item := range cases {
cloned := convertor.DeepClone(item)
isPointerEqual := &cloned == &item
fmt.Println(cloned, isPointerEqual)
}
// Output:
// true false
// 1 false
// 0.1 false
// map[a:1 b:2] false
// &{test 1 0.1 true <nil> } false
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化需要设置dst和src struct字段的json tag。</p>
<b>函数签名:</b>
```go
func CopyProperties(dst, src interface{}) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
type Disk struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type DiskVO struct {
Name string `json:"name"`
Total string `json:"total"`
Used string `json:"used"`
Percent float64 `json:"percent"`
}
type Indicator struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int `json:"cpu"`
Disk []Disk `json:"disk"`
Stop chan bool `json:"-"`
}
type IndicatorVO struct {
Id string `json:"id"`
Ip string `json:"ip"`
UpTime string `json:"upTime"`
LoadAvg string `json:"loadAvg"`
Cpu int64 `json:"cpu"`
Disk []DiskVO `json:"disk"`
}
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
}}
indicatorVO := IndicatorVO{}
err := convertor.CopyProperties(&indicatorVO, indicator)
if err != nil {
return
}
fmt.Println(indicatorVO.Id)
fmt.Println(indicatorVO.Ip)
fmt.Println(len(indicatorVO.Disk))
// Output:
// 001
// 127.0.0.1
// 3
}
```
### <span id="ToInterface">ToInterface</span>
<p>将反射值转换成对应的interface类型。</p>
<b>函数签名:</b>
```go
func ToInterface(v reflect.Value) (value interface{}, ok bool)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/convertor"
)
func main() {
val := reflect.ValueOf("abc")
iVal, ok := convertor.ToInterface(val)
fmt.Printf("%T\n", iVal)
fmt.Printf("%v\n", iVal)
fmt.Println(ok)
// Output:
// string
// abc
// true
}
```

View File

@@ -1,23 +1,21 @@
# Cryptor
Package cryptor contains some functions for data encryption and decryption. Support base64, md5, hmac, aes, des, rsa.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go](https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/des.go](https://github.com/duke-git/lancet/blob/v1/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
```
@@ -25,43 +23,47 @@ import (
## Index
- [AesEcbEncrypt](#AesEcbEncrypt)
- [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt)
- [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt)
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha256](#Sha256)
- [Sha512](#Sha512)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
- [AesEcbEncrypt](#AesEcbEncrypt)
- [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt)
- [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt)
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha256](#Sha256)
- [Sha512](#Sha512)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="AesEcbEncrypt">AesEcbEncrypt</span>
<p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -71,7 +73,6 @@ import (
```go
func AesEcbEncrypt(data, key []byte) []byte
```
<b>Example:</b>
```go
@@ -79,18 +80,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesEcbDecrypt">AesEcbDecrypt</span>
<p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -100,7 +103,6 @@ func main() {
```go
func AesEcbDecrypt(encrypted, key []byte) []byte
```
<b>Example:</b>
```go
@@ -108,18 +110,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesCbcEncrypt">AesCbcEncrypt</span>
<p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -129,7 +133,6 @@ func main() {
```go
func AesCbcEncrypt(data, key []byte) []byte
```
<b>Example:</b>
```go
@@ -137,18 +140,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCbcDecrypt">AesCbcDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -166,18 +171,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -195,12 +202,12 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
@@ -208,6 +215,8 @@ func main() {
}
```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -225,17 +234,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCfbDecrypt">AesCfbDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -253,18 +264,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesOfbEncrypt">AesOfbEncrypt</span>
<p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -282,17 +295,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCfbDecrypt">AesOfbDecrypt</span>
<p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -310,19 +325,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="Base64StdEncode">Base64StdEncode</span>
<p>Encode string with base64 encoding.</p>
@@ -332,7 +349,6 @@ func main() {
```go
func Base64StdEncode(s string) string
```
<b>Example:</b>
```go
@@ -340,15 +356,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
base64Str := cryptor.Base64StdEncode("hello world")
base64Str := cryptor.Base64StdEncode("hello world")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ=
}
```
### <span id="Base64StdDecode">Base64StdDecode</span>
<p>Decode a base64 encoded string.</p>
@@ -366,7 +384,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
@@ -375,6 +393,8 @@ func main() {
}
```
### <span id="DesEcbEncrypt">DesEcbEncrypt</span>
<p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -392,18 +412,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesEcbDecrypt">DesEcbDecrypt</span>
<p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -421,19 +443,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesCbcEncrypt">DesCbcEncrypt</span>
<p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -451,18 +475,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted))
}
```
### <span id="DesCbcDecrypt">DesCbcDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -480,19 +506,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesCtrCrypt">DesCtrCrypt</span>
<p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
@@ -510,12 +538,12 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
@@ -523,6 +551,8 @@ func main() {
}
```
### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
<p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p>
@@ -540,17 +570,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted))
}
```
### <span id="DesCfbDecrypt">DesCfbDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -568,18 +600,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesOfbEncrypt">DesOfbEncrypt</span>
<p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -597,17 +631,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesOfbDecrypt">DesOfbDecrypt</span>
<p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -625,19 +661,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="HmacMd5">HmacMd5</span>
<p>Get the md5 hmac hash of string.</p>
@@ -655,15 +693,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
}
```
### <span id="HmacSha1">HmacSha1</span>
<p>Get the sha1 hmac hash of string.</p>
@@ -681,15 +721,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
}
```
### <span id="HmacSha256">HmacSha256</span>
<p>Get the sha256 hmac hash of string</p>
@@ -707,15 +749,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
}
```
### <span id="HmacSha512">HmacSha512</span>
<p>Get the sha512 hmac hash of string.</p>
@@ -733,15 +777,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s) //5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
}
```
### <span id="Md5String">Md5String</span>
<p>Get the md5 value of string.</p>
@@ -759,15 +806,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
}
```
### <span id="Md5File">Md5File</span>
<p>Get the md5 value of file.</p>
@@ -785,15 +834,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
}
```
### <span id="Sha1">Sha1</span>
<p>Get the sha1 value of string.</p>
@@ -811,15 +862,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
}
```
### <span id="Sha256">Sha256</span>
<p>Get the sha256 value of string.</p>
@@ -837,15 +890,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
}
```
### <span id="Sha512">Sha512</span>
<p>Get the sha512 value of string.</p>
@@ -863,15 +918,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha512("hello world"))
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
}
```
### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>Create the rsa public and private key file in current directory.</p>
@@ -889,17 +946,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
}
```
### <span id="RsaEncrypt">RsaEncrypt</span>
<p>Encrypt data with public key file useing ras algorithm.</p>
@@ -917,23 +976,25 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="RsaDecrypt">RsaDecrypt</span>
<p>Decrypt data with private key file useing ras algorithm.</p>
@@ -951,19 +1012,22 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
}
```

View File

@@ -1,67 +1,69 @@
# Cryptor
cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go](https://github.com/duke-git/lancet/blob/v1/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/des.go](https://github.com/duke-git/lancet/blob/v1/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go](https://github.com/duke-git/lancet/blob/v1/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/v1/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [AesEcbEncrypt](#AesEcbEncrypt)
- [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt)
- [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt)
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha256](#Sha256)
- [Sha512](#Sha512)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
- [AesEcbEncrypt](#AesEcbEncrypt)
- [AesEcbDecrypt](#AesEcbDecrypt)
- [AesCbcEncrypt](#AesCbcEncrypt)
- [AesCbcDecrypt](#AesCbcDecrypt)
- [AesCtrCrypt](#AesCtrCrypt)
- [AesCfbEncrypt](#AesCfbEncrypt)
- [AesCfbDecrypt](#AesCfbDecrypt)
- [AesOfbEncrypt](#AesOfbEncrypt)
- [AesOfbDecrypt](#AesOfbDecrypt)
- [Base64StdEncode](#Base64StdEncode)
- [Base64StdDecode](#Base64StdDecode)
- [DesEcbEncrypt](#DesEcbEncrypt)
- [DesEcbDecrypt](#DesEcbDecrypt)
- [DesCbcEncrypt](#DesCbcEncrypt)
- [DesCbcDecrypt](#DesCbcDecrypt)
- [DesCtrCrypt](#DesCtrCrypt)
- [DesCfbEncrypt](#DesCfbEncrypt)
- [DesCfbDecrypt](#DesCfbDecrypt)
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacSha1](#HmacSha1)
- [HmacSha256](#HmacSha256)
- [HmacSha512](#HmacSha512)
- [Md5String](#Md5String)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha256](#Sha256)
- [Sha512](#Sha512)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="AesEcbEncrypt">AesEcbEncrypt</span>
<p>使用AES ECB算法模式加密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -71,7 +73,6 @@ import (
```go
func AesEcbEncrypt(data, key []byte) []byte
```
<b>列子:</b>
```go
@@ -79,18 +80,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesEcbDecrypt">AesEcbDecrypt</span>
<p>使用AES ECB算法模式解密数据. 参数`key`的长度是16, 24 or 32。
@@ -100,7 +103,6 @@ func main() {
```go
func AesEcbDecrypt(encrypted, key []byte) []byte
```
<b>列子:</b>
```go
@@ -108,18 +110,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesCbcEncrypt">AesCbcEncrypt</span>
<p>使用AES CBC算法模式加密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -129,7 +133,6 @@ func main() {
```go
func AesCbcEncrypt(data, key []byte) []byte
```
<b>列子:</b>
```go
@@ -137,18 +140,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCbcDecrypt">AesCbcDecrypt</span>
<p>使用AES CBC算法模式解密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -166,19 +171,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>使用AES CTR算法模式加密/解密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -196,12 +203,12 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
@@ -209,6 +216,8 @@ func main() {
}
```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>使用AES CFB算法模式加密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -226,17 +235,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCfbDecrypt">AesCfbDecrypt</span>
<p>使用AES CFB算法模式解密数据. 参数`key`的长度是16, 24 or 32。</p>
@@ -254,18 +265,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="AesOfbEncrypt">AesOfbEncrypt</span>
<p>使用AES OFB算法模式加密数据. 参数`key`的长度是16, 24 or 32</p>
@@ -283,17 +296,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="AesCfbDecrypt">AesOfbDecrypt</span>
<p>使用AES OFB算法模式解密数据. 参数`key`的长度是16, 24 or 32</p>
@@ -311,18 +326,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefghijklmnop"
key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="Base64StdEncode">Base64StdEncode</span>
<p>将字符串base64编码</p>
@@ -332,7 +349,6 @@ func main() {
```go
func Base64StdEncode(s string) string
```
<b>列子:</b>
```go
@@ -340,15 +356,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
base64Str := cryptor.Base64StdEncode("hello world")
base64Str := cryptor.Base64StdEncode("hello world")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ=
}
```
### <span id="Base64StdDecode">Base64StdDecode</span>
<p>解码base64字符串</p>
@@ -366,15 +384,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=")
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=")
fmt.Println(str) //hello world
}
```
### <span id="DesEcbEncrypt">DesEcbEncrypt</span>
<p>使用DES ECB算法模式加密数据. 参数`key`的长度是8</p>
@@ -392,18 +412,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesEcbDecrypt">DesEcbDecrypt</span>
<p>使用DES ECB算法模式解密数据. 参数`key`的长度是8</p>
@@ -421,19 +443,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesCbcEncrypt">DesCbcEncrypt</span>
<p>使用DES CBC算法模式加密数据. 参数`key`的长度是8</p>
@@ -451,18 +475,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesCbcDecrypt">DesCbcDecrypt</span>
<p>使用DES CBC算法模式解密数据. 参数`key`的长度是8</p>
@@ -480,19 +506,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesCtrCrypt">DesCtrCrypt</span>
<p>使用DES CTR算法模式加密/解密数据. 参数`key`的长度是8</p>
@@ -510,12 +538,12 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
@@ -523,6 +551,8 @@ func main() {
}
```
### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
<p>使用DES CFB算法模式加密数据. 参数`key`的长度是8</p>
@@ -540,17 +570,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesCfbDecrypt">DesCfbDecrypt</span>
<p>使用DES CFB算法模式解密数据. 参数`key`的长度是8</p>
@@ -568,18 +600,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="DesOfbEncrypt">DesOfbEncrypt</span>
<p>使用DES OFB算法模式加密数据. 参数`key`的长度是8</p>
@@ -597,17 +631,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted))
}
```
### <span id="DesOfbDecrypt">DesOfbDecrypt</span>
<p>使用DES OFB算法模式解密数据. 参数`key`的长度是8</p>
@@ -625,18 +661,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := "hello world"
key := "abcdefgh"
key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="HmacMd5">HmacMd5</span>
<p>获取字符串md5 hmac值</p>
@@ -654,15 +692,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
s := cryptor.HmacMd5("hello world", "12345"))
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
}
```
### <span id="HmacSha1">HmacSha1</span>
<p>获取字符串sha1 hmac值</p>
@@ -680,15 +720,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
s := cryptor.HmacSha1("hello world", "12345"))
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
}
```
### <span id="HmacSha256">HmacSha256</span>
<p>获取字符串sha256 hmac值</p>
@@ -706,15 +748,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
s := cryptor.HmacSha256("hello world", "12345"))
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
}
```
### <span id="HmacSha512">HmacSha512</span>
<p>获取字符串sha512 hmac值</p>
@@ -732,16 +776,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
s := cryptor.HmacSha512("hello world", "12345"))
fmt.Println(s)
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
}
```
### <span id="Md5String">Md5String</span>
<p>获取字符串md5值</p>
@@ -759,15 +805,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
s := cryptor.Md5String("hello"))
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
}
```
### <span id="Md5File">Md5File</span>
<p>获取文件md5值.</p>
@@ -785,15 +833,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
s := cryptor.Md5File("./main.go"))
fmt.Println(s)
}
```
### <span id="Sha1">Sha1</span>
<p>获取字符串sha1值</p>
@@ -811,15 +861,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
s := cryptor.Sha1("hello world"))
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
}
```
### <span id="Sha256">Sha256</span>
<p>获取字符串sha256值</p>
@@ -837,15 +889,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
s := cryptor.Sha256("hello world"))
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
}
```
### <span id="Sha512">Sha512</span>
<p>获取字符串sha512值</p>
@@ -863,15 +917,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
s := cryptor.Sha512("hello world"))
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
}
```
### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>在当前目录下创建rsa私钥文件和公钥文件</p>
@@ -889,17 +945,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="RsaEncrypt">RsaEncrypt</span>
<p>用公钥文件ras加密数据</p>
@@ -917,22 +975,23 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted)) //hello world
}
```
### <span id="RsaDecrypt">RsaDecrypt</span>
<p>用私钥文件rsa解密数据</p>
@@ -950,18 +1009,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
fmt.Println(err)
}
data := []byte("hello world")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted)) //hello world
}
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,47 @@
# 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/v1/fileutil/file.go](https://github.com/duke-git/lancet/blob/v1/fileutil/file.go)
- [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/fileutil"
"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)
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
- [CurrentPath](#CurrentPath)
- [IsZipFile](#IsZipFile)
- [FileSize](#FileSize)
- [MTime](#MTime)
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [UnZip](#UnZip)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="ClearFile">ClearFile</span>
### <span id="ClearFile">ClearFile</span>
<p>Clear the file content, write empty string to the file.</p>
<b>Signature:</b>
@@ -59,7 +49,6 @@ import (
```go
func ClearFile(path string) error
```
<b>Example:</b>
```go
@@ -67,7 +56,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -78,34 +67,7 @@ func main() {
}
```
### <span id="CreateDir">CreateDir</span>
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
<b>Signature:</b>
```go
func CreateDir(absPath string) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
err := fileutil.CreateDir("/a/")
fmt.Println(err)
}
```
### <span id="CreateFile">CreateFile</span>
<p>Create file in path. return true if create succeed.</p>
<b>Signature:</b>
@@ -113,7 +75,6 @@ func main() {
```go
func CreateFile(path string) bool
```
<b>Example:</b>
```go
@@ -121,7 +82,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -130,8 +91,8 @@ func main() {
}
```
### <span id="CopyFile">CopyFile</span>
### <span id="CopyFile">CopyFile</span>
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
<b>Signature:</b>
@@ -139,7 +100,6 @@ func main() {
```go
func CopyFile(srcFilePath string, dstFilePath string) error
```
<b>Example:</b>
```go
@@ -147,19 +107,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
```
### <span id="FileMode">FileMode</span>
### <span id="FileMode">FileMode</span>
<p>Return file mode infomation.</p>
<b>Signature:</b>
@@ -167,7 +128,6 @@ func main() {
```go
func FileMode(path string) (fs.FileMode, error)
```
<b>Example:</b>
```go
@@ -175,28 +135,28 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
### <span id="MiMeType">MiMeType</span>
### <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 interface{}) string
func MiMeType(file any) string
```
<b>Example:</b>
```go
@@ -205,7 +165,7 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -218,8 +178,10 @@ func main() {
}
```
### <span id="IsExist">IsExist</span>
### <span id="IsExist">IsExist</span>
<p>Checks if a file or directory exists.</p>
<b>Signature:</b>
@@ -227,7 +189,6 @@ func main() {
```go
func IsExist(path string) bool
```
<b>Example:</b>
```go
@@ -235,7 +196,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -245,8 +206,9 @@ func main() {
}
```
### <span id="IsLink">IsLink</span>
### <span id="IsLink">IsLink</span>
<p>Checks if a file is symbol link or not.</p>
<b>Signature:</b>
@@ -254,7 +216,6 @@ func main() {
```go
func IsLink(path string) bool
```
<b>Example:</b>
```go
@@ -262,7 +223,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -271,16 +232,16 @@ func main() {
}
```
### <span id="IsDir">IsDir</span>
### <span id="IsDir">IsDir</span>
<p>Checks if the path is directy or not.</p>
<b>Signature:</b>
```go
func IsDir(path string) bool
func IsDir(path string) bool
```
<b>Example:</b>
```go
@@ -288,7 +249,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -300,8 +261,9 @@ func main() {
}
```
### <span id="ListFileNames">ListFileNames</span>
### <span id="ListFileNames">ListFileNames</span>
<p>List all file names in given path.</p>
<b>Signature:</b>
@@ -309,7 +271,6 @@ func main() {
```go
func ListFileNames(path string) ([]string, error)
```
<b>Example:</b>
```go
@@ -317,7 +278,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -326,8 +287,9 @@ func main() {
}
```
### <span id="RemoveFile">RemoveFile</span>
### <span id="RemoveFile">RemoveFile</span>
<p>Remove the file of path.</p>
<b>Signature:</b>
@@ -335,7 +297,6 @@ func main() {
```go
func RemoveFile(path string) error
```
<b>Example:</b>
```go
@@ -343,19 +304,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(err)
}
}
```
### <span id="ReadFileToString">ReadFileToString</span>
### <span id="ReadFileToString">ReadFileToString</span>
<p>Return string of file content.</p>
<b>Signature:</b>
@@ -363,7 +324,6 @@ func main() {
```go
func ReadFileToString(path string) (string, error)
```
<b>Example:</b>
```go
@@ -372,23 +332,24 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
### <span id="ReadFileByLine">ReadFileByLine</span>
### <span id="ReadFileByLine">ReadFileByLine</span>
<p>Read file line by line, and return slice of lines</p>
<b>Signature:</b>
@@ -396,7 +357,6 @@ func main() {
```go
func ReadFileByLine(path string)([]string, error)
```
<b>Example:</b>
```go
@@ -405,24 +365,25 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
### <span id="Zip">Zip</span>
### <span id="Zip">Zip</span>
<p>Create a zip file of fpath, fpath could be a file or a directory.</p>
<b>Signature:</b>
@@ -430,7 +391,6 @@ func main() {
```go
func Zip(fpath string, destPath string) error
```
<b>Example:</b>
```go
@@ -438,19 +398,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span>
### <span id="UnZip">UnZip</span>
<p>Unzip the file and save it to dest path.</p>
<b>Signature:</b>
@@ -458,7 +420,6 @@ func main() {
```go
func UnZip(zipFile string, destPath string) error
```
<b>Example:</b>
```go
@@ -466,300 +427,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>return current absolute path.</p>
<b>Signature:</b>
```go
func CurrentPath() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
absPath := CurrentPath()
fmt.Println(absPath)
}
```
### <span id="IsZipFile">IsZipFile</span>
<p>Checks if file is zip file or not.</p>
<b>Signature:</b>
```go
func IsZipFile(filepath string) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
isZip := IsZipFile("./zipfile.zip")
fmt.Println(isZip)
}
```
### <span id="FileSize">FileSize</span>
<p>Returns file size in bytes.</p>
<b>Signature:</b>
```go
func FileSize(path string) (int64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
size, err := fileutil.FileSize("./testdata/test.txt")
fmt.Println(size)
fmt.Println(err)
// Output:
// 20
// <nil>
}
```
### <span id="MTime">MTime</span>
<p>Returns file modified time(unix timestamp).</p>
<b>Signature:</b>
```go
func MTime(filepath string) (int64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
mtime, err := fileutil.MTime("./testdata/test.txt")
fmt.Println(mtime)
fmt.Println(err)
// Output:
// 1682391110
// <nil>
}
```
### <span id="Sha">Sha</span>
<p>returns file sha value, param `shaType` should be 1, 256 or 512.</p>
<b>Signature:</b>
```go
func Sha(filepath string, shaType ...int) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
fmt.Println(sha1)
fmt.Println(sha256)
fmt.Println(sha512)
fmt.Println(err)
// Output:
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
// <nil>
}
```
### <span id="ReadCsvFile">ReadCsvFile</span>
<p>Reads file content into slice.</p>
<b>Signature:</b>
```go
func ReadCsvFile(filepath string) ([][]string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
fmt.Println(content)
fmt.Println(err)
// Output:
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
// <nil>
}
```
### <span id="WriteBytesToFile">WriteBytesToFile</span>
<p>Writes bytes to target file.</p>
<b>Signature:</b>
```go
func WriteBytesToFile(filepath string, content []byte) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="WriteStringToFile">WriteStringToFile</span>
<p>Writes string to target file.</p>
<b>Signature:</b>
```go
func WriteStringToFile(filepath string, content string, append bool) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteStringToFile(filepath, "hello", true)
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```

View File

@@ -1,57 +1,47 @@
# Fileutil
fileutil 包支持文件基本操作。
fileutil包支持文件基本操作。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/fileutil/file.go](https://github.com/duke-git/lancet/blob/v1/fileutil/file.go)
- [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/fileutil"
"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)
- [ClearFile](#ClearFile)
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
- [IsLink](#IsLink)
- [IsDir](#IsDir)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
- [CurrentPath](#CurrentPath)
- [IsZipFile](#IsZipFile)
- [FileSize](#FileSize)
- [MTime](#MTime)
- [Sha](#Sha)
- [ReadCsvFile](#ReadCsvFile)
- [WriteStringToFile](#WriteStringToFile)
- [WriteBytesToFile](#WriteBytesToFile)
- [ListFileNames](#ListFileNames)
- [RemoveFile](#RemoveFile)
- [ReadFileToString](#ReadFileToString)
- [ReadFileByLine](#ReadFileByLine)
- [Zip](#Zip)
- [UnZip](#UnZip)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="ClearFile">ClearFile</span>
### <span id="ClearFile">ClearFile</span>
<p>清空文件内容</p>
<b>函数签名:</b>
@@ -59,7 +49,6 @@ import (
```go
func ClearFile(path string) error
```
<b>例子:</b>
```go
@@ -67,7 +56,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -78,34 +67,7 @@ func main() {
}
```
### <span id="CreateDir">CreateDir</span>
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
<b>函数签名:</b>
```go
func CreateDir(absPath string) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
err := fileutil.CreateDir("/a/")
fmt.Println(err)
}
```
### <span id="CreateFile">CreateFile</span>
<p>创建文件创建成功返回true, 否则返回false</p>
<b>函数签名:</b>
@@ -113,7 +75,6 @@ func main() {
```go
func CreateFile(path string) bool
```
<b>例子:</b>
```go
@@ -121,7 +82,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -130,8 +91,8 @@ func main() {
}
```
### <span id="CopyFile">CopyFile</span>
### <span id="CopyFile">CopyFile</span>
<p>拷贝文件,会覆盖原有的拷贝文件</p>
<b>函数签名:</b>
@@ -139,7 +100,6 @@ func main() {
```go
func CopyFile(srcFilePath string, dstFilePath string) error
```
<b>例子:</b>
```go
@@ -147,19 +107,20 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.CopyFile("./test.txt", "./test_copy.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
```
### <span id="FileMode">FileMode</span>
### <span id="FileMode">FileMode</span>
<p>获取文件mode信息</p>
<b>函数签名:</b>
@@ -167,7 +128,6 @@ func main() {
```go
func FileMode(path string) (fs.FileMode, error)
```
<b>例子:</b>
```go
@@ -175,28 +135,28 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
mode, err := fileutil.FileMode("./test.txt")
if err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
fmt.Println(mode)
}
```
### <span id="MiMeType">MiMeType</span>
### <span id="MiMeType">MiMeType</span>
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
<b>函数签名:</b>
```go
func MiMeType(file interface{}) string
func MiMeType(file any) string
```
<b>例子:</b>
```go
@@ -205,7 +165,7 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -218,8 +178,10 @@ func main() {
}
```
### <span id="IsExist">IsExist</span>
### <span id="IsExist">IsExist</span>
<p>判断文件或目录是否存在</p>
<b>函数签名:</b>
@@ -227,7 +189,6 @@ func main() {
```go
func IsExist(path string) bool
```
<b>例子:</b>
```go
@@ -235,7 +196,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -245,8 +206,9 @@ func main() {
}
```
### <span id="IsLink">IsLink</span>
### <span id="IsLink">IsLink</span>
<p>判断文件是否是符号链接</p>
<b>函数签名:</b>
@@ -254,7 +216,6 @@ func main() {
```go
func IsLink(path string) bool
```
<b>例子:</b>
```go
@@ -262,7 +223,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -271,16 +232,16 @@ func main() {
}
```
### <span id="IsDir">IsDir</span>
### <span id="IsDir">IsDir</span>
<p>判断目录是否存在</p>
<b>函数签名:</b>
```go
func IsDir(path string) bool
func IsDir(path string) bool
```
<b>例子:</b>
```go
@@ -288,7 +249,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -300,8 +261,9 @@ func main() {
}
```
### <span id="ListFileNames">ListFileNames</span>
### <span id="ListFileNames">ListFileNames</span>
<p>返回目录下所有文件名</p>
<b>函数签名:</b>
@@ -309,7 +271,6 @@ func main() {
```go
func ListFileNames(path string) ([]string, error)
```
<b>例子:</b>
```go
@@ -317,7 +278,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
@@ -326,8 +287,9 @@ func main() {
}
```
### <span id="RemoveFile">RemoveFile</span>
### <span id="RemoveFile">RemoveFile</span>
<p>删除文件</p>
<b>函数签名:</b>
@@ -335,7 +297,6 @@ func main() {
```go
func RemoveFile(path string) error
```
<b>例子:</b>
```go
@@ -343,19 +304,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.RemoveFile("./test.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(err)
}
}
```
### <span id="ReadFileToString">ReadFileToString</span>
### <span id="ReadFileToString">ReadFileToString</span>
<p>读取文件内容并返回字符串</p>
<b>函数签名:</b>
@@ -363,7 +324,6 @@ func main() {
```go
func ReadFileToString(path string) (string, error)
```
<b>例子:</b>
```go
@@ -372,23 +332,24 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./test.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
f.WriteString("hello world")
content, _ := fileutil.ReadFileToString(path)
content, _ := fileutil.ReadFileToString(path)
fmt.Println(content) //hello world
}
```
### <span id="ReadFileByLine">ReadFileByLine</span>
### <span id="ReadFileByLine">ReadFileByLine</span>
<p>按行读取文件内容,返回字符串切片包含每一行</p>
<b>函数签名:</b>
@@ -396,7 +357,6 @@ func main() {
```go
func ReadFileByLine(path string)([]string, error)
```
<b>例子:</b>
```go
@@ -405,24 +365,25 @@ package main
import (
"fmt"
"os"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
path := "./text.txt"
fileutil.CreateFile(path)
fileutil.CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
contents, _ := fileutil.ReadFileByLine(path)
contents, _ := fileutil.ReadFileByLine(path)
fmt.Println(contents) //[]string{"hello", "world"}
}
```
### <span id="Zip">Zip</span>
### <span id="Zip">Zip</span>
<p>zip压缩文件, fpath参数可以是文件或目录</p>
<b>函数签名:</b>
@@ -430,7 +391,6 @@ func main() {
```go
func Zip(fpath string, destPath string) error
```
<b>例子:</b>
```go
@@ -438,27 +398,28 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.txt", "./test.zip")
err := fileutil.Zip("./test.txt", "./test.zip")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="UnZip">UnZip</span>
### <span id="UnZip">UnZip</span>
<p>zip解压缩文件并保存在目录中</p>
<b>函数签名:</b>
<b>Signature:</b>
```go
func UnZip(zipFile string, destPath string) error
```
<b>例子:</b>
```go
@@ -466,299 +427,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>返回当前位置的绝对路径。</p>
<b>函数签名:</b>
```go
func CurrentPath() string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
absPath := CurrentPath()
fmt.Println(absPath)
}
```
### <span id="IsZipFile">IsZipFile</span>
<p>判断文件是否是zip压缩文件。</p>
<b>函数签名:</b>
```go
func IsZipFile(filepath string) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
isZip := IsZipFile("./zipfile.zip")
fmt.Println(isZip)
}
```
### <span id="FileSize">FileSize</span>
<p>返回文件字节大小。</p>
<b>函数签名:</b>
```go
func FileSize(path string) (int64, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
size, err := fileutil.FileSize("./testdata/test.txt")
fmt.Println(size)
fmt.Println(err)
// Output:
// 20
// <nil>
}
```
### <span id="MTime">MTime</span>
<p>返回文件修改时间(unix timestamp).</p>
<b>函数签名:</b>
```go
func MTime(filepath string) (int64, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
mtime, err := fileutil.MTime("./testdata/test.txt")
fmt.Println(mtime)
fmt.Println(err)
// Output:
// 1682391110
// <nil>
}
```
### <span id="Sha">Sha</span>
<p>返回文件sha值参数`shaType` 应传值为: 1, 256512.</p>
<b>函数签名:</b>
```go
func Sha(filepath string, shaType ...int) (string, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
sha1, err := fileutil.Sha("./testdata/test.txt", 1)
sha256, _ := fileutil.Sha("./testdata/test.txt", 256)
sha512, _ := fileutil.Sha("./testdata/test.txt", 512)
fmt.Println(sha1)
fmt.Println(sha256)
fmt.Println(sha512)
fmt.Println(err)
// Output:
// dda3cf10c5a6ff6c6659a497bf7261b287af2bc7
// aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35
// d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870
// <nil>
}
```
### <span id="ReadCsvFile">ReadCsvFile</span>
<p>读取csv文件内容到切片</p>
<b>函数签名:</b>
```go
func ReadCsvFile(filepath string) ([][]string, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
content, err := fileutil.ReadCsvFile("./testdata/test.csv")
fmt.Println(content)
fmt.Println(err)
// Output:
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
// <nil>
}
```
### <span id="WriteBytesToFile">WriteBytesToFile</span>
<p>将bytes写入文件。</p>
<b>函数签名:</b>
```go
func WriteBytesToFile(filepath string, content []byte) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```
### <span id="WriteStringToFile">WriteStringToFile</span>
<p>将字符串写入文件。</p>
<b>函数签名:</b>
```go
func WriteStringToFile(filepath string, content string, append bool) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/fileutil"
)
func main() {
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
return
}
defer file.Close()
err = fileutil.WriteStringToFile(filepath, "hello", true)
if err != nil {
return
}
content, err := fileutil.ReadFileToString(filepath)
if err != nil {
return
}
os.Remove(filepath)
fmt.Println(content)
// Output:
// hello
}
```

View File

@@ -1,50 +1,41 @@
# Formatter
formatter contains some functions for data formatting.
<div STYLE="page-break-after: always;"></div>
## Source:
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
- [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/formatter"
"github.com/duke-git/lancet/v2/formatter"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Comma](#Comma)
- [Pretty](#Pretty)
- [PrettyToWriter](#PrettyToWriter)
- [DecimalBytes](#DecimalBytes)
- [BinaryBytes](#BinaryBytes)
- [ParseDecimalBytes](#ParseDecimalBytes)
- [ParseBinaryBytes](#ParseBinaryBytes)
- [Comma](#Comma)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Comma">Comma</span>
### <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(value interface{}, symbol string) string
func Comma(v any, symbol string) string
```
<b>Example:</b>
```go
@@ -52,7 +43,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
"github.com/duke-git/lancet/v2/formatter"
)
func main() {
@@ -60,241 +51,3 @@ func main() {
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
```
### <span id="Pretty">Pretty</span>
<p>Pretty data to JSON string.</p>
<b>Signature:</b>
```go
func Pretty(v interface{}) (string, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
result2, _ := formatter.Pretty(map[string]int{"a": 1})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [
// "a",
// "b",
// "c"
// ]
// {
// "a": 1
// }
}
```
### <span id="PrettyToWriter">PrettyToWriter</span>
<p>Pretty encode data to writer.</p>
<b>Signature:</b>
```go
func PrettyToWriter(v interface{}, out io.Writer) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
type User struct {
Name string `json:"name"`
Aage uint `json:"age"`
}
user := User{Name: "King", Aage: 10000}
buf := &bytes.Buffer{}
err := formatter.PrettyToWriter(user, buf)
fmt.Println(buf)
fmt.Println(err)
// Output:
// {
// "name": "King",
// "age": 10000
// }
//
// <nil>
}
```
### <span id="DecimalBytes">DecimalBytes</span>
<p>Returns a human readable byte size under decimal standard (base 1000). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
<b>Signature:</b>
```go
func DecimalBytes(size float64, precision ...int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1 := formatter.DecimalBytes(1000)
result2 := formatter.DecimalBytes(1024)
result3 := formatter.DecimalBytes(1234567)
result4 := formatter.DecimalBytes(1234567, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 1KB
// 1.024KB
// 1.2346MB
// 1.235MB
}
```
### <span id="BinaryBytes">BinaryBytes</span>
<p>Returns a human readable byte size under binary standard (base 1024). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
<b>Signature:</b>
```go
func BinaryBytes(size float64, precision ...int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1 := formatter.BinaryBytes(1024)
result2 := formatter.BinaryBytes(1024 * 1024)
result3 := formatter.BinaryBytes(1234567)
result4 := formatter.BinaryBytes(1234567, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 1KiB
// 1MiB
// 1.1774MiB
// 1.18MiB
}
```
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
<p>Returns the human readable bytes size string into the amount it represents(base 1000).</p>
<b>Signature:</b>
```go
func ParseDecimalBytes(size string) (uint64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.ParseDecimalBytes("12")
result2, _ := formatter.ParseDecimalBytes("12k")
result3, _ := formatter.ParseDecimalBytes("12 Kb")
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 12
// 12000
// 12000
// 12200
}
```
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
<p>Returns the human readable bytes size string into the amount it represents(base 1024).</p>
<b>Signature:</b>
```go
func ParseBinaryBytes(size string) (uint64, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.ParseBinaryBytes("12")
result2, _ := formatter.ParseBinaryBytes("12ki")
result3, _ := formatter.ParseBinaryBytes("12 KiB")
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 12
// 12288
// 12288
// 12492
}
```

View File

@@ -1,49 +1,40 @@
# Formatter
formatter 格式化器包含一些数据格式化处理方法。
formatter格式化器包含一些数据格式化处理方法。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
- [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/formatter"
"github.com/duke-git/lancet/v2/formatter"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Comma](#Comma)
- [Pretty](#Pretty)
- [PrettyToWriter](#PrettyToWriter)
- [DecimalBytes](#DecimalBytes)
- [BinaryBytes](#BinaryBytes)
- [ParseDecimalBytes](#ParseDecimalBytes)
- [ParseBinaryBytes](#ParseBinaryBytes)
- [Comma](#Comma)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Comma">Comma</span>
### <span id="Comma">Comma</span>
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
<b>函数签名:</b>
```go
func Comma(v interface{}, symbol string) string
func Comma(v any, symbol string) string
```
<b>例子:</b>
```go
@@ -51,7 +42,7 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
"github.com/duke-git/lancet/v2/formatter"
)
func main() {
@@ -59,241 +50,3 @@ func main() {
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
}
```
### <span id="Pretty">Pretty</span>
<p>返回pretty JSON字符串.</p>
<b>函数签名:</b>
```go
func Pretty(v interface{}) (string, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
result2, _ := formatter.Pretty(map[string]int{"a": 1})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [
// "a",
// "b",
// "c"
// ]
// {
// "a": 1
// }
}
```
### <span id="PrettyToWriter">PrettyToWriter</span>
<p>Pretty encode数据到writer。</p>
<b>函数签名:</b>
```go
func PrettyToWriter(v interface{}, out io.Writer) error
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
type User struct {
Name string `json:"name"`
Aage uint `json:"age"`
}
user := User{Name: "King", Aage: 10000}
buf := &bytes.Buffer{}
err := formatter.PrettyToWriter(user, buf)
fmt.Println(buf)
fmt.Println(err)
// Output:
// {
// "name": "King",
// "age": 10000
// }
//
// <nil>
}
```
### <span id="DecimalBytes">DecimalBytes</span>
<p>返回十进制标准以1000为基数下的可读字节单位字符串。precision参数指定小数点后的位数默认为4。</p>
<b>函数签名:</b>
```go
func DecimalBytes(size float64, precision ...int) string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1 := formatter.DecimalBytes(1000)
result2 := formatter.DecimalBytes(1024)
result3 := formatter.DecimalBytes(1234567)
result4 := formatter.DecimalBytes(1234567, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 1KB
// 1.024KB
// 1.2346MB
// 1.235MB
}
```
### <span id="BinaryBytes">BinaryBytes</span>
<p>返回binary标准以1024为基数下的可读字节单位字符串。precision参数指定小数点后的位数默认为4。</p>
<b>函数签名:</b>
```go
func BinaryBytes(size float64, precision ...int) string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1 := formatter.BinaryBytes(1024)
result2 := formatter.BinaryBytes(1024 * 1024)
result3 := formatter.BinaryBytes(1234567)
result4 := formatter.BinaryBytes(1234567, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 1KiB
// 1MiB
// 1.1774MiB
// 1.18MiB
}
```
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
<p>将字节单位字符串转换成其所表示的字节数以1000为基数。</p>
<b>函数签名:</b>
```go
func ParseDecimalBytes(size string) (uint64, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.ParseDecimalBytes("12")
result2, _ := formatter.ParseDecimalBytes("12k")
result3, _ := formatter.ParseDecimalBytes("12 Kb")
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 12
// 12000
// 12000
// 12200
}
```
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
<p>将字节单位字符串转换成其所表示的字节数以1024为基数。</p>
<b>函数签名:</b>
```go
func ParseBinaryBytes(size string) (uint64, error)
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/formatter"
)
func main() {
result1, _ := formatter.ParseBinaryBytes("12")
result2, _ := formatter.ParseBinaryBytes("12ki")
result3, _ := formatter.ParseBinaryBytes("12 KiB")
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 12
// 12288
// 12288
// 12492
}
```

View File

@@ -1,52 +1,47 @@
# 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/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
- [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/function"
"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)
- [Pipeline](#Pipeline)
- [Schedule](#Schedule)
- [Watcher](#Watcher)
- [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>
### <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 interface{}) func(args ...interface{}) []reflect.Value
func After(n int, fn any) func(args ...any) []reflect.Value
```
<b>Example:</b>
```go
@@ -54,35 +49,37 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"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
})
arr := []string{"a", "b"}
f := function.After(len(arr), func(i int) int {
fmt.Println("last print")
return i
})
type cb func(args ...interface{}) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("arr[%d] is %s \n", i, s)
fn(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)
}
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
// 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>
@@ -90,9 +87,8 @@ func main() {
<b>Signature:</b>
```go
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
func Before(n int, fn any) func(args ...any) []reflect.Value
```
<b>Example:</b>
```go
@@ -100,34 +96,36 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/internal"
"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
})
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...interface{}) []reflect.Value
appendStr := func(i int, s string, fn cb) {
v := fn(i)
res = append(res, v[0].Int())
}
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)
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
}
```
### <span id="Curry">Curry</span>
<p>Make a curry function.</p>
@@ -135,10 +133,9 @@ func main() {
<b>Signature:</b>
```go
type Fn func(...interface{}) interface{}
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
```
<b>Example:</b>
```go
@@ -146,22 +143,24 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...interface{}) interface{} {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
result := add1(2)
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>
@@ -169,9 +168,8 @@ func main() {
<b>Signature:</b>
```go
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
func Compose(fnList ...func(...any) any) func(...any) any
```
<b>Example:</b>
```go
@@ -179,24 +177,26 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add1 := func(v ...interface{}) interface{} {
return v[0].(int) + 1
}
add2 := func(v ...interface{}) interface{} {
return v[0].(int) + 2
}
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)
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>
@@ -206,7 +206,6 @@ func main() {
```go
func Debounced(fn func(), duration time.Duration) func()
```
<b>Example:</b>
```go
@@ -214,30 +213,32 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
add := func() {
count++
}
add := func() {
count++
}
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
}
```
### <span id="Delay">Delay</span>
<p>Invoke function after delayed time.</p>
@@ -245,9 +246,8 @@ func main() {
<b>Signature:</b>
```go
func Delay(delay time.Duration, fn interface{}, args ...interface{})
func Delay(delay time.Duration, fn any, args ...any)
```
<b>Example:</b>
```go
@@ -255,17 +255,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"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")
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>
@@ -273,9 +275,8 @@ func main() {
<b>Signature:</b>
```go
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
func Schedule(d time.Duration, fn any, args ...any) chan bool
```
<b>Example:</b>
```go
@@ -283,65 +284,24 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var res []string
appendStr := func(s string) {
res = append(res, s)
}
appendStr := func(s string) {
res = append(res, s)
}
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
fmt.Println(res) //[* * * * *]
fmt.Println(res) //[* * * * *]
}
```
### <span id="Pipeline">Pipeline</span>
<p>Pipeline takes a list of functions and returns a function whose param will be passed into
the functions one by one.</p>
<b>Signature:</b>
```go
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
addOne := func(x interface{}) interface{} {
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
f := function.Pipeline(addOne, double, square)
result := fn(2)
fmt.Println(result)
// Output:
// 36
}
```
### <span id="Watcher">Watcher</span>
@@ -351,16 +311,15 @@ func main() {
```go
type Watcher struct {
startTime int64
stopTime int64
excuting bool
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
@@ -368,35 +327,38 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
w := &function.Watcher{}
w.Start()
w.Start()
longRunningTask()
longRunningTask()
fmt.Println(w.excuting) //true
fmt.Println(w.excuting) //true
w.Stop()
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
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))
}
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}
```

View File

@@ -1,52 +1,47 @@
# Function
function 函数包控制函数执行流程,包含部分函数式编程。
function函数包控制函数执行流程包含部分函数式编程。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
- [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/function"
"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)
- [Pipeline](#Pipeline)
- [Schedule](#Schedule)
- [Watcher](#Watcher)
- [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>
### <span id="After">After</span>
<p>创建一个函数当他被调用n或更多次之后将马上触发fn</p>
<b>函数签名:</b>
```go
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
func After(n int, fn any) func(args ...any) []reflect.Value
```
<b>例子:</b>
```go
@@ -54,35 +49,37 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"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
})
arr := []string{"a", "b"}
f := function.After(len(arr), func(i int) int {
fmt.Println("last print")
return i
})
type cb func(args ...interface{}) []reflect.Value
print := func(i int, s string, fn cb) {
fmt.Printf("arr[%d] is %s \n", i, s)
fn(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)
}
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
// arr[0] is a
// arr[1] is b
// last print
}
```
### <span id="Before">Before</span>
<p>创建一个函数调用次数不超过n次之后再调用这个函数将返回一次最后调用fn的结果</p>
@@ -90,9 +87,8 @@ func main() {
<b>函数签名:</b>
```go
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
func Before(n int, fn any) func(args ...any) []reflect.Value
```
<b>例子:</b>
```go
@@ -100,34 +96,36 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/function"
"github.com/duke-git/lancet/v2/internal"
)
func main() {
assert := internal.NewAssert(t, "TestBefore")
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
})
arr := []string{"a", "b", "c", "d", "e"}
f := function.Before(3, func(i int) int {
return i
})
var res []int64
type cb func(args ...interface{}) []reflect.Value
appendStr := func(i int, s string, fn cb) {
v := fn(i)
res = append(res, v[0].Int())
}
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)
}
for i := 0; i < len(arr); i++ {
appendStr(i, arr[i], f)
}
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
expected := []int64{0, 1, 2, 2, 2}
assert.Equal(expected, res)
}
```
### <span id="Curry">Curry</span>
<p>创建一个柯里化的函数</p>
@@ -135,10 +133,9 @@ func main() {
<b>函数签名:</b>
```go
type Fn func(...interface{}) interface{}
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
```
<b>例子:</b>
```go
@@ -146,22 +143,24 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...interface{}) interface{} {
return add(values[0].(int), values[1].(int))
}
add1 := addCurry.Curry(1)
result := add1(2)
fmt.Println(result) //3
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>
@@ -169,9 +168,8 @@ func main() {
<b>函数签名:</b>
```go
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
func Compose(fnList ...func(...any) any) func(...any) any
```
<b>例子:</b>
```go
@@ -179,24 +177,26 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
add1 := func(v ...interface{}) interface{} {
return v[0].(int) + 1
}
add2 := func(v ...interface{}) interface{} {
return v[0].(int) + 2
}
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)
add3 := function.Compose(add1, add2)
result := add3(1)
fmt.Println(result) //4
fmt.Println(result) //4
}
```
### <span id="Debounced">Debounced</span>
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
@@ -206,7 +206,6 @@ func main() {
```go
func Debounced(fn func(), duration time.Duration) func()
```
<b>例子:</b>
```go
@@ -214,30 +213,32 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
count := 0
add := func() {
count++
}
count := 0
add := func() {
count++
}
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //1
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
function.debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count) //2
}
```
### <span id="Delay">Delay</span>
<p>延迟delay时间后调用函数</p>
@@ -245,9 +246,8 @@ func main() {
<b>函数签名:</b>
```go
func Delay(delay time.Duration, fn interface{}, args ...interface{})
func Delay(delay time.Duration, fn any, args ...any)
```
<b>例子:</b>
```go
@@ -255,17 +255,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"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")
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>
@@ -273,9 +275,8 @@ func main() {
<b>函数签名:</b>
```go
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
func Schedule(d time.Duration, fn any, args ...any) chan bool
```
<b>例子:</b>
```go
@@ -283,64 +284,24 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
var res []string
appendStr := func(s string) {
res = append(res, s)
}
appendStr := func(s string) {
res = append(res, s)
}
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
stop := function.Schedule(1*time.Second, appendStr, "*")
time.Sleep(5 * time.Second)
close(stop)
fmt.Println(res) //[* * * * *]
}
```
### <span id="Pipeline">Pipeline</span>
<p>管道执行多个函数</p>
<b>函数签名:</b>
```go
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/function"
)
func main() {
addOne := func(x interface{}) interface{} {
return x.(int) + 1
}
double := func(x interface{}) interface{} {
return 2 * x.(int)
}
square := func(x interface{}) interface{} {
return x.(int) * x.(int)
}
f := function.Pipeline(addOne, double, square)
result := fn(2)
fmt.Println(result)
// Output:
// 36
}
```
### <span id="Watcher">Watcher</span>
@@ -350,16 +311,15 @@ func main() {
```go
type Watcher struct {
startTime int64
stopTime int64
excuting bool
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
@@ -367,35 +327,38 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/function"
"github.com/duke-git/lancet/v2/function"
)
func main() {
w := &function.Watcher{}
w.Start()
w.Start()
longRunningTask()
longRunningTask()
fmt.Println(w.excuting) //true
fmt.Println(w.excuting) //true
w.Stop()
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
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))
}
var slice []int64
for i := 0; i < 10000000; i++ {
slice = append(slice, int64(i))
}
}
```

304
docs/maputil.md Normal file
View File

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

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

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

View File

@@ -1,49 +1,72 @@
# Mathutil
Package mathutil implements some functions for math calculation.
<div STYLE="page-break-after: always;"></div>
## Source:
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
- [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/mathutil"
"github.com/duke-git/lancet/v2/mathutil"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Average](#Average)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Max](#Max)
- [Min](#Min)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
- [GCD](#GCD)
- [LCM](#LCM)
- [Cos](#Cos)
- [Sin](#Sin)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Exponent">Exponent</span>
### <span id="Average">Average</span>
<p>Return average value of numbers. Maybe call RoundToFloat to round result.</p>
<b>Signature:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Average(0, 0)) //0
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
}
```
### <span id="Exponent">Exponent</span>
<p>Calculate x to the nth power.</p>
<b>Signature:</b>
@@ -51,7 +74,6 @@ import (
```go
func Exponent(x, n int64) int64
```
<b>Example:</b>
```go
@@ -59,18 +81,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Fibonacci">Fibonacci</span>
<p>Calculate the nth number of fibonacci sequence.</p>
<b>Signature:</b>
@@ -78,7 +101,6 @@ func main() {
```go
func Fibonacci(first, second, n int) int
```
<b>Example:</b>
```go
@@ -86,20 +108,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Factorial">Factorial</span>
<p>Calculate the factorial of x.</p>
<b>Signature:</b>
@@ -107,7 +130,6 @@ func main() {
```go
func Factorial(x uint) uint
```
<b>Example:</b>
```go
@@ -115,19 +137,74 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Max">Max</span>
<p>Return max value of numbers.</p>
<b>Signature:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Max(0, 0)) //0
fmt.Println(mathutil.Max(1, 2, 3)) //3
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
}
```
### <span id="Min">Min</span>
<p>Return min value of numbers.</p>
<b>Signature:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Min(0, 0)) //0
fmt.Println(mathutil.Min(1, 2, 3)) //1
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
}
```
### <span id="Percent">Percent</span>
<p>calculate the percentage of val to total, retain n decimal places.</p>
<b>Signature:</b>
@@ -135,7 +212,6 @@ func main() {
```go
func Percent(val, total float64, n int) float64
```
<b>Example:</b>
```go
@@ -143,17 +219,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
}
```
### <span id="RoundToFloat">RoundToFloat</span>
### <span id="RoundToFloat">RoundToFloat</span>
<p>Round float up to n decimal places.</p>
<b>Signature:</b>
@@ -161,7 +238,6 @@ func main() {
```go
func RoundToFloat(x float64, n int) float64
```
<b>Example:</b>
```go
@@ -169,20 +245,22 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="RoundToString">RoundToString</span>
<p>Round float up to n decimal places. will return string.</p>
<b>Signature:</b>
@@ -190,7 +268,6 @@ func main() {
```go
func RoundToString(x float64, n int) string
```
<b>Example:</b>
```go
@@ -198,20 +275,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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"
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>
### <span id="TruncRound">TruncRound</span>
<p>Round float off n decimal places.</p>
<b>Signature:</b>
@@ -219,7 +297,6 @@ func main() {
```go
func TruncRound(x float64, n int) float64
```
<b>Example:</b>
```go
@@ -227,319 +304,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
}
```
### <span id="AngleToRadian">AngleToRadian</span>
<p>Converts angle value to radian value.</p>
<b>Signature:</b>
```go
func AngleToRadian(angle float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.AngleToRadian(45)
result2 := mathutil.AngleToRadian(90)
result3 := mathutil.AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
```
### <span id="RadianToAngle">RadianToAngle</span>
<p>Converts radian value to angle value.</p>
<b>Signature:</b>
```go
func RadianToAngle(radian float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.RadianToAngle(math.Pi)
result2 := mathutil.RadianToAngle(math.Pi / 2)
result3 := mathutil.RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
```
### <span id="PointDistance">PointDistance</span>
<p>Caculates two points distance.</p>
<b>Signature:</b>
```go
func PointDistance(x1, y1, x2, y2 float64) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
```
### <span id="IsPrime">IsPrime</span>
<p>Checks if number is prime number.</p>
<b>Signature:</b>
```go
func IsPrime(n int) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
```
### <span id="GCD">GCD</span>
<p>Return greatest common divisor (GCD) of integers.</p>
<b>Signature:</b>
```go
func GCD(integers ...int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.GCD(1, 1)
result2 := mathutil.GCD(1, -1)
result3 := mathutil.GCD(-1, 1)
result4 := mathutil.GCD(-1, -1)
result5 := mathutil.GCD(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// 1
// -1
// -1
// 3
}
```
### <span id="LCM">LCM</span>
<p>Return Least Common Multiple (LCM) of integers.</p>
<b>Signature:</b>
```go
func LCM(integers ...int) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.LCM(1, 1)
result2 := mathutil.LCM(1, 2)
result3 := mathutil.LCM(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 18
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
}
```
### <span id="Cos">Cos</span>
<p>Returns the cosine of the radian argument.</p>
<b>Signature:</b>
```go
func Cos(radian float64, precision ...int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Cos(0)
result2 := mathutil.Cos(90)
result3 := mathutil.Cos(180)
result4 := mathutil.Cos(math.Pi)
result5 := mathutil.Cos(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// -0.447
// -0.598
// -1
// 0
}
```
### <span id="Sin">Sin</span>
<p>Returns the sine of the radian argument.</p>
<b>Signature:</b>
```go
func Sin(radian float64, precision ...int) float64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Sin(0)
result2 := mathutil.Sin(90)
result3 := mathutil.Sin(180)
result4 := mathutil.Sin(math.Pi)
result5 := mathutil.Sin(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 0
// 0.894
// -0.801
// 0
// 1
}
```

View File

@@ -1,49 +1,70 @@
# Mathutil
mathutil 包实现了一些数学计算的函数.
mathutil包实现了一些数学计算的函数.
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
- [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/mathutil"
"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)
- [AngleToRadian](#AngleToRadian)
- [RadianToAngle](#RadianToAngle)
- [PointDistance](#PointDistance)
- [IsPrime](#IsPrime)
- [GCD](#GCD)
- [LCM](#LCM)
- [Cos](#Cos)
- [Sin](#Sin)
- [Average](#Average)
- [Exponent](#Exponent)
- [Fibonacci](#Fibonacci)
- [Factorial](#Factorial)
- [Max](#Max)
- [Min](#Min)
- [Percent](#Percent)
- [RoundToFloat](#RoundToFloat)
- [RoundToString](#RoundToString)
- [TruncRound](#TruncRound)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Exponent">Exponent</span>
### <span id="Average">Average</span>
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
<b>函数签名:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Average(0, 0)) //0
fmt.Println(mathutil.Average(1, 1)) //1
avg := mathutil.Average(1.2, 1.4) //1.2999999998
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
}
```
### <span id="Exponent">Exponent</span>
<p>指数计算x的n次方</p>
<b>函数签名:</b>
@@ -51,7 +72,6 @@ import (
```go
func Exponent(x, n int64) int64
```
<b>例子:</b>
```go
@@ -59,18 +79,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Fibonacci">Fibonacci</span>
<p>计算斐波那契数列的第n个数</p>
<b>函数签名:</b>
@@ -78,7 +99,6 @@ func main() {
```go
func Fibonacci(first, second, n int) int
```
<b>例子:</b>
```go
@@ -86,20 +106,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Factorial">Factorial</span>
<p>计算阶乘</p>
<b>函数签名:</b>
@@ -107,7 +128,6 @@ func main() {
```go
func Factorial(x uint) uint
```
<b>例子:</b>
```go
@@ -115,19 +135,73 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="Max">Max</span>
<p>返回参数中的最大数</p>
<b>函数签名:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Max(0, 0)) //0
fmt.Println(mathutil.Max(1, 2, 3)) //3
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
}
```
### <span id="Min">Min</span>
<p>返回参数中的最小数</p>
<b>函数签名:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
fmt.Println(mathutil.Min(0, 0)) //0
fmt.Println(mathutil.Min(1, 2, 3)) //1
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
}
```
### <span id="Percent">Percent</span>
<p>计算百分比保留n位小数</p>
<b>函数签名:</b>
@@ -135,7 +209,6 @@ func main() {
```go
func Percent(val, total float64, n int) float64
```
<b>例子:</b>
```go
@@ -143,17 +216,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
}
```
### <span id="RoundToFloat">RoundToFloat</span>
### <span id="RoundToFloat">RoundToFloat</span>
<p>四舍五入保留n位小数</p>
<b>函数签名:</b>
@@ -161,7 +235,6 @@ func main() {
```go
func RoundToFloat(x float64, n int) float64
```
<b>例子:</b>
```go
@@ -169,20 +242,22 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
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>
### <span id="RoundToString">RoundToString</span>
<p>四舍五入保留n位小数返回字符串</p>
<b>函数签名:</b>
@@ -190,7 +265,6 @@ func main() {
```go
func RoundToString(x float64, n int) string
```
<b>例子:</b>
```go
@@ -198,20 +272,21 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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"
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>
### <span id="TruncRound">TruncRound</span>
<p>截短n位小数不进行四舍五入</p>
<b>函数签名:</b>
@@ -219,7 +294,6 @@ func main() {
```go
func TruncRound(x float64, n int) float64
```
<b>例子:</b>
```go
@@ -227,320 +301,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
"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
}
```
### <span id="AngleToRadian">AngleToRadian</span>
<p>将角度值转为弧度值</p>
<b>函数签名:</b>
```go
func AngleToRadian(angle float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.AngleToRadian(45)
result2 := mathutil.AngleToRadian(90)
result3 := mathutil.AngleToRadian(180)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.7853981633974483
// 1.5707963267948966
// 3.141592653589793
}
```
### <span id="RadianToAngle">RadianToAngle</span>
<p>将弧度值转为角度值</p>
<b>函数签名:</b>
```go
func RadianToAngle(radian float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.RadianToAngle(math.Pi)
result2 := mathutil.RadianToAngle(math.Pi / 2)
result3 := mathutil.RadianToAngle(math.Pi / 4)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 180
// 90
// 45
}
```
### <span id="PointDistance">PointDistance</span>
<p>计算两个坐标点的距离</p>
<b>函数签名:</b>
```go
func PointDistance(x1, y1, x2, y2 float64) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.PointDistance(1, 1, 4, 5)
fmt.Println(result1)
// Output:
// 5
}
```
### <span id="IsPrime">IsPrime</span>
<p>判断质数。</p>
<b>函数签名:</b>
```go
func IsPrime(n int) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.IsPrime(-1)
result2 := mathutil.IsPrime(0)
result3 := mathutil.IsPrime(1)
result4 := mathutil.IsPrime(2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
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
}
```
### <span id="GCD">GCD</span>
<p>计算整数最大公约数。</p>
<b>函数签名:</b>
```go
func GCD(integers ...int) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.GCD(1, 1)
result2 := mathutil.GCD(1, -1)
result3 := mathutil.GCD(-1, 1)
result4 := mathutil.GCD(-1, -1)
result5 := mathutil.GCD(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// 1
// -1
// -1
// 3
}
```
### <span id="LCM">LCM</span>
<p>计算整数最小公倍数。</p>
<b>函数签名:</b>
```go
func LCM(integers ...int) int
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.LCM(1, 1)
result2 := mathutil.LCM(1, 2)
result3 := mathutil.LCM(3, 6, 9)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 18
}
```
### <span id="Cos">Cos</span>
<p>计算弧度的余弦值。</p>
<b>函数签名:</b>
```go
func Cos(radian float64, precision ...int) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Cos(0)
result2 := mathutil.Cos(90)
result3 := mathutil.Cos(180)
result4 := mathutil.Cos(math.Pi)
result5 := mathutil.Cos(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 1
// -0.447
// -0.598
// -1
// 0
}
```
### <span id="Sin">Sin</span>
<p>计算弧度的正弦值。</p>
<b>函数签名:</b>
```go
func Sin(radian float64, precision ...int) float64
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/mathutil"
)
func main() {
result1 := mathutil.Sin(0)
result2 := mathutil.Sin(90)
result3 := mathutil.Sin(180)
result4 := mathutil.Sin(math.Pi)
result5 := mathutil.Sin(math.Pi / 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 0
// 0.894
// -0.801
// 0
// 1
}
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,36 @@
# 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/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
- [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/random"
"github.com/duke-git/lancet/v2/random"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="RandBytes">RandBytes</span>
### <span id="RandBytes">RandBytes</span>
<p>Generate random byte slice.</p>
<b>Signature:</b>
@@ -44,7 +38,6 @@ import (
```go
func RandBytes(length int) []byte
```
<b>Example:</b>
```go
@@ -52,17 +45,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
}
```
### <span id="RandInt">RandInt</span>
### <span id="RandInt">RandInt</span>
<p>Generate random int between min and max, may contain min, not max.</p>
<b>Signature:</b>
@@ -70,7 +63,6 @@ func main() {
```go
func RandInt(min, max int) int
```
<b>Example:</b>
```go
@@ -78,25 +70,25 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
}
```
### <span id="RandString">RandString</span>
<p>Generate random given length string. only contains letter (a-zA-Z)</p>
### <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
@@ -104,121 +96,19 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //pGWsze
randStr := random.RandString(6)
fmt.Println(randStr)
}
```
### <span id="RandUpper">RandUpper</span>
<p>Generate a random upper case string</p>
<b>Signature:</b>
```go
func RandUpper(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //PACWGF
}
```
### <span id="RandLower">RandLower</span>
<p>Generate a random lower case string</p>
<b>Signature:</b>
```go
func RandLower(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandLower(6)
fmt.Println(randStr) //siqbew
}
```
### <span id="RandNumeral">RandNumeral</span>
<p>Generate a random numeral string</p>
<b>Signature:</b>
```go
func RandNumeral(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandNumeral(6)
fmt.Println(randStr) //035172
}
```
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
<p>generate a random numeral or letter string</p>
<b>Signature:</b>
```go
func RandNumeralOrLetter(length int) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandNumeralOrLetter(6)
fmt.Println(randStr) //0aW7cQ
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
<b>Signature:</b>
@@ -226,7 +116,6 @@ func main() {
```go
func UUIdV4() (string, error)
```
<b>Example:</b>
```go
@@ -234,14 +123,16 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
uuid, err := random.UUIdV4()
uuid, err := random.UUIdV4()
if err != nil {
return
}
fmt.Println(uuid)
fmt.Println(uuid)
}
```

View File

@@ -1,42 +1,37 @@
# Random
random 随机数生成器包,可以生成随机[]bytes, int, string。
random随机数生成器包可以生成随机[]bytes, int, string。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
- [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/random"
"github.com/duke-git/lancet/v2/random"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [UUIdV4](#UUIdV4)
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
- [RandNumeralOrLetter](#RandNumeralOrLetter)
- [UUIdV4](#UUIdV4)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="RandBytes">RandBytes</span>
### <span id="RandBytes">RandBytes</span>
<p>生成随机字节切片</p>
<b>函数签名:</b>
@@ -44,7 +39,6 @@ import (
```go
func RandBytes(length int) []byte
```
<b>例子:</b>
```go
@@ -52,17 +46,17 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
randBytes := random.RandBytes(4)
fmt.Println(randBytes)
}
```
### <span id="RandInt">RandInt</span>
### <span id="RandInt">RandInt</span>
<p>生成随机int, 范围[min, max)</p>
<b>函数签名:</b>
@@ -70,7 +64,6 @@ func main() {
```go
func RandInt(min, max int) int
```
<b>例子:</b>
```go
@@ -78,25 +71,25 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
rInt := random.RandInt(1, 10)
fmt.Println(rInt)
}
```
### <span id="RandString">RandString</span>
<p>生成给定长度的随机字符串,只包含字母(a-zA-Z)</p>
### <span id="RandString">RandInt</span>
<p>生成随机给定长度的随机字符串</p>
<b>函数签名:</b>
```go
func RandString(length int) string
```
<b>例子:</b>
```go
@@ -104,121 +97,18 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //pGWsze
randStr := random.RandString(6)
fmt.Println(randStr)
}
```
### <span id="RandUpper">RandUpper</span>
<p>生成给定长度的随机大写字母字符串</p>
<b>函数签名:</b>
```go
func RandUpper(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandString(6)
fmt.Println(randStr) //PACWGF
}
```
### <span id="RandLower">RandLower</span>
<p>生成给定长度的随机小写字母字符串</p>
<b>函数签名:</b>
```go
func RandLower(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandLower(6)
fmt.Println(randStr) //siqbew
}
```
### <span id="RandNumeral">RandNumeral</span>
<p>生成给定长度的随机数字字符串</p>
<b>函数签名:</b>
```go
func RandNumeral(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandNumeral(6)
fmt.Println(randStr) //035172
}
```
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
<p>生成给定长度的随机字符串(数字+字母)</p>
<b>函数签名:</b>
```go
func RandNumeralOrLetter(length int) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/random"
)
func main() {
randStr := random.RandNumeralOrLetter(6)
fmt.Println(randStr) //0aW7cQ
}
```
### <span id="UUIdV4">UUIdV4</span>
<p>生成UUID v4字符串</p>
<b>函数签名:</b>
@@ -226,7 +116,6 @@ func main() {
```go
func UUIdV4() (string, error)
```
<b>例子:</b>
```go
@@ -234,14 +123,16 @@ package main
import (
"fmt"
"github.com/duke-git/lancet/random"
"github.com/duke-git/lancet/v2/random"
)
func main() {
uuid, err := random.UUIdV4()
uuid, err := random.UUIdV4()
if err != nil {
return
}
fmt.Println(uuid)
fmt.Println(uuid)
}
```

View File

@@ -1,39 +1,37 @@
# 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/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
- [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/retry"
"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)
- [Context](#Context)
- [Retry](#Retry)
- [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Context">Context</span>
### <span id="Context">Context</span>
<p>Set retry context config, can cancel the retry with context.</p>
<b>Signature:</b>
@@ -41,42 +39,43 @@ import (
```go
func Context(ctx context.Context)
```
<b>Example:</b>
```go
import (
"context"
"errors"
"fmt"
"github.com/duke-git/lancet/retry"
"time"
"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")
}
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),
)
err := retry.Retry(increaseNumber,
retry.RetryDuration(time.Microsecond*50),
retry.Context(ctx),
)
if err != nil {
fmt.Println(err) //retry is cancelled
}
if err != nil {
fmt.Println(err) //retry is cancelled
}
}
```
### <span id="RetryFunc">RetryFunc</span>
### <span id="RetryFunc">RetryFunc</span>
<p>Function that retry executes.</p>
<b>Signature:</b>
@@ -84,7 +83,6 @@ func main() {
```go
type RetryFunc func() error
```
<b>Example:</b>
```go
@@ -94,31 +92,32 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber = func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="RetryTimes">RetryTimes</span>
### <span id="RetryTimes">RetryTimes</span>
<p>Set times of retry. Default times is 5.</p>
<b>Signature:</b>
@@ -126,7 +125,6 @@ func main() {
```go
func RetryTimes(n uint)
```
<b>Example:</b>
```go
@@ -136,28 +134,29 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
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
}
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>
### <span id="RetryDuration">RetryDuration</span>
<p>Set duration of retries. Default duration is 3 second.</p>
<b>Signature:</b>
@@ -165,7 +164,6 @@ func main() {
```go
func RetryDuration(d time.Duration)
```
<b>Example:</b>
```go
@@ -175,30 +173,30 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="Retry">Retry</span>
### <span id="Retry">Retry</span>
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
<b>Signature:</b>
@@ -206,7 +204,6 @@ func main() {
```go
func Retry(retryFunc RetryFunc, opts ...Option) error
```
<b>Example:</b>
```go
@@ -216,23 +213,23 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}

View File

@@ -1,39 +1,39 @@
# Retry
retry 重试执行函数直到函数运行成功或被 context cancel。
retry重试执行函数直到函数运行成功或被context cancel。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
- [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/retry"
"github.com/duke-git/lancet/v2/retry"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Context](#Context)
- [Retry](#Retry)
- [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes)
- [Context](#Context)
- [Retry](#Retry)
- [RetryFunc](#RetryFunc)
- [RetryDuration](#RetryDuration)
- [RetryTimes](#RetryTimes)
<div STYLE="page-break-after: always;"></div>
## Document 文档
## Document文档
### <span id="Context">Context</span>
<p>设置重试context参数</p>
<b>函数签名:</b>
@@ -41,42 +41,43 @@ import (
```go
func Context(ctx context.Context)
```
<b>例子:</b>
```go
import (
"context"
"errors"
"fmt"
"lancet-demo/retry"
"time"
"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")
}
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),
)
err := retry.Retry(increaseNumber,
retry.RetryDuration(time.Microsecond*50),
retry.Context(ctx),
)
if err != nil {
fmt.Println(err) //retry is cancelled
}
if err != nil {
fmt.Println(err) //retry is cancelled
}
}
```
### <span id="RetryFunc">RetryFunc</span>
### <span id="RetryFunc">RetryFunc</span>
<p>被重试执行的函数</p>
<b>函数签名:</b>
@@ -84,7 +85,6 @@ func main() {
```go
type RetryFunc func() error
```
<b>例子:</b>
```go
@@ -94,31 +94,32 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber = func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="RetryTimes">RetryTimes</span>
### <span id="RetryTimes">RetryTimes</span>
<p>设置重试次数默认5</p>
<b>函数签名:</b>
@@ -126,7 +127,6 @@ func main() {
```go
func RetryTimes(n uint)
```
<b>例子:</b>
```go
@@ -136,28 +136,29 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
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
}
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>
### <span id="RetryDuration">RetryDuration</span>
<p>设置重试间隔时间默认3秒</p>
<b>函数签名:</b>
@@ -165,7 +166,6 @@ func main() {
```go
func RetryDuration(d time.Duration)
```
<b>例子:</b>
```go
@@ -175,30 +175,30 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}
```
### <span id="Retry">Retry</span>
### <span id="Retry">Retry</span>
<p>重试执行函数retryFunc直到函数运行成功或被context停止</p>
<b>函数签名:</b>
@@ -206,7 +206,6 @@ func main() {
```go
func Retry(retryFunc RetryFunc, opts ...Option) error
```
<b>例子:</b>
```go
@@ -216,23 +215,23 @@ import (
"fmt"
"errors"
"log"
"github.com/duke-git/lancet/retry"
"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")
}
increaseNumber := func() error {
number++
if number == 3 {
return nil
}
return errors.New("error occurs")
}
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
if err != nil {
log.Fatal(err)
}
log.Fatal(err)
}
fmt.Println(number) //3
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,41 @@
# 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/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
- [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/system"
"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)
- [GetOsBits](#GetOsBits)
- [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>
### <span id="IsWindows">IsWindows</span>
<p>Check if current os is windows.</p>
<b>Signature:</b>
@@ -45,23 +43,24 @@ import (
```go
func IsWindows() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
}
```
### <span id="IsLinux">IsLinux</span>
### <span id="IsLinux">IsLinux</span>
<p>Check if current os is linux.</p>
<b>Signature:</b>
@@ -69,23 +68,23 @@ func main() {
```go
func IsLinux() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
}
```
### <span id="IsMac">IsMac</span>
### <span id="IsMac">IsMac</span>
<p>Check if current os is macos.</p>
<b>Signature:</b>
@@ -93,23 +92,23 @@ func main() {
```go
func IsMac() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsMac := system.IsMac
fmt.Println(isOsMac)
isOsMac := system.IsMac
fmt.Println(isOsMac)
}
```
### <span id="GetOsEnv">GetOsEnv</span>
### <span id="GetOsEnv">GetOsEnv</span>
<p>Gets the value of the environment variable named by the key.</p>
<b>Signature:</b>
@@ -117,23 +116,23 @@ func main() {
```go
func GetOsEnv(key string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
}
```
### <span id="SetOsEnv">SetOsEnv</span>
### <span id="SetOsEnv">SetOsEnv</span>
<p>Sets the value of the environment variable named by the key.</p>
<b>Signature:</b>
@@ -141,23 +140,24 @@ func main() {
```go
func SetOsEnv(key, value string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
}
```
### <span id="RemoveOsEnv">RemoveOsEnv</span>
### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>Remove a single environment variable.</p>
<b>Signature:</b>
@@ -165,25 +165,25 @@ func main() {
```go
func RemoveOsEnv(key string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CompareOsEnv">CompareOsEnv</span>
### <span id="CompareOsEnv">CompareOsEnv</span>
<p>Get env named by the key and compare it with comparedEnv.</p>
<b>Signature:</b>
@@ -191,71 +191,52 @@ func main() {
```go
func CompareOsEnv(key, comparedEnv string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"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
system.SetOsEnv("foo", "foo_value")
res := system.CompareOsEnv("foo", "foo_value")
fmt.Println(res) //true
}
```
### <span id="ExecCommand">ExecCommand</span>
### <span id="ExecCommand">CompareOsEnv</span>
<p>use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
<b>Signature:</b>
```go
type (
Option func(*exec.Cmd)
)
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
func ExecCommand(command string) (stdout, stderr string, err error)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
out, errout, err := system.ExecCommand("ls", system.WithForeground())
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
}
```
### <span id="GetOsBits">GetOsBits</span>
<p>获取当前操作系统位数返回32或64</p>
<b>函数签名:</b>
```go
func GetOsBits() int
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
)
func main() {
osBit := system.GetOsBits()
fmt.Println(osBit)
}
```

View File

@@ -1,43 +1,41 @@
# System
system 包含 os, runtime, shell command 相关函数。
system包含os, runtime, shell command相关函数。
<div STYLE="page-break-after: always;"></div>
## 源码:
[https://github.com/duke-git/lancet/blob/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
- [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/system"
"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)
- [GetOsBits](#GetOsBits)
- [IsWindows](#IsWindows)
- [IsLinux](#IsLinux)
- [IsMac](#IsMac)
- [GetOsEnv](#GetOsEnv)
- [SetOsEnv](#SetOsEnv)
- [RemoveOsEnv](#RemoveOsEnv)
- [CompareOsEnv](#CompareOsEnv)
- [ExecCommand](#ExecCommand)
<div STYLE="page-break-after: always;"></div>
## Documentation 文档
## Documentation文档
### <span id="IsWindows">IsWindows</span>
<p>检查当前操作系统是否是windows</p>
<b>Signature:</b>
@@ -45,23 +43,24 @@ import (
```go
func IsWindows() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
isOsWindows := system.IsWindows()
fmt.Println(isOsWindows)
}
```
### <span id="IsLinux">IsLinux</span>
### <span id="IsLinux">IsLinux</span>
<p>检查当前操作系统是否是linux</p>
<b>Signature:</b>
@@ -69,23 +68,23 @@ func main() {
```go
func IsLinux() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
isOsLinux := system.IsLinux()
fmt.Println(isOsLinux)
}
```
### <span id="IsMac">IsMac</span>
### <span id="IsMac">IsMac</span>
<p>检查当前操作系统是否是macos</p>
<b>Signature:</b>
@@ -93,23 +92,23 @@ func main() {
```go
func IsMac() bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
isOsMac := system.IsMac
fmt.Println(isOsMac)
isOsMac := system.IsMac
fmt.Println(isOsMac)
}
```
### <span id="GetOsEnv">GetOsEnv</span>
### <span id="GetOsEnv">GetOsEnv</span>
<p>获取key命名的环境变量的值</p>
<b>Signature:</b>
@@ -117,23 +116,23 @@ func main() {
```go
func GetOsEnv(key string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
fooEnv := system.GetOsEnv("foo")
fmt.Println(fooEnv)
}
```
### <span id="SetOsEnv">SetOsEnv</span>
### <span id="SetOsEnv">SetOsEnv</span>
<p>设置由key命名的环境变量的值</p>
<b>Signature:</b>
@@ -141,23 +140,24 @@ func main() {
```go
func SetOsEnv(key, value string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
err := system.SetOsEnv("foo", "foo_value")
fmt.Println(err)
}
```
### <span id="RemoveOsEnv">RemoveOsEnv</span>
### <span id="RemoveOsEnv">RemoveOsEnv</span>
<p>删除单个环境变量</p>
<b>Signature:</b>
@@ -165,25 +165,25 @@ func main() {
```go
func RemoveOsEnv(key string) error
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
err := system.RemoveOsEnv("foo")
if err != nil {
fmt.Println(err)
}
}
```
### <span id="CompareOsEnv">CompareOsEnv</span>
### <span id="CompareOsEnv">CompareOsEnv</span>
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
<b>Signature:</b>
@@ -191,71 +191,52 @@ func main() {
```go
func CompareOsEnv(key, comparedEnv string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"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
system.SetOsEnv("foo", "foo_value")
res := system.CompareOsEnv("foo", "foo_value")
fmt.Println(res) //true
}
```
### <span id="ExecCommand">ExecCommand</span>
### <span id="ExecCommand">CompareOsEnv</span>
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
<b>Signature:</b>
```go
type (
Option func(*exec.Cmd)
)
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
func ExecCommand(command string) (stdout, stderr string, err error)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
"fmt"
"github.com/duke-git/lancet/v2/system"
)
func main() {
out, errout, err := system.ExecCommand("ls", system.WithForeground())
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
}
```
### <span id="GetOsBits">GetOsBits</span>
<p>Get current os bits, 32bit or 64bit. return 32 or 64</p>
<b>Signature:</b>
```go
func GetOsBits() int
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/system"
)
func main() {
osBit := system.GetOsBits()
fmt.Println(osBit)
}
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

@@ -7,21 +7,13 @@ package fileutil
import (
"archive/zip"
"bufio"
"bytes"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/csv"
"errors"
"fmt"
"io"
"io/fs"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"strings"
)
@@ -48,11 +40,6 @@ func CreateFile(path string) bool {
return true
}
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
func CreateDir(absPath string) error {
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
}
// IsDir checks if the path is directory or not
func IsDir(path string) bool {
file, err := os.Stat(path)
@@ -94,7 +81,7 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
}
}
// ClearFile write empty string to path file
//ClearFile write empty string to path file
func ClearFile(path string) error {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
if err != nil {
@@ -106,7 +93,7 @@ func ClearFile(path string) error {
return err
}
// ReadFileToString return string of file content
//ReadFileToString return string of file content
func ReadFileToString(path string) (string, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
@@ -227,11 +214,7 @@ func UnZip(zipFile string, destPath string) error {
defer zipReader.Close()
for _, f := range zipReader.File {
//issue#62: fix ZipSlip bug
path, err := safeFilepathJoin(destPath, f.Name)
if err != nil {
return err
}
path := filepath.Join(destPath, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
} else {
@@ -260,17 +243,6 @@ func UnZip(zipFile string, destPath string) error {
return nil
}
func safeFilepathJoin(path1, path2 string) (string, error) {
relPath, err := filepath.Rel(".", path2)
if err != nil || strings.HasPrefix(relPath, "..") {
return "", fmt.Errorf("(zipslip) filepath is unsafe %q: %v", path2, err)
}
if path1 == "" {
path1 = "."
}
return filepath.Join(path1, filepath.Join("/", relPath)), nil
}
// IsLink checks if a file is symbol link or not
func IsLink(path string) bool {
fi, err := os.Lstat(path)
@@ -291,7 +263,7 @@ func FileMode(path string) (fs.FileMode, error) {
// MiMeType return file mime type
// param `file` should be string(file path) or *os.File
func MiMeType(file interface{}) string {
func MiMeType(file any) string {
var mediatype string
readBuffer := func(f *os.File) ([]byte, error) {
@@ -324,128 +296,3 @@ func MiMeType(file interface{}) string {
}
return mediatype
}
// CurrentPath return current absolute path.
func CurrentPath() string {
var absPath string
_, filename, _, ok := runtime.Caller(1)
if ok {
absPath = path.Dir(filename)
}
return absPath
}
// IsZipFile checks if file is zip or not.
func IsZipFile(filepath string) bool {
f, err := os.Open(filepath)
if err != nil {
return false
}
defer f.Close()
buf := make([]byte, 4)
if n, err := f.Read(buf); err != nil || n < 4 {
return false
}
return bytes.Equal(buf, []byte("PK\x03\x04"))
}
// FileSize returns file size in bytes.
func FileSize(path string) (int64, error) {
f, err := os.Stat(path)
if err != nil {
return 0, err
}
return f.Size(), nil
}
// MTime returns file modified time.
func MTime(filepath string) (int64, error) {
f, err := os.Stat(filepath)
if err != nil {
return 0, err
}
return f.ModTime().Unix(), nil
}
// MTime returns file sha value, param `shaType` should be 1, 256 or 512.
func Sha(filepath string, shaType ...int) (string, error) {
file, err := os.Open(filepath)
if err != nil {
return "", err
}
defer file.Close()
h := sha1.New()
if len(shaType) > 0 {
if shaType[0] == 1 {
h = sha1.New()
} else if shaType[0] == 256 {
h = sha256.New()
} else if shaType[0] == 512 {
h = sha512.New()
} else {
return "", errors.New("param `shaType` should be 1, 256 or 512.")
}
}
_, err = io.Copy(h, file)
if err != nil {
return "", err
}
sha := fmt.Sprintf("%x", h.Sum(nil))
return sha, nil
}
// ReadCsvFile read file content into slice.
func ReadCsvFile(filepath string) ([][]string, error) {
f, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer f.Close()
csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll()
if err != nil {
return nil, err
}
return records, nil
}
// WriteStringToFile write string to target file.
func WriteStringToFile(filepath string, content string, append bool) error {
flag := os.O_RDWR | os.O_CREATE
if append {
flag = flag | os.O_APPEND
}
f, err := os.OpenFile(filepath, flag, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(content)
return err
}
// WriteBytesToFile write bytes to target file.
func WriteBytesToFile(filepath string, content []byte) error {
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(content)
return err
}

View File

@@ -4,7 +4,7 @@ import (
"os"
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestIsExist(t *testing.T) {
@@ -33,27 +33,6 @@ func TestCreateFile(t *testing.T) {
os.Remove(f)
}
func TestCreateDir(t *testing.T) {
assert := internal.NewAssert(t, "TestCreateDir")
pwd, err := os.Getwd()
if err != nil {
t.Error(err)
t.FailNow()
}
dirPath := pwd + "/a/"
err = CreateDir(dirPath)
if err != nil {
t.Error(err)
t.FailNow()
}
assert.Equal(true, IsExist(dirPath))
os.Remove(dirPath)
assert.Equal(false, IsExist(dirPath))
}
func TestIsDir(t *testing.T) {
assert := internal.NewAssert(t, "TestIsDir")
@@ -97,10 +76,10 @@ func TestCopyFile(t *testing.T) {
func TestListFileNames(t *testing.T) {
assert := internal.NewAssert(t, "TestListFileNames")
filesInPath, err := ListFileNames("../datetime/")
filesInPath, err := ListFileNames("./")
assert.IsNil(err)
expected := []string{"conversion.go", "conversion_test.go", "datetime.go", "datetime_test.go"}
expected := []string{"file.go", "file_test.go"}
assert.Equal(expected, filesInPath)
}
@@ -221,124 +200,3 @@ func TestMiMeType(t *testing.T) {
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
}
func TestCurrentPath(t *testing.T) {
absPath := CurrentPath()
t.Log(absPath)
}
func TestIsZipFile(t *testing.T) {
assert := internal.NewAssert(t, "TestIsZipFile")
assert.Equal(false, IsZipFile("./file.go"))
assert.Equal(true, IsZipFile("./testdata/file.go.zip"))
}
func TestFileSize(t *testing.T) {
assert := internal.NewAssert(t, "TestFileSize")
size, err := FileSize("./testdata/test.txt")
assert.IsNil(err)
assert.Equal(int64(20), size)
}
func TestMTime(t *testing.T) {
// assert := internal.NewAssert(t, "TestMTime")
// mtime, err := MTime("./testdata/test.txt")
// assert.IsNil(err)
// assert.Equal(int64(1682478195), mtime)
}
func TestSha(t *testing.T) {
assert := internal.NewAssert(t, "TestSha")
sha1, err := Sha("./testdata/test.txt", 1)
sha256, err := Sha("./testdata/test.txt", 256)
sha512, err := Sha("./testdata/test.txt", 512)
assert.IsNil(err)
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
}
func TestReadCsvFile(t *testing.T) {
assert := internal.NewAssert(t, "TestReadCsvFile")
content, err := ReadCsvFile("./testdata/test.csv")
t.Log(content)
assert.IsNil(err)
assert.Equal(3, len(content))
assert.Equal(3, len(content[0]))
assert.Equal("Bob", content[0][0])
}
func TestWriteStringToFile(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteStringToFile")
filepath := "./test.txt"
file, err := os.Create(filepath)
if err != nil {
t.Fail()
}
defer file.Close()
err = WriteStringToFile(filepath, "hello", false)
if err != nil {
t.Fail()
}
content1, err := ReadFileToString(filepath)
if err != nil {
t.Fail()
}
err = WriteStringToFile(filepath, " world", true)
if err != nil {
t.Fail()
}
content2, err := os.ReadFile(filepath)
if err != nil {
t.Fail()
}
assert.Equal("hello", content1)
assert.Equal("hello world", string(content2))
os.Remove(filepath)
}
func TestWriteBytesToFile(t *testing.T) {
assert := internal.NewAssert(t, "TestWriteBytesToFile")
filepath := "./bytes.txt"
file, err := os.Create(filepath)
if err != nil {
t.Fail()
}
defer file.Close()
err = WriteBytesToFile(filepath, []byte("hello"))
if err != nil {
t.Fail()
}
content, err := os.ReadFile(filepath)
if err != nil {
t.Fail()
}
assert.Equal("hello", string(content))
os.Remove(filepath)
}

Binary file not shown.

View File

@@ -1,3 +0,0 @@
Bob, 12, male
Duke, 14, male
Lucy, 16, female
1 Bob 12 male
2 Duke 14 male
3 Lucy 16 female

View File

@@ -1 +0,0 @@
this is a test file.

View File

@@ -4,176 +4,14 @@
// Package formatter implements some functions to format string, struct.
package formatter
import (
"encoding/json"
"fmt"
"io"
import "strings"
"github.com/duke-git/lancet/convertor"
"github.com/duke-git/lancet/strutil"
"github.com/duke-git/lancet/validator"
)
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
// if value is invalid number string eg "aa", return empty string
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
func Comma(value interface{}, symbol string) string {
if validator.IsInt(value) {
v, err := convertor.ToInt(value)
if err != nil {
return ""
}
return symbol + commaInt(v)
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
func Comma(v any, symbol string) string {
s := numString(v)
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
}
if validator.IsFloat(value) {
v, err := convertor.ToFloat(value)
if err != nil {
return ""
}
return symbol + commaFloat(v)
}
if strutil.IsString(value) {
v := fmt.Sprintf("%v", value)
if validator.IsNumberStr(v) {
return symbol + commaStr(v)
}
return ""
}
return ""
}
// Pretty data to JSON string.
func Pretty(v interface{}) (string, error) {
out, err := json.MarshalIndent(v, "", " ")
return string(out), err
}
// PrettyToWriter pretty encode data to writer.
func PrettyToWriter(v interface{}, out io.Writer) error {
enc := json.NewEncoder(out)
enc.SetIndent("", " ")
if err := enc.Encode(v); err != nil {
return err
}
return nil
}
// http://en.wikipedia.org/wiki/Binary_prefix
const (
// Decimal
UnitB = 1
UnitKB = 1000
UnitMB = 1000 * UnitKB
UnitGB = 1000 * UnitMB
UnitTB = 1000 * UnitGB
UnitPB = 1000 * UnitTB
UnitEB = 1000 * UnitPB
// Binary
UnitBiB = 1
UnitKiB = 1024
UnitMiB = 1024 * UnitKiB
UnitGiB = 1024 * UnitMiB
UnitTiB = 1024 * UnitGiB
UnitPiB = 1024 * UnitTiB
UnitEiB = 1024 * UnitPiB
)
// type byteUnitMap map[byte]int64
var (
decimalByteMap = map[string]uint64{
"b": UnitB,
"kb": UnitKB,
"mb": UnitMB,
"gb": UnitGB,
"tb": UnitTB,
"pb": UnitPB,
"eb": UnitEB,
// Without suffix
"": UnitB,
"k": UnitKB,
"m": UnitMB,
"g": UnitGB,
"t": UnitTB,
"p": UnitPB,
"e": UnitEB,
}
binaryByteMap = map[string]uint64{
"bi": UnitBiB,
"kib": UnitKiB,
"mib": UnitMiB,
"gib": UnitGiB,
"tib": UnitTiB,
"pib": UnitPiB,
"eib": UnitEiB,
// Without suffix
"": UnitBiB,
"ki": UnitKiB,
"mi": UnitMiB,
"gi": UnitGiB,
"ti": UnitTiB,
"pi": UnitPiB,
"ei": UnitEiB,
}
)
var (
decimalByteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
binaryByteUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
)
// DecimalBytes returns a human readable byte size under decimal standard (base 1000)
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
// Play: https://go.dev/play/p/FPXs1suwRcs
func DecimalBytes(size float64, precision ...int) string {
p := 5
if len(precision) > 0 {
p = precision[0] + 1
}
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
return fmt.Sprintf("%.*g%s", p, size, unit)
}
// BinaryBytes returns a human-readable byte size under binary standard (base 1024)
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
func BinaryBytes(size float64, precision ...int) string {
p := 5
if len(precision) > 0 {
p = precision[0] + 1
}
size, unit := calculateByteSize(size, 1024.0, binaryByteUnits)
return fmt.Sprintf("%.*g%s", p, size, unit)
}
func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) {
i := 0
unitsLimit := len(byteUnits) - 1
for size >= base && i < unitsLimit {
size = size / base
i++
}
return size, byteUnits[i]
}
// ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000).
// ParseDecimalBytes("42 MB") -> 42000000, nil
func ParseDecimalBytes(size string) (uint64, error) {
return parseBytes(size, "decimal")
}
// ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024).
// ParseBinaryBytes("42 mib") -> 44040192, nil
func ParseBinaryBytes(size string) (uint64, error) {
return parseBytes(size, "binary")
return symbol + commaString(s)
}

View File

@@ -1,134 +1,40 @@
package formatter
import (
"bytes"
"fmt"
"math"
"reflect"
"strconv"
"strings"
"unicode"
)
// see https://github.com/dustin/go-humanize/blob/master/comma.go
func commaInt(v int64) string {
sign := ""
// Min int64 can't be negated to a usable value, so it has to be special cased.
if v == math.MinInt64 {
return "-9,223,372,036,854,775,808"
}
if v < 0 {
sign = "-"
v = 0 - v
}
parts := []string{"", "", "", "", "", "", ""}
j := len(parts) - 1
for v > 999 {
parts[j] = strconv.FormatInt(v%1000, 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
v = v / 1000
j--
}
parts[j] = strconv.Itoa(int(v))
return sign + strings.Join(parts[j:], ",")
}
func commaFloat(v float64) string {
buf := &bytes.Buffer{}
if v < 0 {
buf.Write([]byte{'-'})
v = 0 - v
}
comma := []byte{','}
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}
func commaStr(s string) string {
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
}
return commaStrRecursive(s)
}
func commaStrRecursive(s string) string {
func commaString(s string) string {
if len(s) <= 3 {
return s
}
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
}
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
func parseBytes(s string, kind string) (uint64, error) {
lastDigit := 0
hasComma := false
for _, r := range s {
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
break
}
if r == ',' {
hasComma = true
}
lastDigit++
}
num := s[:lastDigit]
if hasComma {
num = strings.Replace(num, ",", "", -1)
}
f, err := strconv.ParseFloat(num, 64)
if err != nil {
return 0, err
}
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
if kind == "decimal" {
if m, ok := decimalByteMap[extra]; ok {
f *= float64(m)
if f >= math.MaxUint64 {
return 0, fmt.Errorf("too large: %v", s)
func numString(value any) string {
switch reflect.TypeOf(value).Kind() {
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
return fmt.Sprintf("%v", value)
case reflect.String:
{
sv := fmt.Sprintf("%v", value)
if strings.Contains(sv, ".") {
_, err := strconv.ParseFloat(sv, 64)
if err == nil {
return sv
}
} else {
_, err := strconv.ParseInt(sv, 10, 64)
if err == nil {
return sv
}
}
return uint64(f), nil
}
} else {
if m, ok := binaryByteMap[extra]; ok {
f *= float64(m)
if f >= math.MaxUint64 {
return 0, fmt.Errorf("too large: %v", s)
}
return uint64(f), nil
}
default:
return ""
}
return 0, fmt.Errorf("unhandled size name: %v", extra)
return ""
}

View File

@@ -1,10 +1,9 @@
package formatter
import (
"bytes"
"testing"
"github.com/duke-git/lancet/internal"
"github.com/duke-git/lancet/v2/internal"
)
func TestComma(t *testing.T) {
@@ -13,148 +12,12 @@ func TestComma(t *testing.T) {
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.6789", Comma("12345.6789", ""))
assert.Equal("123,456,789,000", Comma("123456789000", ""))
assert.Equal("12,345,678.9", Comma("12345678.9", ""))
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, ""))
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
assert.Equal("12,345,678.9", Comma(12345678.9, ""))
assert.Equal("123,456,789,000", Comma(123456789000, ""))
}
func TestPretty(t *testing.T) {
assert := internal.NewAssert(t, "TestPretty")
cases := []interface{}{
"",
"abc",
123,
[]string{"a", "b", "c"},
map[string]int{"a": 1},
struct {
Abc int `json:"abc"`
}{Abc: 123},
}
expects := []string{
"\"\"",
`"abc"`,
"123",
"[\n \"a\",\n \"b\",\n \"c\"\n]",
"{\n \"a\": 1\n}",
"{\n \"abc\": 123\n}",
}
for i, v := range cases {
result, err := Pretty(v)
assert.IsNil(err)
t.Log("result -> ", result)
assert.Equal(expects[i], result)
}
}
func TestPrettyToWriter(t *testing.T) {
assert := internal.NewAssert(t, "TestPrettyToWriter")
type User struct {
Name string `json:"name"`
Aage uint `json:"age"`
}
user := User{Name: "King", Aage: 10000}
expects := "{\n \"name\": \"King\",\n \"age\": 10000\n}\n"
buf := &bytes.Buffer{}
err := PrettyToWriter(user, buf)
assert.IsNil(err)
assert.Equal(expects, buf.String())
}
func TestDecimalBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestDecimalBytes")
assert.Equal("1KB", DecimalBytes(1000))
assert.Equal("1.024KB", DecimalBytes(1024))
assert.Equal("1.2346MB", DecimalBytes(1234567))
assert.Equal("1.235MB", DecimalBytes(1234567, 3))
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB)))
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB)))
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB)))
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB)))
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB)))
}
func TestBinaryBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestBinaryBytes")
assert.Equal("1KiB", BinaryBytes(1024))
assert.Equal("1MiB", BinaryBytes(1024*1024))
assert.Equal("1.1774MiB", BinaryBytes(1234567))
assert.Equal("1.18MiB", BinaryBytes(1234567, 2))
}
func TestParseDecimalBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestParseDecimalBytes")
cases := map[string]uint64{
"12": uint64(12),
"12 k": uint64(12000),
"12 kb": uint64(12000),
"12kb": uint64(12000),
"12k": uint64(12000),
"12K": uint64(12000),
"12KB": uint64(12000),
"12 K": uint64(12000),
"12 KB": uint64(12000),
"12 Kb": uint64(12000),
"12 kB": uint64(12000),
"12.2 KB": uint64(12200),
}
for k, v := range cases {
result, err := ParseDecimalBytes(k)
assert.Equal(v, result)
assert.IsNil(err)
}
_, err := ParseDecimalBytes("12 AB")
assert.IsNotNil(err)
}
func TestParseBinaryBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestParseBinaryBytes")
cases := map[string]uint64{
"12": uint64(12),
"12 ki": uint64(12288),
"12 kib": uint64(12288),
"12kib": uint64(12288),
"12ki": uint64(12288),
"12KI": uint64(12288),
"12KIB": uint64(12288),
"12KiB": uint64(12288),
"12 Ki": uint64(12288),
"12 KiB": uint64(12288),
"12 Kib": uint64(12288),
"12 kiB": uint64(12288),
"12.2 KiB": uint64(12492),
}
for k, v := range cases {
result, err := ParseBinaryBytes(k)
assert.Equal(v, result)
assert.IsNil(err)
}
_, err := ParseDecimalBytes("12 AB")
assert.IsNotNil(err)
}

View File

@@ -10,11 +10,11 @@ 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 {
func After(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure
mustBeFunction(fn)
return func(args ...interface{}) []reflect.Value {
return func(args ...any) []reflect.Value {
n--
if n < 1 {
return unsafeInvokeFunc(fn, args...)
@@ -24,11 +24,11 @@ func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
}
// 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 = unsafeInvokeFunc(fn, args...)
}
@@ -40,20 +40,20 @@ func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
}
}
// Fn is for curry function which is func(...interface{}) interface{}
type Fn func(...interface{}) interface{}
// Fn is for curry function which is func(...any) any
type Fn func(...any) any
// Curry make a curry function
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} {
return func(values ...interface{}) interface{} {
v := append([]interface{}{i}, values...)
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:]
@@ -66,7 +66,7 @@ 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)
@@ -95,7 +95,7 @@ func Debounced(fn func(), duration time.Duration) func() {
}
// Schedule invoke function every duration time, util close the returned bool chan
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
func Schedule(d time.Duration, fn any, args ...any) chan bool {
// Catch programming error while constructing the closure
mustBeFunction(fn)
@@ -113,15 +113,3 @@ func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
return quit
}
// Pipeline takes a list of functions and returns a function whose param will be passed into
// the functions one by one.
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{} {
return func(arg interface{}) (result interface{}) {
result = arg
for _, fn := range funcs {
result = fn(result)
}
return
}
}

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