mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-05 05:12:26 +08:00
Compare commits
390 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ffff0e3f3 | ||
|
|
8ebb8a028e | ||
|
|
995ffb799f | ||
|
|
3cd546d7f2 | ||
|
|
7fb49515ce | ||
|
|
8f3ea60636 | ||
|
|
58a37b7e8d | ||
|
|
6bd61460d3 | ||
|
|
05b85a2131 | ||
|
|
1eb793420e | ||
|
|
05f9854945 | ||
|
|
3be706e23f | ||
|
|
b5e7312353 | ||
|
|
95a894e53f | ||
|
|
8322951475 | ||
|
|
6b2c91b0f6 | ||
|
|
ec161f335d | ||
|
|
d1a8f37a71 | ||
|
|
a769257017 | ||
|
|
f3579fc142 | ||
|
|
de877e5278 | ||
|
|
08f14d2b08 | ||
|
|
0ed2b11ba1 | ||
|
|
643edc1468 | ||
|
|
e2ff83649a | ||
|
|
a7fecfc73b | ||
|
|
8bbae69175 | ||
|
|
840ea8f3c5 | ||
|
|
a4e89bd7c1 | ||
|
|
2015d36b08 | ||
|
|
921f218ef7 | ||
|
|
0a2cc9c928 | ||
|
|
ed93aae970 | ||
|
|
1671f7856a | ||
|
|
1008dd4956 | ||
|
|
a254ebdc8e | ||
|
|
0bc11001a4 | ||
|
|
85d98ad915 | ||
|
|
cb08613ac3 | ||
|
|
bad1b05224 | ||
|
|
527328739a | ||
|
|
213e2b4ead | ||
|
|
5d6ab72059 | ||
|
|
30eb2c72b0 | ||
|
|
adf18a2e47 | ||
|
|
f99a8ef3cf | ||
|
|
fcdf1d5839 | ||
|
|
ee0afed963 | ||
|
|
1d94896c9b | ||
|
|
69cf9bbcf0 | ||
|
|
2bbcb85286 | ||
|
|
e58c9b797b | ||
|
|
3e1ac5e0b5 | ||
|
|
8869e0440d | ||
|
|
69f9c74bcb | ||
|
|
84ebc7ce71 | ||
|
|
c745097749 | ||
|
|
ba75e58e5f | ||
|
|
7e85a0ed7d | ||
|
|
2268a0312f | ||
|
|
da84d95aa3 | ||
|
|
48244d6711 | ||
|
|
5e3337a52e | ||
|
|
c3372e18b1 | ||
|
|
90e5a0bfb2 | ||
|
|
93be25920f | ||
|
|
f9e5ec9096 | ||
|
|
601df5dc12 | ||
|
|
63216d9b1c | ||
|
|
c32a19868d | ||
|
|
71e914019b | ||
|
|
9824db0056 | ||
|
|
ba9188a29a | ||
|
|
8625fbd8d3 | ||
|
|
81b29baf30 | ||
|
|
5a38e34063 | ||
|
|
159168dd7b | ||
|
|
ec092a009a | ||
|
|
ca40b5d6c6 | ||
|
|
a6d39a3bba | ||
|
|
38148978cf | ||
|
|
3e8c3bd396 | ||
|
|
30971c1aab | ||
|
|
bc260277bc | ||
|
|
c0b200f846 | ||
|
|
305847993c | ||
|
|
f5d70728c3 | ||
|
|
c2a5335bc6 | ||
|
|
7b4e060f85 | ||
|
|
a360372aa9 | ||
|
|
7f78a6b11e | ||
|
|
5c53cb5867 | ||
|
|
f7e9d5dc47 | ||
|
|
5c580ed013 | ||
|
|
0f9764f41e | ||
|
|
0bc5f82554 | ||
|
|
e91965b013 | ||
|
|
483a286d8e | ||
|
|
3f8e306ced | ||
|
|
0b29f0520d | ||
|
|
8611ec0c10 | ||
|
|
286e10d189 | ||
|
|
3e7f94b03e | ||
|
|
356351896d | ||
|
|
9be124211e | ||
|
|
f467658481 | ||
|
|
5c9d0e396e | ||
|
|
8f74460c1b | ||
|
|
d5752499bf | ||
|
|
eb7cf76eae | ||
|
|
4af074d181 | ||
|
|
73fb8fefd2 | ||
|
|
9cf535055d | ||
|
|
8be7b3e396 | ||
|
|
dac706d700 | ||
|
|
2097277a7d | ||
|
|
95b516e278 | ||
|
|
ca373b00a7 | ||
|
|
a220220f09 | ||
|
|
aeef0418a4 | ||
|
|
9b7d8d7abf | ||
|
|
4d21e81263 | ||
|
|
ce2397422e | ||
|
|
4b3a62b36a | ||
|
|
e054680d20 | ||
|
|
5381842eec | ||
|
|
6e0498514c | ||
|
|
967e6a3493 | ||
|
|
5b24801e49 | ||
|
|
974ba525a6 | ||
|
|
f0235c40b6 | ||
|
|
712a215ea6 | ||
|
|
7893f828d3 | ||
|
|
53fa210f09 | ||
|
|
de9ee08be4 | ||
|
|
5381450bea | ||
|
|
6853d627f4 | ||
|
|
e461acdb72 | ||
|
|
2a796adf85 | ||
|
|
5e6e8d82a8 | ||
|
|
e9280b8c25 | ||
|
|
bb6f10a1fb | ||
|
|
33b4cffe60 | ||
|
|
2b765b49e0 | ||
|
|
004dbdc32e | ||
|
|
ab50e8120a | ||
|
|
73c97af7d8 | ||
|
|
5e8a065eaa | ||
|
|
aa74400607 | ||
|
|
a6eaaef563 | ||
|
|
1b31014f81 | ||
|
|
036847577d | ||
|
|
d21edd1cde | ||
|
|
c58c50327c | ||
|
|
9bfdc686f8 | ||
|
|
5ca8f6ef6f | ||
|
|
a54d4c79a0 | ||
|
|
f7b54986aa | ||
|
|
92fae4273b | ||
|
|
0d29f5437a | ||
|
|
e95d7c82cd | ||
|
|
e138043289 | ||
|
|
aabfcb7bde | ||
|
|
0b5e884371 | ||
|
|
3d1bd08434 | ||
|
|
a62ad71791 | ||
|
|
c02c4f813b | ||
|
|
235d2f2486 | ||
|
|
e9380a3d9f | ||
|
|
81d13c2f1a | ||
|
|
7290296849 | ||
|
|
8a8460a592 | ||
|
|
7a98c431d3 | ||
|
|
606d887230 | ||
|
|
473f9c9f3e | ||
|
|
9ff3d0e79c | ||
|
|
5db1d07d6d | ||
|
|
6c6d14828a | ||
|
|
0e1593c67b | ||
|
|
6c7f38d8b3 | ||
|
|
069812e0ee | ||
|
|
4a539a23c8 | ||
|
|
0b1dab0399 | ||
|
|
805e2543d0 | ||
|
|
a3d518da76 | ||
|
|
e3e2d8394c | ||
|
|
0eeaa06055 | ||
|
|
a43bc554ee | ||
|
|
aebab7c944 | ||
|
|
665bad4ca3 | ||
|
|
e4901e99e9 | ||
|
|
4277e8eca5 | ||
|
|
fdc93c8cc7 | ||
|
|
860a499f98 | ||
|
|
2e1c2276a5 | ||
|
|
d367397dab | ||
|
|
66fd8cf651 | ||
|
|
a6be1828b9 | ||
|
|
8f5d297572 | ||
|
|
a1a4fdc598 | ||
|
|
1610076d22 | ||
|
|
cacbf97223 | ||
|
|
cd156dba5f | ||
|
|
3a71a8697d | ||
|
|
c88fd3db86 | ||
|
|
27d19d1717 | ||
|
|
da24bae6b4 | ||
|
|
3cd9d6b68c | ||
|
|
874d09f331 | ||
|
|
fdf251ac98 | ||
|
|
7ec2533b7a | ||
|
|
9fd0603f4a | ||
|
|
9f7b416a8d | ||
|
|
bf4b2b5fd6 | ||
|
|
22af59565e | ||
|
|
f9e047f190 | ||
|
|
fa298b740d | ||
|
|
6d4fc981b6 | ||
|
|
4c21fe700c | ||
|
|
b7370e8ef8 | ||
|
|
38920e3be6 | ||
|
|
a630a7cda9 | ||
|
|
66dfd9c4fd | ||
|
|
be62aaac9b | ||
|
|
e0c9ccbce3 | ||
|
|
d2d1e5a055 | ||
|
|
bbc58c7e46 | ||
|
|
ac2ecceaec | ||
|
|
a06bb8ee6a | ||
|
|
27b5702fd3 | ||
|
|
b2c3fa0ab8 | ||
|
|
4afc838937 | ||
|
|
3482f80d1c | ||
|
|
565f2893b9 | ||
|
|
1b1b10d0ee | ||
|
|
c5c3888ffc | ||
|
|
11214986cc | ||
|
|
0bc7b83e59 | ||
|
|
6225418074 | ||
|
|
ddd265de78 | ||
|
|
80e48f06ca | ||
|
|
0b976e9a4c | ||
|
|
96320069f4 | ||
|
|
c5297ec329 | ||
|
|
aa4b61ff85 | ||
|
|
7dbd7002a3 | ||
|
|
a995db445a | ||
|
|
6e5b67bee7 | ||
|
|
52b8ea8166 | ||
|
|
6fe8a9efe7 | ||
|
|
dcef06e9da | ||
|
|
8f410bf9cb | ||
|
|
9cd6eb4ddf | ||
|
|
bf581162ee | ||
|
|
bd984fa378 | ||
|
|
d7f23e2dee | ||
|
|
3802c715c3 | ||
|
|
4b12173f24 | ||
|
|
31c618c187 | ||
|
|
6497b321b0 | ||
|
|
bda78201f5 | ||
|
|
0753ea2801 | ||
|
|
e25b53712b | ||
|
|
56c9327a86 | ||
|
|
11eb559998 | ||
|
|
61a612a06a | ||
|
|
2351ab4714 | ||
|
|
88eec858b4 | ||
|
|
14c37b5a5f | ||
|
|
ad8b1d424c | ||
|
|
a9f01d8a69 | ||
|
|
781b89d51a | ||
|
|
073c77e751 | ||
|
|
91a0d3077d | ||
|
|
17b34f8f19 | ||
|
|
8ff37f0eff | ||
|
|
f445ecbaf8 | ||
|
|
b698fec50f | ||
|
|
b38bb66b34 | ||
|
|
bdfdeaf496 | ||
|
|
172c44c07a | ||
|
|
534263eb08 | ||
|
|
a25b1ac7e3 | ||
|
|
d84f9777ea | ||
|
|
f9caaf8063 | ||
|
|
f198711d1c | ||
|
|
19378ca4d1 | ||
|
|
71c7733eb0 | ||
|
|
20786c360b | ||
|
|
51fafa110e | ||
|
|
07fc453b74 | ||
|
|
b309044981 | ||
|
|
541e6d4ea3 | ||
|
|
4037b96cc4 | ||
|
|
8e484c4a6f | ||
|
|
dd339563bc | ||
|
|
9567dcc57f | ||
|
|
de104ebeb6 | ||
|
|
eebd95395f | ||
|
|
56265647ff | ||
|
|
756da3719d | ||
|
|
f3008ac7c4 | ||
|
|
c6583d3b83 | ||
|
|
a3d7bac72e | ||
|
|
74b4d53514 | ||
|
|
a08afe0d77 | ||
|
|
ee680aa84c | ||
|
|
caa74064f0 | ||
|
|
abc94c0b26 | ||
|
|
86bcdce07b | ||
|
|
789f5d933d | ||
|
|
156fd2ef5d | ||
|
|
ea036b3a81 | ||
|
|
3daca8b331 | ||
|
|
21a952d2be | ||
|
|
03d331dfb6 | ||
|
|
ef79e1305e | ||
|
|
7c2670d019 | ||
|
|
31f64c0a98 | ||
|
|
28b8986cbe | ||
|
|
b4ff33ce80 | ||
|
|
25fa117712 | ||
|
|
0c9f539e3d | ||
|
|
05bd1afaa6 | ||
|
|
51cb665110 | ||
|
|
47c368e8f2 | ||
|
|
3127360b28 | ||
|
|
5b6def5ff0 | ||
|
|
33d99ad7d4 | ||
|
|
8bd31d39c3 | ||
|
|
a418549525 | ||
|
|
1f849efe1c | ||
|
|
8ad374bb21 | ||
|
|
a69d886565 | ||
|
|
cf58542b4a | ||
|
|
51f166d1d9 | ||
|
|
fbeb031b40 | ||
|
|
095cfc0aab | ||
|
|
e66ab154bc | ||
|
|
91bc1a512c | ||
|
|
8753255026 | ||
|
|
9cf1f13fec | ||
|
|
5d78bae4bb | ||
|
|
27777eecc0 | ||
|
|
1a7e0e8792 | ||
|
|
02b7aa8f33 | ||
|
|
f188d3d08f | ||
|
|
0c924b859e | ||
|
|
c5a5a07462 | ||
|
|
1ff5dd6df0 | ||
|
|
b5f86a488c | ||
|
|
1390b7a964 | ||
|
|
c3e28a9fc0 | ||
|
|
e924429d6e | ||
|
|
7079b1f704 | ||
|
|
40cad365c0 | ||
|
|
6386ab908d | ||
|
|
bb563724c7 | ||
|
|
72924d4486 | ||
|
|
231f8b04b4 | ||
|
|
daa932fee3 | ||
|
|
1b0691f1d5 | ||
|
|
0b6a00bd99 | ||
|
|
4ab98664bb | ||
|
|
31eb5f4d1f | ||
|
|
0ae5d17a06 | ||
|
|
4558d7a3c2 | ||
|
|
4715301240 | ||
|
|
1c58ee23f1 | ||
|
|
2a303d5e4b | ||
|
|
326e7881a6 | ||
|
|
31e8b12674 | ||
|
|
a0431d9435 | ||
|
|
0456b65cc7 | ||
|
|
989b4dd791 | ||
|
|
a76b02fbba | ||
|
|
2d7747738a | ||
|
|
fe0cb04137 | ||
|
|
fe0264f628 | ||
|
|
65396cee32 | ||
|
|
544702b460 | ||
|
|
d8936cdcb5 | ||
|
|
d4b97d6b20 | ||
|
|
5caa14c838 | ||
|
|
0d0848ac67 | ||
|
|
d5334f892f | ||
|
|
36ef5b3bd3 | ||
|
|
6f48b00c88 | ||
|
|
7b744c299e | ||
|
|
154ec56780 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
liberapay: Duke_Du
|
||||
patreon: DukeDu
|
||||
8
.github/workflows/codecov.yml
vendored
8
.github/workflows/codecov.yml
vendored
@@ -3,11 +3,11 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# - v2
|
||||
- rc
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
# - v2
|
||||
- rc
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -17,8 +17,10 @@ jobs:
|
||||
fetch-depth: 2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "1.18"
|
||||
go-version: "1.20"
|
||||
- name: Run coverage
|
||||
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
|
||||
- name: Run govet
|
||||
run: go vet -v ./...
|
||||
- name: Upload coverage to Codecov
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -6,6 +6,10 @@ fileutil/*.txt
|
||||
fileutil/*.zip
|
||||
fileutil/*.link
|
||||
fileutil/unzip/*
|
||||
fileutil/tempdir/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
test
|
||||
# cryptor/*.pem
|
||||
test
|
||||
docs/node_modules
|
||||
docs/.vitepress/cache
|
||||
docs/.vitepress/dist
|
||||
|
||||
37
CONTRIBUTION.md
Normal file
37
CONTRIBUTION.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Lancet Contribution Guide
|
||||
|
||||
Hi! Thank you for choosing Lancet.
|
||||
|
||||
Lancet is a powerful, efficient, and reusable util function library of go. It makes Go dev easier by taking the hassle out of working with concurrency, net, math, slice, string, etc.
|
||||
|
||||
We are excited that you are interested in contributing to lancet. Before submitting your contribution though, please make sure to take a moment and read through the following guidelines.
|
||||
|
||||
## Issue Guidelines
|
||||
|
||||
- Issues are exclusively for bug reports, feature requests and design-related topics. Other questions may be closed directly.
|
||||
|
||||
- Before submitting an issue, please check if similar problems have already been issued.
|
||||
|
||||
- Please specify which version of Lancet and Go you are using, and provide OS information. [Go Playground](https://go.dev/play/) is recommended to build a live demo so that your issue can be reproduced clearly.
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
- Fork this repository to your own account. Do not create branches here.
|
||||
|
||||
- Commit info should be formatted as `type(scope): info about commit`. eg. `fix(package): [scrollbar] fix xxx bug`.
|
||||
|
||||
1. type: type must be one of [chore, docs, feat, fix, refactor, release, test].
|
||||
|
||||
2. scope: scope must be one of [package, file, internal].
|
||||
|
||||
3. header: header must not be longer than 72 characters.
|
||||
|
||||
- Rebase before creating a PR to keep commit history clear.
|
||||
|
||||
- Before submitting a PR, please execute the unit test command: `go test -v ./...` to ensure that all unit test tasks should pass.
|
||||
|
||||
- Make sure PRs are created to `rc` branch instead of other branch.
|
||||
|
||||
- If your PR fixes a bug, please provide a description about the related bug.
|
||||
|
||||
- If the PR is for a new feature, make sure to complete the relevant documentation (/lancet/docs/en/api/packages).
|
||||
37
CONTRIBUTION.zh-CN.md
Normal file
37
CONTRIBUTION.zh-CN.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Lancet 贡献指南
|
||||
|
||||
Hi! 首先感谢你使用 Lancet。
|
||||
|
||||
lancet(柳叶刀)是一个功能强大、全面、高效、可复用的go语言工具函数库。它消除了处理并发、网络、数学、切片、字符串等的麻烦,使 Go 开发变得更容易。
|
||||
|
||||
Lancet 的成长离不开大家的支持,如果你愿意为 Lancet 贡献代码或提供建议,请阅读以下内容。
|
||||
|
||||
## Issue 规范
|
||||
|
||||
- issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
|
||||
|
||||
- 在提交 issue 之前,请搜索相关内容是否已被提出。
|
||||
|
||||
- 请说明 Lancet 和 Go 的版本号,并提供操作系统信息。推荐使用 [Go Playground](https://go.dev/play/) 生成在线 demo,这能够更直观地重现问题。
|
||||
|
||||
## Pull Request 规范
|
||||
|
||||
- 请先 fork 一份到自己的项目下,不要直接在仓库下建分支。
|
||||
|
||||
- commit 信息要以 `type(scope): 描述信息` 的形式填写,例如 `fix(package): [scrollbar] fix xxx bug`。
|
||||
|
||||
1. type: 必须是 chore, docs, feat, fix, refactor, release, test 其中的一个。
|
||||
|
||||
2. scope: 必须是 package, file, internal 其中的一个。
|
||||
|
||||
3. header: 描述信息不要超过 72 个字符。
|
||||
|
||||
- 提交 PR 前请 rebase,确保 commit 记录的整洁。
|
||||
|
||||
- 提交 PR 前请执行单元测试命令:go test -v ./...,确保所有单元测试任务通过。
|
||||
|
||||
- 确保 PR 是提交到 `rc` 分支,而不是其他分支。
|
||||
|
||||
- 如果是修复 bug,请在 PR 中给出描述信息。
|
||||
|
||||
- 如果PR是新功能,确保完成相关文档(/lancet/docs/api/packages)。
|
||||
1704
README_zh-CN.md
1704
README_zh-CN.md
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
return node.value, true
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
}
|
||||
} else {
|
||||
node.value = value
|
||||
l.moveToHead(node)
|
||||
l.moveToTail(node)
|
||||
}
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
l.length = len(l.cache)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
|
||||
return node.key
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
|
||||
func (l *LRUCache[K, V]) moveToTail(node *lruNode[K, V]) {
|
||||
if l.tail == node {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
assert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
@@ -16,19 +16,19 @@ func TestLRUCache(t *testing.T) {
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
asssert.Equal(3, cache.Len())
|
||||
assert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(1, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(1, v)
|
||||
|
||||
v, ok = cache.Get(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, v)
|
||||
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
import "github.com/duke-git/lancet/v2/constraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
@@ -23,7 +23,7 @@ func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/t6MeGiUSN47
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
||||
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/Anozfr8ZLH3
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
|
||||
@@ -8,34 +8,34 @@ import (
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
assert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
assert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
assert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
assert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
assert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
assert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -3,24 +3,29 @@
|
||||
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
import "github.com/duke-git/lancet/v2/constraints"
|
||||
|
||||
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/GNdv7Jg2Taj
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
breakTag := false
|
||||
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)
|
||||
breakTag = true
|
||||
}
|
||||
}
|
||||
if !breakTag {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/G5LJiWgJJW6
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
|
||||
@@ -35,7 +40,7 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/oXovbkekayS
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
for j := i + 1; j < len(slice); j++ {
|
||||
@@ -49,7 +54,7 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/3ibkszpJEu3
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
gap := 1
|
||||
@@ -69,11 +74,11 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
|
||||
// Play: https://go.dev/play/p/7Y7c1Elk3ax
|
||||
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func QuickSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
quickSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
|
||||
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
p := partition(slice, lowIndex, highIndex, comparator)
|
||||
quickSort(slice, lowIndex, p-1, comparator)
|
||||
@@ -82,7 +87,7 @@ func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
}
|
||||
|
||||
// partition split slice into two parts
|
||||
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
func partition[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) int {
|
||||
p := slice[highIndex]
|
||||
i := lowIndex
|
||||
for j := lowIndex; j < highIndex; j++ {
|
||||
@@ -99,7 +104,7 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
|
||||
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/u6Iwa1VZS_f
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
for i := size/2 - 1; i >= 0; i-- {
|
||||
@@ -111,7 +116,7 @@ func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func sift[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := 2*i + 1
|
||||
|
||||
@@ -133,11 +138,11 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
||||
|
||||
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/ydinn9YzUJn
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
|
||||
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator constraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
mid := (lowIndex + highIndex) / 2
|
||||
mergeSort(slice, lowIndex, mid, comparator)
|
||||
@@ -146,7 +151,7 @@ func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
}
|
||||
}
|
||||
|
||||
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator constraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := midIndex + 1
|
||||
temp := []T{}
|
||||
@@ -175,7 +180,7 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
|
||||
|
||||
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
|
||||
// Play: https://go.dev/play/p/tB-Umgm0DrP
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/v2/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
@@ -47,7 +47,7 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
|
||||
func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
assert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -62,23 +62,23 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
assert := 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)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
}
|
||||
|
||||
func TestInsertionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestInsertionSort")
|
||||
assert := internal.NewAssert(t, "TestInsertionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -93,12 +93,12 @@ func TestInsertionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestSelectionSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestSelectionSort")
|
||||
assert := internal.NewAssert(t, "TestSelectionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -113,12 +113,12 @@ func TestSelectionSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestShellSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestShellSort")
|
||||
assert := internal.NewAssert(t, "TestShellSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -133,12 +133,12 @@ func TestShellSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestQuickSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestQuickSort")
|
||||
assert := internal.NewAssert(t, "TestQuickSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -153,12 +153,12 @@ func TestQuickSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestHeapSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestHeapSort")
|
||||
assert := internal.NewAssert(t, "TestHeapSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -173,12 +173,12 @@ func TestHeapSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestMergeSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestMergeSort")
|
||||
assert := internal.NewAssert(t, "TestMergeSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -193,12 +193,12 @@ func TestMergeSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestCountSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
asssert := internal.NewAssert(t, "TestCountSort")
|
||||
assert := internal.NewAssert(t, "TestCountSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
@@ -213,5 +213,5 @@ func TestCountSort(t *testing.T) {
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", sortedPeopleByAge)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// operator type
|
||||
@@ -62,3 +64,9 @@ func LessOrEqual(left, right any) bool {
|
||||
func GreaterOrEqual(left, right any) bool {
|
||||
return compareValue(greaterOrEqual, left, right)
|
||||
}
|
||||
|
||||
// InDelta checks if two values are equal or not within a delta.
|
||||
// Play: https://go.dev/play/p/TuDdcNtMkjo
|
||||
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool {
|
||||
return float64(mathutil.Abs(left-right)) <= delta
|
||||
}
|
||||
|
||||
@@ -168,3 +168,29 @@ func ExampleGreaterOrEqual() {
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleInDelta() {
|
||||
result1 := InDelta(1, 1, 0)
|
||||
result2 := InDelta(1, 2, 0)
|
||||
|
||||
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
|
||||
result4 := InDelta(2.0/3.0, 0.0, 0.001)
|
||||
|
||||
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
|
||||
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package compare
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
@@ -24,6 +25,13 @@ func compareValue(operator string, left, right any) bool {
|
||||
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
return compareRefValue(operator, left, right, leftType.Kind())
|
||||
|
||||
case reflect.Ptr:
|
||||
if leftVal, ok := left.(*big.Int); ok {
|
||||
if rightVal, ok := right.(*big.Int); ok {
|
||||
return compareBigInt(operator, leftVal, rightVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -70,7 +78,7 @@ func compareRefValue(operator string, leftObj, rightObj any, kind reflect.Kind)
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
||||
if bytes.Equal(bytesObj1, bytesObj2) {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
@@ -155,169 +163,129 @@ func compareBasicValue(operator string, leftValue, rightValue any) bool {
|
||||
}
|
||||
|
||||
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 int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
left, err := convertor.ToBigInt(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareBigInt(operator, left, right)
|
||||
|
||||
case float32, float64:
|
||||
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
|
||||
}
|
||||
}
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
return compareStrings(operator, left, right)
|
||||
}
|
||||
|
||||
case bool:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case bool:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return compareBools(operator, left, right)
|
||||
}
|
||||
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
return compareFloats(operator, left, right)
|
||||
}
|
||||
case float32, float64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return compareFloats(operator, left, right)
|
||||
|
||||
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToBigInt(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
left, err := convertor.ToBigInt(left)
|
||||
return compareBigInt(operator, left, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBigInt compares two big.Int values based on the operator
|
||||
func compareBigInt(operator string, left, right *big.Int) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left.Cmp(right) == 0
|
||||
case lessThan:
|
||||
return left.Cmp(right) < 0
|
||||
case greaterThan:
|
||||
return left.Cmp(right) > 0
|
||||
case lessOrEqual:
|
||||
return left.Cmp(right) <= 0
|
||||
case greaterOrEqual:
|
||||
return left.Cmp(right) >= 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareFloats compares two float64 values based on the operator
|
||||
func compareFloats(operator string, left, right float64) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareStrings compares two string values based on the operator
|
||||
func compareStrings(operator string, left, right string) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
case lessThan:
|
||||
return left < right
|
||||
case greaterThan:
|
||||
return left > right
|
||||
case lessOrEqual:
|
||||
return left <= right
|
||||
case greaterOrEqual:
|
||||
return left >= right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// compareBools compares two boolean values based on the operator
|
||||
func compareBools(operator string, left, right bool) bool {
|
||||
switch operator {
|
||||
case equal:
|
||||
return left == right
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,130 +13,191 @@ func TestEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
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
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), false},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}, false},
|
||||
// {time.Now(), time.Now(), true},
|
||||
// {time.Now(), time.Now().Add(time.Second), false},
|
||||
{[]byte("hello"), []byte("hello"), true},
|
||||
{[]byte("hello"), []byte("world"), false},
|
||||
{json.Number("123"), json.Number("123"), true},
|
||||
{json.Number("123"), json.Number("124"), false},
|
||||
|
||||
{big.NewInt(123), big.NewInt(123), true},
|
||||
}
|
||||
|
||||
st2 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, Equal(tt.left, tt.right))
|
||||
}
|
||||
|
||||
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) {
|
||||
t.Parallel()
|
||||
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"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 1, true},
|
||||
{int64(1), int64(1), true},
|
||||
{"a", "a", true},
|
||||
{true, true, true},
|
||||
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
|
||||
{map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}, true},
|
||||
{1, 2, false},
|
||||
{1, int64(1), true},
|
||||
{"a", "b", false},
|
||||
{true, false, false},
|
||||
{[]int{1, 2}, []int{1, 2, 3}, false},
|
||||
}
|
||||
|
||||
assert.Equal(false, EqualValue(1, "2"))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, EqualValue(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
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"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
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)))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessThan(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
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"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "a", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 1, false},
|
||||
{1, int64(1), false},
|
||||
}
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterThan(time2, time1))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterThan(tt.left, tt.right))
|
||||
}
|
||||
|
||||
assert.Equal(false, GreaterThan(1, 2))
|
||||
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||
assert.Equal(false, GreaterThan("b", "c"))
|
||||
}
|
||||
|
||||
func TestLessOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
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"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{1, 2, true},
|
||||
{1, 1, true},
|
||||
{1.1, 2.2, true},
|
||||
{"a", "b", true},
|
||||
{time.Now(), time.Now().Add(time.Second), true},
|
||||
{[]byte("hello1"), []byte("hello2"), true},
|
||||
{json.Number("123"), json.Number("124"), true},
|
||||
{645680099112988673, 645680099112988675, true},
|
||||
{2, 1, false},
|
||||
{1, int64(2), false},
|
||||
}
|
||||
|
||||
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)))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, LessOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreaterOrEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
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"))
|
||||
tests := []struct {
|
||||
left any
|
||||
right any
|
||||
want bool
|
||||
}{
|
||||
{2, 1, true},
|
||||
{1, 1, true},
|
||||
{2.2, 1.1, true},
|
||||
{"b", "b", true},
|
||||
{time.Now().Add(time.Second), time.Now(), true},
|
||||
{[]byte("hello2"), []byte("hello1"), true},
|
||||
{json.Number("124"), json.Number("123"), true},
|
||||
{645680099112988675, 645680099112988673, true},
|
||||
{1, 2, false},
|
||||
{int64(2), 1, false},
|
||||
{"b", "c", false},
|
||||
}
|
||||
|
||||
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"))
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, GreaterOrEqual(tt.left, tt.right))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInDelta(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestInDelta")
|
||||
|
||||
tests := []struct {
|
||||
left float64
|
||||
right float64
|
||||
delta float64
|
||||
want bool
|
||||
}{
|
||||
{1, 1, 0, true},
|
||||
{1, 2, 0, false},
|
||||
{2.0 / 3.0, 0.66667, 0.001, true},
|
||||
{2.0 / 3.0, 0.0, 0.001, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 0, false},
|
||||
{float64(74.96) - float64(20.48), 54.48, 1e-14, true},
|
||||
{float64(float32(80.45)), float64(80.45), 0, false},
|
||||
{float64(float32(80.45)), float64(80.45), 1e-5, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(tt.want, InDelta(tt.left, tt.right, tt.delta))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,7 @@ func Or[T, U any](a T, b U) bool {
|
||||
// Xor returns true if a or b but not both is truthy.
|
||||
// Play: https://go.dev/play/p/gObZrW7ZbG8
|
||||
func Xor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA || valB) && valA != valB
|
||||
return Bool(a) != Bool(b)
|
||||
}
|
||||
|
||||
// Nor returns true if neither a nor b is truthy.
|
||||
@@ -63,9 +61,7 @@ func Nor[T, U any](a T, b U) bool {
|
||||
// Xnor returns true if both a and b or neither a nor b are truthy.
|
||||
// Play: https://go.dev/play/p/OuDB9g51643
|
||||
func Xnor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA && valB) || (!valA && !valB)
|
||||
return Bool(a) == Bool(b)
|
||||
}
|
||||
|
||||
// Nand returns false if both a and b are truthy.
|
||||
@@ -76,10 +72,17 @@ func Nand[T, U any](a T, b U) bool {
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
} else {
|
||||
return elseValue
|
||||
}
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
// Deprecated: Use Ternary instead.
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
return Ternary(isTrue, ifValue, elseValue)
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ func ExampleNand() {
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
func ExampleTernary() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
result1 := Ternary(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
result2 := Ternary(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
|
||||
@@ -124,13 +124,13 @@ func TestNand(t *testing.T) {
|
||||
assert.Equal(false, Nand(1, 1))
|
||||
}
|
||||
|
||||
func TestTernaryOperator(t *testing.T) {
|
||||
func TestTernary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TernaryOperator")
|
||||
assert := internal.NewAssert(t, "TestTernary")
|
||||
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
|
||||
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
|
||||
assert.Equal(trueValue, Ternary(true, trueValue, falseValue))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package lancetconstraints contain some comstomer constraints.
|
||||
package lancetconstraints
|
||||
// Package constraints contain some custom interface.
|
||||
package constraints
|
||||
|
||||
// Comparator is for comparing two values
|
||||
type Comparator interface {
|
||||
@@ -6,6 +6,7 @@ package convertor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -73,7 +75,7 @@ func ToBytes(value any) ([]byte, error) {
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
c := make([]string, 0, len(s))
|
||||
if len(s) == 0 {
|
||||
c = append(c, "")
|
||||
}
|
||||
@@ -394,3 +396,124 @@ func GbkToUtf8(bs []byte) ([]byte, error) {
|
||||
b, err := io.ReadAll(r)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// ToStdBase64 convert data to standard base64 encoding.
|
||||
// Play: https://go.dev/play/p/_fLJqJD3NMo
|
||||
func ToStdBase64(value any) string {
|
||||
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||
return ""
|
||||
}
|
||||
switch value.(type) {
|
||||
case []byte:
|
||||
return base64.StdEncoding.EncodeToString(value.([]byte))
|
||||
case string:
|
||||
return base64.StdEncoding.EncodeToString([]byte(value.(string)))
|
||||
case error:
|
||||
return base64.StdEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||
default:
|
||||
marshal, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToUrlBase64 convert data to URL base64 encoding.
|
||||
// Play: https://go.dev/play/p/C_d0GlvEeUR
|
||||
func ToUrlBase64(value any) string {
|
||||
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||
return ""
|
||||
}
|
||||
switch value.(type) {
|
||||
case []byte:
|
||||
return base64.URLEncoding.EncodeToString(value.([]byte))
|
||||
case string:
|
||||
return base64.URLEncoding.EncodeToString([]byte(value.(string)))
|
||||
case error:
|
||||
return base64.URLEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||
default:
|
||||
marshal, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToRawStdBase64 convert data to raw standard base64 encoding.
|
||||
// Play: https://go.dev/play/p/wSAr3sfkDcv
|
||||
func ToRawStdBase64(value any) string {
|
||||
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||
return ""
|
||||
}
|
||||
switch value.(type) {
|
||||
case []byte:
|
||||
return base64.RawStdEncoding.EncodeToString(value.([]byte))
|
||||
case string:
|
||||
return base64.RawStdEncoding.EncodeToString([]byte(value.(string)))
|
||||
case error:
|
||||
return base64.RawStdEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||
default:
|
||||
marshal, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.RawStdEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToRawUrlBase64 convert data to raw URL base64 encoding.
|
||||
// Play: https://go.dev/play/p/HwdDPFcza1O
|
||||
func ToRawUrlBase64(value any) string {
|
||||
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||
return ""
|
||||
}
|
||||
switch value.(type) {
|
||||
case []byte:
|
||||
return base64.RawURLEncoding.EncodeToString(value.([]byte))
|
||||
case string:
|
||||
return base64.RawURLEncoding.EncodeToString([]byte(value.(string)))
|
||||
case error:
|
||||
return base64.RawURLEncoding.EncodeToString([]byte(value.(error).Error()))
|
||||
default:
|
||||
marshal, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// ToBigInt converts an integer of any supported type (int, int64, uint64, etc.) to *big.Int
|
||||
// Play: todo
|
||||
func ToBigInt[T any](v T) (*big.Int, error) {
|
||||
result := new(big.Int)
|
||||
|
||||
switch v := any(v).(type) {
|
||||
case int:
|
||||
result.SetInt64(int64(v)) // Convert to int64 for big.Int
|
||||
case int8:
|
||||
result.SetInt64(int64(v))
|
||||
case int16:
|
||||
result.SetInt64(int64(v))
|
||||
case int32:
|
||||
result.SetInt64(int64(v))
|
||||
case int64:
|
||||
result.SetInt64(v)
|
||||
case uint:
|
||||
result.SetUint64(uint64(v)) // Convert to uint64 for big.Int
|
||||
case uint8:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint16:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint32:
|
||||
result.SetUint64(uint64(v))
|
||||
case uint64:
|
||||
result.SetUint64(v)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type: %T", v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package convertor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -391,3 +392,191 @@ func ExampleGbkToUtf8() {
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleToStdBase64() {
|
||||
// if you want to see the result, please use 'base64.StdEncoding.DecodeString()' to decode the result
|
||||
|
||||
afterEncode := ToStdBase64(nil)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode = ToStdBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = ToStdBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = ToStdBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = ToStdBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = ToStdBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = ToStdBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = ToStdBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
//
|
||||
// aGVsbG8=
|
||||
// aGVsbG8=
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||
// MTIzLjQ1Ng==
|
||||
// dHJ1ZQ==
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToUrlBase64() {
|
||||
// if you want to see the result, please use 'base64.URLEncoding.DecodeString()' to decode the result
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode := ToUrlBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = ToUrlBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = ToUrlBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = ToUrlBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = ToUrlBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = ToUrlBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = ToUrlBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8=
|
||||
// aGVsbG8=
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||
// MTIzLjQ1Ng==
|
||||
// dHJ1ZQ==
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToRawStdBase64() {
|
||||
// if you want to see the result, please use 'base64.RawStdEncoding.DecodeString()' to decode the result
|
||||
stringVal := "hello"
|
||||
afterEncode := ToRawStdBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = ToRawStdBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = ToRawStdBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = ToRawStdBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = ToRawStdBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = ToRawStdBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = ToRawStdBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8
|
||||
// aGVsbG8
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||
// MTIzLjQ1Ng
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToRawUrlBase64() {
|
||||
// if you want to see the result, please use 'base64.RawURLEncoding.DecodeString()' to decode the result
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode := ToRawUrlBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = ToRawUrlBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = ToRawUrlBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = ToRawUrlBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = ToRawUrlBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = ToRawUrlBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = ToRawUrlBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8
|
||||
// aGVsbG8
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||
// MTIzLjQ1Ng
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
func ExampleToBigInt() {
|
||||
n := 9876543210
|
||||
bigInt, _ := ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
val := c.clone(v.Index(i))
|
||||
|
||||
if val.IsValid() {
|
||||
if !val.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package convertor
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
@@ -337,6 +342,7 @@ func TestDeepClone(t *testing.T) {
|
||||
Nil: nil,
|
||||
// unexported: "can't be cloned",
|
||||
},
|
||||
[]interface{}{1, &Struct{Str: "test"}, Struct{Str: "test2"}},
|
||||
}
|
||||
|
||||
for i, item := range cases {
|
||||
@@ -460,3 +466,359 @@ func TestGbkToUtf8(t *testing.T) {
|
||||
assert.Equal(true, utf8.Valid(utf8Data))
|
||||
assert.Equal("hello", string(utf8Data))
|
||||
}
|
||||
|
||||
func TestToStdBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToStdBase64")
|
||||
|
||||
r1 := ToStdBase64("abc")
|
||||
d1, _ := base64.StdEncoding.DecodeString(r1)
|
||||
assert.Equal("abc", string(d1))
|
||||
|
||||
r2 := ToStdBase64([]byte("abc"))
|
||||
d2, _ := base64.StdEncoding.DecodeString(r2)
|
||||
assert.Equal("abc", string(d2))
|
||||
|
||||
r3 := ToStdBase64(123)
|
||||
d3, _ := base64.StdEncoding.DecodeString(r3)
|
||||
assert.Equal("123", string(d3))
|
||||
|
||||
r4 := ToStdBase64(11.11)
|
||||
d4, _ := base64.StdEncoding.DecodeString(r4)
|
||||
assert.Equal("11.11", string(d4))
|
||||
|
||||
r5 := ToStdBase64(map[string]any{"name": "duke", "quantity": 1})
|
||||
d5, _ := base64.StdEncoding.DecodeString(r5)
|
||||
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||
|
||||
r6 := ToStdBase64([]int64{7, 5, 9, 4, 23})
|
||||
d6, _ := base64.StdEncoding.DecodeString(r6)
|
||||
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||
|
||||
r7 := ToStdBase64([]string{"7", "5", "9", "4", "23"})
|
||||
d7, _ := base64.StdEncoding.DecodeString(r7)
|
||||
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||
|
||||
r8 := ToStdBase64(nil)
|
||||
d8, _ := base64.StdEncoding.DecodeString(r8)
|
||||
assert.Equal("", string(d8))
|
||||
|
||||
ch := make(chan int, 3)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
r9 := ToStdBase64(ch)
|
||||
d9, _ := base64.StdEncoding.DecodeString(r9)
|
||||
assert.Equal("", string(d9))
|
||||
|
||||
r10 := ToStdBase64(io.EOF)
|
||||
d10, _ := base64.StdEncoding.DecodeString(r10)
|
||||
assert.Equal("EOF", string(d10))
|
||||
|
||||
r11 := ToStdBase64(errors.New("test"))
|
||||
d11, _ := base64.StdEncoding.DecodeString(r11)
|
||||
assert.Equal("test", string(d11))
|
||||
|
||||
typedNil := (*int)(nil)
|
||||
r12 := ToStdBase64(typedNil)
|
||||
d12, _ := base64.StdEncoding.DecodeString(r12)
|
||||
assert.Equal("", string(d12))
|
||||
|
||||
type nilInterface interface {
|
||||
}
|
||||
var nI nilInterface = nil
|
||||
d13, _ := base64.StdEncoding.DecodeString(ToStdBase64(nI))
|
||||
assert.Equal("", string(d13))
|
||||
|
||||
var p unsafe.Pointer
|
||||
d14, _ := base64.StdEncoding.DecodeString(ToStdBase64(p))
|
||||
assert.Equal("", string(d14))
|
||||
}
|
||||
|
||||
func TestToUrlBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToUrlBase64")
|
||||
|
||||
r1 := ToUrlBase64("abc")
|
||||
d1, _ := base64.URLEncoding.DecodeString(r1)
|
||||
assert.Equal("abc", string(d1))
|
||||
|
||||
r2 := ToUrlBase64([]byte("abc"))
|
||||
d2, _ := base64.URLEncoding.DecodeString(r2)
|
||||
assert.Equal("abc", string(d2))
|
||||
|
||||
r3 := ToUrlBase64(123)
|
||||
d3, _ := base64.URLEncoding.DecodeString(r3)
|
||||
assert.Equal("123", string(d3))
|
||||
|
||||
r4 := ToUrlBase64(11.11)
|
||||
d4, _ := base64.URLEncoding.DecodeString(r4)
|
||||
assert.Equal("11.11", string(d4))
|
||||
|
||||
r5 := ToUrlBase64(map[string]any{"name": "duke", "quantity": 1})
|
||||
d5, _ := base64.URLEncoding.DecodeString(r5)
|
||||
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||
|
||||
r6 := ToUrlBase64([]int64{7, 5, 9, 4, 23})
|
||||
d6, _ := base64.URLEncoding.DecodeString(r6)
|
||||
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||
|
||||
r7 := ToUrlBase64([]string{"7", "5", "9", "4", "23"})
|
||||
d7, _ := base64.URLEncoding.DecodeString(r7)
|
||||
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||
|
||||
r8 := ToUrlBase64(nil)
|
||||
d8, _ := base64.URLEncoding.DecodeString(r8)
|
||||
assert.Equal("", string(d8))
|
||||
|
||||
ch := make(chan int, 3)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
r9 := ToUrlBase64(ch)
|
||||
d9, _ := base64.URLEncoding.DecodeString(r9)
|
||||
assert.Equal("", string(d9))
|
||||
|
||||
r10 := ToUrlBase64(io.EOF)
|
||||
d10, _ := base64.URLEncoding.DecodeString(r10)
|
||||
assert.Equal("EOF", string(d10))
|
||||
|
||||
r11 := ToUrlBase64(errors.New("test"))
|
||||
d11, _ := base64.URLEncoding.DecodeString(r11)
|
||||
assert.Equal("test", string(d11))
|
||||
|
||||
typedNil := (*int)(nil)
|
||||
r12 := ToUrlBase64(typedNil)
|
||||
d12, _ := base64.URLEncoding.DecodeString(r12)
|
||||
assert.Equal("", string(d12))
|
||||
|
||||
type nilInterface interface {
|
||||
}
|
||||
var nI nilInterface = nil
|
||||
d13, _ := base64.URLEncoding.DecodeString(ToUrlBase64(nI))
|
||||
assert.Equal("", string(d13))
|
||||
|
||||
var p unsafe.Pointer
|
||||
d14, _ := base64.URLEncoding.DecodeString(ToUrlBase64(p))
|
||||
assert.Equal("", string(d14))
|
||||
|
||||
r15 := ToUrlBase64("4+3/4?=")
|
||||
d15, _ := base64.URLEncoding.DecodeString(r15)
|
||||
assert.Equal("4+3/4?=", string(d15))
|
||||
}
|
||||
|
||||
func TestToRawStdBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToRawStdBase64")
|
||||
|
||||
r1 := ToRawStdBase64("abc")
|
||||
d1, _ := base64.RawStdEncoding.DecodeString(r1)
|
||||
assert.Equal("abc", string(d1))
|
||||
|
||||
r2 := ToRawStdBase64([]byte("abc"))
|
||||
d2, _ := base64.RawStdEncoding.DecodeString(r2)
|
||||
assert.Equal("abc", string(d2))
|
||||
|
||||
r3 := ToRawStdBase64(123)
|
||||
d3, _ := base64.RawStdEncoding.DecodeString(r3)
|
||||
assert.Equal("123", string(d3))
|
||||
|
||||
r4 := ToRawStdBase64(11.11)
|
||||
d4, _ := base64.RawStdEncoding.DecodeString(r4)
|
||||
assert.Equal("11.11", string(d4))
|
||||
|
||||
r5 := ToRawStdBase64(map[string]any{"name": "duke", "quantity": 1})
|
||||
d5, _ := base64.RawStdEncoding.DecodeString(r5)
|
||||
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||
|
||||
r6 := ToRawStdBase64([]int64{7, 5, 9, 4, 23})
|
||||
d6, _ := base64.RawStdEncoding.DecodeString(r6)
|
||||
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||
|
||||
r7 := ToRawStdBase64([]string{"7", "5", "9", "4", "23"})
|
||||
d7, _ := base64.RawStdEncoding.DecodeString(r7)
|
||||
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||
|
||||
r8 := ToRawStdBase64(nil)
|
||||
d8, _ := base64.RawStdEncoding.DecodeString(r8)
|
||||
assert.Equal("", string(d8))
|
||||
|
||||
ch := make(chan int, 3)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
r9 := ToRawStdBase64(ch)
|
||||
d9, _ := base64.RawStdEncoding.DecodeString(r9)
|
||||
assert.Equal("", string(d9))
|
||||
|
||||
r10 := ToRawStdBase64(io.EOF)
|
||||
d10, _ := base64.RawStdEncoding.DecodeString(r10)
|
||||
assert.Equal("EOF", string(d10))
|
||||
|
||||
r11 := ToRawStdBase64(errors.New("test"))
|
||||
d11, _ := base64.RawStdEncoding.DecodeString(r11)
|
||||
assert.Equal("test", string(d11))
|
||||
|
||||
typedNil := (*int)(nil)
|
||||
r12 := ToRawStdBase64(typedNil)
|
||||
d12, _ := base64.RawStdEncoding.DecodeString(r12)
|
||||
assert.Equal("", string(d12))
|
||||
|
||||
type nilInterface interface {
|
||||
}
|
||||
var nI nilInterface = nil
|
||||
d13, _ := base64.RawStdEncoding.DecodeString(ToRawStdBase64(nI))
|
||||
assert.Equal("", string(d13))
|
||||
|
||||
var p unsafe.Pointer
|
||||
d14, _ := base64.RawStdEncoding.DecodeString(ToRawStdBase64(p))
|
||||
assert.Equal("", string(d14))
|
||||
}
|
||||
|
||||
func TestToRawUrlBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToRawUrlBase64")
|
||||
|
||||
r1 := ToRawUrlBase64("abc")
|
||||
d1, _ := base64.RawURLEncoding.DecodeString(r1)
|
||||
assert.Equal("abc", string(d1))
|
||||
|
||||
r2 := ToRawUrlBase64([]byte("abc"))
|
||||
d2, _ := base64.RawURLEncoding.DecodeString(r2)
|
||||
assert.Equal("abc", string(d2))
|
||||
|
||||
r3 := ToRawUrlBase64(123)
|
||||
d3, _ := base64.RawURLEncoding.DecodeString(r3)
|
||||
assert.Equal("123", string(d3))
|
||||
|
||||
r4 := ToRawUrlBase64(11.11)
|
||||
d4, _ := base64.RawURLEncoding.DecodeString(r4)
|
||||
assert.Equal("11.11", string(d4))
|
||||
|
||||
r5 := ToRawUrlBase64(map[string]any{"name": "duke", "quantity": 1})
|
||||
d5, _ := base64.RawURLEncoding.DecodeString(r5)
|
||||
assert.Equal("{\"name\":\"duke\",\"quantity\":1}", string(d5))
|
||||
|
||||
r6 := ToRawUrlBase64([]int64{7, 5, 9, 4, 23})
|
||||
d6, _ := base64.RawURLEncoding.DecodeString(r6)
|
||||
assert.Equal("[7,5,9,4,23]", string(d6))
|
||||
|
||||
r7 := ToRawUrlBase64([]string{"7", "5", "9", "4", "23"})
|
||||
d7, _ := base64.RawURLEncoding.DecodeString(r7)
|
||||
assert.Equal("[\"7\",\"5\",\"9\",\"4\",\"23\"]", string(d7))
|
||||
|
||||
r8 := ToRawUrlBase64(nil)
|
||||
d8, _ := base64.RawURLEncoding.DecodeString(r8)
|
||||
assert.Equal("", string(d8))
|
||||
|
||||
ch := make(chan int, 3)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
r9 := ToRawUrlBase64(ch)
|
||||
d9, _ := base64.RawURLEncoding.DecodeString(r9)
|
||||
assert.Equal("", string(d9))
|
||||
|
||||
r10 := ToRawUrlBase64(io.EOF)
|
||||
d10, _ := base64.RawURLEncoding.DecodeString(r10)
|
||||
assert.Equal("EOF", string(d10))
|
||||
|
||||
r11 := ToRawUrlBase64(errors.New("test"))
|
||||
d11, _ := base64.RawURLEncoding.DecodeString(r11)
|
||||
assert.Equal("test", string(d11))
|
||||
|
||||
typedNil := (*int)(nil)
|
||||
r12 := ToRawUrlBase64(typedNil)
|
||||
d12, _ := base64.RawURLEncoding.DecodeString(r12)
|
||||
assert.Equal("", string(d12))
|
||||
|
||||
type nilInterface interface {
|
||||
}
|
||||
var nI nilInterface = nil
|
||||
d13, _ := base64.RawURLEncoding.DecodeString(ToRawUrlBase64(nI))
|
||||
assert.Equal("", string(d13))
|
||||
|
||||
var p unsafe.Pointer
|
||||
d14, _ := base64.RawURLEncoding.DecodeString(ToRawUrlBase64(p))
|
||||
assert.Equal("", string(d14))
|
||||
|
||||
r15 := ToRawUrlBase64("4+3/4?=")
|
||||
d15, _ := base64.RawURLEncoding.DecodeString(r15)
|
||||
assert.Equal("4+3/4?=", string(d15))
|
||||
}
|
||||
|
||||
func TestToBigInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestToBigInt")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want *big.Int
|
||||
hasErr bool
|
||||
}{
|
||||
{
|
||||
name: "int",
|
||||
input: 42,
|
||||
want: big.NewInt(42),
|
||||
},
|
||||
{
|
||||
name: "int8",
|
||||
input: int8(127),
|
||||
want: big.NewInt(127),
|
||||
},
|
||||
{
|
||||
name: "int16",
|
||||
input: int16(32000),
|
||||
want: big.NewInt(32000),
|
||||
},
|
||||
{
|
||||
name: "int32",
|
||||
input: int32(123456),
|
||||
want: big.NewInt(123456),
|
||||
},
|
||||
{
|
||||
name: "int64",
|
||||
input: int64(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint",
|
||||
input: uint(987654321),
|
||||
want: big.NewInt(987654321),
|
||||
},
|
||||
{
|
||||
name: "uint8",
|
||||
input: uint8(255),
|
||||
want: big.NewInt(255),
|
||||
},
|
||||
{
|
||||
name: "uint16",
|
||||
input: uint16(65535),
|
||||
want: big.NewInt(65535),
|
||||
},
|
||||
{
|
||||
name: "uint32",
|
||||
input: uint32(4294967295),
|
||||
want: big.NewInt(4294967295),
|
||||
},
|
||||
{
|
||||
name: "uint64",
|
||||
input: uint64(18446744073709551615),
|
||||
want: new(big.Int).SetUint64(18446744073709551615),
|
||||
},
|
||||
{
|
||||
name: "unsupported type",
|
||||
input: 3.14, // Unsupported type
|
||||
hasErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ToBigInt(tt.input)
|
||||
if (err != nil) != tt.hasErr {
|
||||
t.Errorf("ToBigInt() error = %v, hasErr %v", err, tt.hasErr)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
104
cryptor/basic.go
104
cryptor/basic.go
@@ -40,14 +40,30 @@ func Md5String(s string) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5String return the md5 string of byte slice.
|
||||
// Play: todo
|
||||
// Md5StringWithBase64 return the md5 value of string with base64.
|
||||
// Play: https://go.dev/play/p/Lx4gH7Vdr5_y
|
||||
func Md5StringWithBase64(s string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(s))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5Byte return the md5 string of byte slice.
|
||||
// Play: https://go.dev/play/p/suraalH8lyC
|
||||
func Md5Byte(data []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(data)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
|
||||
// Play: https://go.dev/play/p/Tcb-Z7LN2ax
|
||||
func Md5ByteWithBase64(data []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(data)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5File return the md5 value of file.
|
||||
func Md5File(filename string) (string, error) {
|
||||
if fileInfo, err := os.Stat(filename); err != nil {
|
||||
@@ -82,56 +98,112 @@ func Md5File(filename string) (string, error) {
|
||||
|
||||
// HmacMd5 return the hmac hash of string use md5.
|
||||
// Play: https://go.dev/play/p/uef0q1fz53I
|
||||
func HmacMd5(data, key string) string {
|
||||
func HmacMd5(str, key string) string {
|
||||
h := hmac.New(md5.New, []byte(key))
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
|
||||
// https://go.dev/play/p/UY0ng2AefFC
|
||||
func HmacMd5WithBase64(data, key string) string {
|
||||
h := hmac.New(md5.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha1 return the hmac hash of string use sha1.
|
||||
// Play: https://go.dev/play/p/1UI4oQ4WXKM
|
||||
func HmacSha1(data, key string) string {
|
||||
func HmacSha1(str, key string) string {
|
||||
h := hmac.New(sha1.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
|
||||
// Play: https://go.dev/play/p/47JmmGrnF7B
|
||||
func HmacSha1WithBase64(str, key string) string {
|
||||
h := hmac.New(sha1.New, []byte(key))
|
||||
h.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha256 return the hmac hash of string use sha256.
|
||||
// Play: https://go.dev/play/p/HhpwXxFhhC0
|
||||
func HmacSha256(data, key string) string {
|
||||
func HmacSha256(str, key string) string {
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
|
||||
// Play: https://go.dev/play/p/EKbkUvPTLwO
|
||||
func HmacSha256WithBase64(str, key string) string {
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
h.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha512 return the hmac hash of string use sha512.
|
||||
// Play: https://go.dev/play/p/59Od6m4A0Ud
|
||||
func HmacSha512(data, key string) string {
|
||||
func HmacSha512(str, key string) string {
|
||||
h := hmac.New(sha512.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
|
||||
// Play: https://go.dev/play/p/c6dSe3E2ydU
|
||||
func HmacSha512WithBase64(str, key string) string {
|
||||
h := hmac.New(sha512.New, []byte(key))
|
||||
h.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/_m_uoD1deMT
|
||||
func Sha1(data string) string {
|
||||
func Sha1(str string) string {
|
||||
sha1 := sha1.New()
|
||||
sha1.Write([]byte(data))
|
||||
sha1.Write([]byte(str))
|
||||
return hex.EncodeToString(sha1.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
|
||||
// Play: https://go.dev/play/p/fSyx-Gl2l2-
|
||||
func Sha1WithBase64(str string) string {
|
||||
sha1 := sha1.New()
|
||||
sha1.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(sha1.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/tU9tfBMIAr1
|
||||
func Sha256(data string) string {
|
||||
func Sha256(str string) string {
|
||||
sha256 := sha256.New()
|
||||
sha256.Write([]byte(data))
|
||||
sha256.Write([]byte(str))
|
||||
return hex.EncodeToString(sha256.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
|
||||
// Play: https://go.dev/play/p/85IXJHIal1k
|
||||
func Sha256WithBase64(str string) string {
|
||||
sha256 := sha256.New()
|
||||
sha256.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(sha256.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/3WsvLYZxsHa
|
||||
func Sha512(data string) string {
|
||||
func Sha512(str string) string {
|
||||
sha512 := sha512.New()
|
||||
sha512.Write([]byte(data))
|
||||
sha512.Write([]byte(str))
|
||||
return hex.EncodeToString(sha512.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
|
||||
// Play: https://go.dev/play/p/q_fY2rA-k5I
|
||||
func Sha512WithBase64(str string) string {
|
||||
sha512 := sha512.New()
|
||||
sha512.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@ func TestMd5String(t *testing.T) {
|
||||
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
|
||||
}
|
||||
|
||||
func TestMd5StringWithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
|
||||
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
|
||||
}
|
||||
|
||||
func TestMd5Byte(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -35,6 +42,13 @@ func TestMd5Byte(t *testing.T) {
|
||||
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
|
||||
}
|
||||
|
||||
func TestMd5ByteWithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
|
||||
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
|
||||
}
|
||||
|
||||
func TestMd5File(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -51,6 +65,13 @@ func TestHmacMd5(t *testing.T) {
|
||||
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
|
||||
}
|
||||
|
||||
func TestHmacMd5WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
|
||||
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
|
||||
}
|
||||
|
||||
func TestHmacSha1(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -63,18 +84,42 @@ func TestHmacSha1(t *testing.T) {
|
||||
assert.Equal(expected, hmacSha1)
|
||||
}
|
||||
|
||||
func TestHmacSha1WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := "hello"
|
||||
key := "12345"
|
||||
hmacSha1 := HmacSha1WithBase64(s, key)
|
||||
expected := "XGqdsMzLkuNu0DI/0Jt/k23prOA="
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacSha1")
|
||||
assert.Equal(expected, hmacSha1)
|
||||
}
|
||||
|
||||
func TestHmacSha256(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := "hello world"
|
||||
str := "hello world"
|
||||
key := "12345"
|
||||
hmacSha256 := HmacSha256(s, key)
|
||||
hmacSha256 := HmacSha256(str, key)
|
||||
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacSha256")
|
||||
assert.Equal(expected, hmacSha256)
|
||||
}
|
||||
|
||||
func TestHmacSha256WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
hms := HmacSha256WithBase64(str, key)
|
||||
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
|
||||
assert.Equal(expected, hms)
|
||||
}
|
||||
|
||||
func TestHmacSha512(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -87,6 +132,18 @@ func TestHmacSha512(t *testing.T) {
|
||||
assert.Equal(expected, hmacSha512)
|
||||
}
|
||||
|
||||
func TestHmacSha512WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
hms := HmacSha512WithBase64(str, key)
|
||||
expected := "3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A=="
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacSha512WithBase64")
|
||||
assert.Equal(expected, hms)
|
||||
}
|
||||
|
||||
func TestSha1(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -98,6 +155,16 @@ func TestSha1(t *testing.T) {
|
||||
assert.Equal(expected, sha1)
|
||||
}
|
||||
|
||||
func TestSha1WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
str := Sha1WithBase64("hello")
|
||||
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha1WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
func TestSha256(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -109,6 +176,16 @@ func TestSha256(t *testing.T) {
|
||||
assert.Equal(expected, sha256)
|
||||
}
|
||||
|
||||
func TestSha256WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
str := Sha256WithBase64("hello")
|
||||
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha256WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
func TestSha512(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -119,3 +196,13 @@ func TestSha512(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSha512")
|
||||
assert.Equal(expected, sha512)
|
||||
}
|
||||
|
||||
func TestSha512WithBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
str := Sha512WithBase64("hello")
|
||||
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha512WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
@@ -8,15 +8,20 @@ package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
@@ -75,6 +80,11 @@ func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/IOq_g8_lKZD
|
||||
func AesCbcEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
@@ -94,6 +104,11 @@ func AesCbcEncrypt(data, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/IOq_g8_lKZD
|
||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
@@ -110,6 +125,11 @@ func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/SpaZO0-5Nsp
|
||||
func AesCtrCrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
@@ -125,6 +145,11 @@ func AesCtrCrypt(data, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/tfkF10B13kH
|
||||
func AesCfbEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -147,6 +172,11 @@ func AesCfbEncrypt(data, key []byte) []byte {
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/tfkF10B13kH
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
@@ -166,6 +196,11 @@ func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/VtHxtkUj-3F
|
||||
func AesOfbEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -188,6 +223,11 @@ func AesOfbEncrypt(data, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/VtHxtkUj-3F
|
||||
func AesOfbDecrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -208,6 +248,56 @@ func AesOfbDecrypt(data, key []byte) []byte {
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// AesGcmEncrypt encrypt data with key use AES GCM algorithm
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ciphertext := gcm.Seal(nonce, nonce, data, nil)
|
||||
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
// AesGcmDecrypt decrypt data with key use AES GCM algorithm
|
||||
// Play: https://go.dev/play/p/rUt0-DmsPCs
|
||||
func AesGcmDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(data) < nonceSize {
|
||||
panic("ciphertext too short")
|
||||
}
|
||||
|
||||
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return plaintext
|
||||
}
|
||||
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/8qivmPeZy4P
|
||||
@@ -254,6 +344,11 @@ func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/4cC4QvWfe3_1
|
||||
func DesCbcEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, _ := des.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
@@ -274,6 +369,11 @@ func DesCbcEncrypt(data, key []byte) []byte {
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/4cC4QvWfe3_1
|
||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := encrypted[:des.BlockSize]
|
||||
@@ -290,6 +390,11 @@ func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/9-T6OjKpcdw
|
||||
func DesCtrCrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
@@ -305,6 +410,11 @@ func DesCtrCrypt(data, key []byte) []byte {
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/y-eNxcFBlxL
|
||||
func DesCfbEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -326,6 +436,11 @@ func DesCfbEncrypt(data, key []byte) []byte {
|
||||
// len(encrypted) should be great than 16, len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/y-eNxcFBlxL
|
||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, _ := des.NewCipher(key)
|
||||
if len(encrypted) < des.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
@@ -340,9 +455,14 @@ func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
}
|
||||
|
||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/74KmNadjN1J
|
||||
func DesOfbEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -364,6 +484,11 @@ func DesOfbEncrypt(data, key []byte) []byte {
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/74KmNadjN1J
|
||||
func DesOfbDecrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 8 {
|
||||
panic("key length shoud be 8")
|
||||
}
|
||||
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -470,6 +595,7 @@ func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return cipherText
|
||||
}
|
||||
|
||||
@@ -503,5 +629,182 @@ func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return plainText
|
||||
}
|
||||
|
||||
// GenerateRsaKeyPair create rsa private and public key.
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey) {
|
||||
privateKey, _ := rsa.GenerateKey(rand.Reader, keySize)
|
||||
return privateKey, &privateKey.PublicKey
|
||||
}
|
||||
|
||||
// RsaEncryptOAEP encrypts the given data with RSA-OAEP.
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func RsaEncryptOAEP(data []byte, label []byte, key rsa.PublicKey) ([]byte, error) {
|
||||
encryptedBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &key, data, label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return encryptedBytes, nil
|
||||
}
|
||||
|
||||
// RsaDecryptOAEP decrypts the data with RSA-OAEP.
|
||||
// Play: https://go.dev/play/p/sSVmkfENKMz
|
||||
func RsaDecryptOAEP(ciphertext []byte, label []byte, key rsa.PrivateKey) ([]byte, error) {
|
||||
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, &key, ciphertext, label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decryptedBytes, nil
|
||||
}
|
||||
|
||||
// RsaSign signs the data with RSA.
|
||||
// Play: todo
|
||||
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
|
||||
privateKey, err := loadRasPrivateKey(privateKeyFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
|
||||
}
|
||||
|
||||
// RsaVerifySign verifies the signature of the data with RSA.
|
||||
// Play: todo
|
||||
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
|
||||
publicKey, err := loadRsaPublicKey(pubKeyFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hashed, err := hashData(hash, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rsa.VerifyPKCS1v15(publicKey, hash, hashed, signature)
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRsaPublicKey(filename string) (*rsa.PublicKey, error) {
|
||||
pubKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(pubKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the public key")
|
||||
}
|
||||
|
||||
var pubKey *rsa.PublicKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
if blockType == "RSA PUBLIC KEY" {
|
||||
pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
// todo: here should be a bug, should return nil, err
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
}
|
||||
} else if blockType == "PUBLIC KEY" {
|
||||
key, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
pubKey, ok = key.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// loadRsaPrivateKey loads and parses a PEM encoded private key file.
|
||||
func loadRasPrivateKey(filename string) (*rsa.PrivateKey, error) {
|
||||
priKeyData, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(priKeyData)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block containing the private key")
|
||||
}
|
||||
|
||||
var privateKey *rsa.PrivateKey
|
||||
blockType := strings.ToUpper(block.Type)
|
||||
|
||||
// PKCS#1 format
|
||||
if blockType == "RSA PRIVATE KEY" {
|
||||
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if blockType == "PRIVATE KEY" { // PKCS#8 format
|
||||
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ok bool
|
||||
privateKey, ok = priKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to parse RSA private key")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
// hashData returns the hash value of the data, using the specified hash function
|
||||
func hashData(hash crypto.Hash, data []byte) ([]byte, error) {
|
||||
if !hash.Available() {
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
var hashed []byte
|
||||
|
||||
switch hash {
|
||||
case crypto.SHA224:
|
||||
h := sha256.Sum224(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA256:
|
||||
h := sha256.Sum256(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA384:
|
||||
h := sha512.Sum384(data)
|
||||
hashed = h[:]
|
||||
case crypto.SHA512:
|
||||
h := sha512.Sum512(data)
|
||||
hashed = h[:]
|
||||
default:
|
||||
return nil, errors.New("unsupported hash algorithm")
|
||||
}
|
||||
|
||||
return hashed, nil
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package cryptor
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleAesEcbEncrypt() {
|
||||
data := "hello"
|
||||
@@ -127,6 +130,34 @@ func ExampleAesOfbDecrypt() {
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesGcmEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesGcmEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesGcmDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesGcmDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesGcmEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesGcmDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesEcbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
@@ -254,7 +285,7 @@ func ExampleDesOfbDecrypt() {
|
||||
|
||||
func ExampleGenerateRsaKey() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -267,14 +298,14 @@ func ExampleGenerateRsaKey() {
|
||||
|
||||
func ExampleRsaEncrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -284,14 +315,14 @@ func ExampleRsaEncrypt() {
|
||||
|
||||
func ExampleRsaDecrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "rsa_private_example.pem", "rsa_public_example.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private_example.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
@@ -322,49 +353,89 @@ func ExampleHmacMd5() {
|
||||
key := "12345"
|
||||
|
||||
hms := HmacMd5(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// e834306eab892d872525d4918a7a639a
|
||||
}
|
||||
|
||||
func ExampleHmacMd5WithBase64() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacMd5WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 6DQwbquJLYclJdSRinpjmg==
|
||||
}
|
||||
|
||||
func ExampleHmacSha1() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha1(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
|
||||
}
|
||||
|
||||
func ExampleHmacSha1WithBase64() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha1WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
|
||||
}
|
||||
|
||||
func ExampleHmacSha256() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha256(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
|
||||
}
|
||||
|
||||
func ExampleHmacSha256WithBase64() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha256WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
|
||||
}
|
||||
|
||||
func ExampleHmacSha512() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha512(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
|
||||
}
|
||||
|
||||
func ExampleHmacSha512WithBase64() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha512WithBase64(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
|
||||
}
|
||||
|
||||
func ExampleMd5String() {
|
||||
md5Str := Md5String("hello")
|
||||
fmt.Println(md5Str)
|
||||
@@ -373,6 +444,14 @@ func ExampleMd5String() {
|
||||
// 5d41402abc4b2a76b9719d911017c592
|
||||
}
|
||||
|
||||
func ExampleMd5StringWithBase64() {
|
||||
md5Str := Md5StringWithBase64("hello")
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
|
||||
func ExampleMd5Byte() {
|
||||
md5Str := Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
@@ -380,6 +459,15 @@ func ExampleMd5Byte() {
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
|
||||
func ExampleMd5ByteWithBase64() {
|
||||
md5Str := Md5ByteWithBase64([]byte("hello"))
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// XUFAKrxLKna5cZ2REBfFkg==
|
||||
}
|
||||
|
||||
func ExampleSha1() {
|
||||
result := Sha1("hello")
|
||||
fmt.Println(result)
|
||||
@@ -388,6 +476,14 @@ func ExampleSha1() {
|
||||
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
|
||||
}
|
||||
|
||||
func ExampleSha1WithBase64() {
|
||||
result := Sha1WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
|
||||
}
|
||||
|
||||
func ExampleSha256() {
|
||||
result := Sha256("hello")
|
||||
fmt.Println(result)
|
||||
@@ -396,6 +492,14 @@ func ExampleSha256() {
|
||||
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
|
||||
}
|
||||
|
||||
func ExampleSha256WithBase64() {
|
||||
result := Sha256WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
|
||||
}
|
||||
|
||||
func ExampleSha512() {
|
||||
result := Sha512("hello")
|
||||
fmt.Println(result)
|
||||
@@ -403,3 +507,79 @@ func ExampleSha512() {
|
||||
// Output:
|
||||
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
|
||||
}
|
||||
|
||||
func ExampleSha512WithBase64() {
|
||||
result := Sha512WithBase64("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
|
||||
}
|
||||
|
||||
func ExampleRsaEncryptOAEP() {
|
||||
pri, pub := GenerateRsaKeyPair(1024)
|
||||
|
||||
data := []byte("hello world")
|
||||
label := []byte("123456")
|
||||
|
||||
encrypted, err := RsaEncryptOAEP(data, label, *pub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
decrypted, err := RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleRsaSign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRsaVerifySign() {
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("ok")
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -139,14 +140,95 @@ func TestDesOfbEncrypt(t *testing.T) {
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
err := GenerateRsaKey(4096, "./rsa_private_example.pem", "./rsa_public_example.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
encrypted := RsaEncrypt(data, "./rsa_public_example.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "./rsa_private_example.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
}
|
||||
|
||||
func TestRsaEncryptOAEP(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
t.Parallel()
|
||||
|
||||
pri, pub := GenerateRsaKeyPair(1024)
|
||||
|
||||
data := []byte("hello world")
|
||||
label := []byte("123456")
|
||||
|
||||
encrypted, err := RsaEncryptOAEP(data, label, *pub)
|
||||
assert.IsNil(err)
|
||||
|
||||
decrypted, err := RsaDecryptOAEP([]byte(encrypted), label, *pri)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("hello world", string(decrypted))
|
||||
}
|
||||
|
||||
func TestAesGcmEncrypt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesGcmEncrypt([]byte(data), []byte(key))
|
||||
decrypted := AesGcmDecrypt(encrypted, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesGcmEncrypt")
|
||||
assert.Equal(data, string(decrypted))
|
||||
}
|
||||
|
||||
func TestRsaSignAndVerify(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
data := []byte("This is a test data for RSA signing")
|
||||
hash := crypto.SHA256
|
||||
|
||||
t.Run("RSA Sign and Verify", func(t *testing.T) {
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
signature, err := RsaSign(hash, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hash, data, signature, publicKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify Invalid Signature", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
|
||||
invalidSig := []byte("InvalidSignature")
|
||||
|
||||
err := RsaVerifySign(hash, data, invalidSig, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RSA Sign and Verify With Different Hash", func(t *testing.T) {
|
||||
publicKey := "./rsa_public_example.pem"
|
||||
privateKey := "./rsa_private_example.pem"
|
||||
hashSign := crypto.SHA256
|
||||
hashVerify := crypto.SHA512
|
||||
|
||||
signature, err := RsaSign(hashSign, data, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("RsaSign failed: %v", err)
|
||||
}
|
||||
|
||||
err = RsaVerifySign(hashVerify, data, signature, publicKey)
|
||||
if err == nil {
|
||||
t.Fatalf("RsaVerifySign failed: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
51
cryptor/rsa_private.pem
Normal file
51
cryptor/rsa_private.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
MIIJKAIBAAKCAgEA5IqWfYbW1NlTDWE2plFWqD6CTquA0Ar/1E66lY8OMtrdpxTm
|
||||
chirmoISWN0BD7r2tV9T/kHs44Sy3raAfkR5ixYF5FRkb63FdIAtoynsxS6MEE26
|
||||
fgWuDAa1xwNt+t/uivnpfJk25htpBNkKGT8ii0TPPLn1N15hMHenT6PzWVjGjQxW
|
||||
cp4dUA4gXTDuqaeu7Oy7Ku2yP90/ra+cjTV8DnBJ9enQhAfu1LivJO3FgmXeuC3u
|
||||
qhhM3t9ZbNy7tvJI5PXDCaS8iesBvCp5carTSXWLpFEgvIhXQIsXtxezKAP3gRd8
|
||||
r5JPQI9FZlxyUcyf+Htkn2A4qyKhFElnP1z9j0YLFhL/gQMdtNIY7yhSb29PyuCG
|
||||
7noz25swrfxbA7ZVppM0J19JNhlpqmusBKLBNqN+KMD8EDli7NLX17S9Dj2pQF9I
|
||||
8fVXPEhkdTb67rr7y3OUANKjh0Opnt3JLoj9u1X7BfCeUSR/qq3E8RFPeyxvP1tc
|
||||
5QVqKBG6UPBo8nLQqdzJhUd8a1YEfXIUbdHLs2q5WVFu2MDavIp634+fzfcIFRoB
|
||||
tdxf5aCdxLaLocsA/aLLyL1pK6K0rpdrSUtcEBMST26qIlU0Ht+SQtaMdE2gyjkM
|
||||
M5RpLh1q/gpow+0j3zu6f5tDsu3qwgjLIx78YCTGUuCpsVMzFK4tahYSPNkCAwEA
|
||||
AQKCAgEAuXz97X2uCW0lqjtXhp+HrN+nFUC/OJtkziTj7RUBmibnNX+SFdKOHMYr
|
||||
K/KbtO+y4rwvSLKrGHIQVxBas6DR4SALwij4p2erVgXehIo3gEZqKaVckoH7pAki
|
||||
KhdPgQmU6zkw1w7nbtWaY/Pf7WO/nrdHV+s56ilwykyi/9F6Ze7Wn43+7+ICuoHs
|
||||
pJZdblcJc4Qj2RC41nq0/zwD3NwnBvT+IlgWA8MIhaArjtZospAJtwSYq3czlMRE
|
||||
KUXyGOcGYMZS+RW6bFnPu6/hh271M67ymne6ESq7XkhGBDV5FCY8EItGiJ1AM47U
|
||||
7eJkap2gzKUhovUOqV9eyz9UTComJETl2kmcjpZeaxrZZxtPap23IzBu6PJoPuDg
|
||||
hgzRWh3BrkakLdq6Km2z+jDFEQhWeHsksozuKzln5USx9wovb9LDKKFSpKm4vzW+
|
||||
7YVLZnH4Z1m4wvWQJShvZur7kkM7aNfK+xcS81OBMtqKerjWhdHqfMRVvLvtG/ev
|
||||
ftPTwRy+u02w+FoYcassTS+lW+Pnhj0ZuOewsWoNvgWg1TpPEDBkY4UJOYQPkTrS
|
||||
bixTBVI3teSjMXmjEAif+BG2LBCl7pFY5SW9Jk6eRvmxt9rEly13C+4tcBHEJnXu
|
||||
eVUMurRuB/9BAKgj4qGHPQlG455mKHQzWJxJXBpRurh+U478xm0CggEBAOgduMra
|
||||
tPDhyhy01iIAzYsh0PW9p11AcCoJkDUE/5IUf03fVt3WKdSNauHZBKTulqaCHkvz
|
||||
+pjmSwPr4JdJKcJzwk5ncResFBYF177JmYXzJzwpIPRQFNP34heaUd9cVsFckddV
|
||||
G3jR7c1vD33VElexUM94BubZFEqF2lO3/y0sLwhd7prKhwy6mctJyvyDFk02psDc
|
||||
6XzBG/sMiZ6meWA1sP4QIM6+sYdZ9ihvTNWGb1+TGojvgOHCEQ3Hv9u/qwdkzFKj
|
||||
qo25pRMV4VNMQUvYIywSB7K5c0w1ccfOINzB8kgqpHhpimAHqZw9ix4H98YmvaXS
|
||||
rr0LP8ES9xVvelcCggEBAPwOs7pWvm/R3RAXZ8Erk9x68Fsn8wzoofsGP/BG5QCC
|
||||
r1fDJr9aJAVggXOVNDktWRKkN7Cnib+Z7ymL5br3FfYPy945cF2e8nkx2ri0VveF
|
||||
glkPCFLb3lF3iLKD8nJNtiv1rpu2v4Dj09+SzQYSIF3h55BaZGUCHLskR7Mhdd74
|
||||
iTBzPaQ3NC+n0xrv8o1EXjy9w/nBt07sZojrf82Ae3mIbEFYdEHUVDaCZKKeBT4b
|
||||
9W8Q5aAt56DIkSkaBAZZZhzbfxollmeKiwJ32+finR7LZ1Fj2cTHia19Ef85U8bE
|
||||
Ow7E2cTDZkqaqgi+pFescl518DQ47PCeXfnFP0g65E8CggEAUApHubO3J0VE06dM
|
||||
G8eZGTwc+VBf0RkyVFyd3JqPoojs6SZ1puN94yysyZpzLoiTbHF8DwbfyC/JeF2z
|
||||
QZfaDZKrUyv6ZIZTGtEC92g/R2B0jBtGoNiohft5fFgbmWEXDXBlXhKb+YqybN+6
|
||||
QNLjk1eynQgvoRUEGTqU8b+F/8a3pTP23muuLCaAeAhHNdHiM9f/oovK+9j/VA+b
|
||||
uRiAzDtXgBSBq6k4QIs2BfVzUkIcT6HDSasFD1RDWzQhJZ6vVEpe5rRHUL3OfYlS
|
||||
/M1TytqKLl09SFUIvCPFy3d5/4XljRsfQeJq8/hQdW8HdOCcgTjEttSyqr+hSWvH
|
||||
xh192wKCAQB0uSY3u2XTCH9zrTMJ/HErn+7gd76REsW4JmvDjEEOHHawkJnH8SlP
|
||||
KCKqcMTPWZWvEUcM0njytolPVw6ap0OPQD9reHP1lt64iwK7mB/R3gy/yztSi6kH
|
||||
VvCBoqLKlfwvnUUvrNBAEsER/rxc/FXqw+tlKMbnE7RUYXeml28rQzLcsfEws7PC
|
||||
Adi717QeATQWstYnObL2pHjTHSOA+ee0Hx3qoNith3M8DuQlfkH1QiNFPLDpnXhv
|
||||
N5IpU3fbrNihsm/InvFon3rCONkoKAQUt6LvyOqWusSiB5Im+9g06rhinXwvJ0Ge
|
||||
eMMW65nVU/FelwUWWeo3f08LlHE6tLL3AoIBABcc549sTCMhBmQS9prESurzhPVk
|
||||
HCFYlR/GdlfNmRtTYssk25xaG+tiaEzXi7DXBq20TGNOATgoX7l9EWIRXkDuR6hS
|
||||
aRXyn+CVU3y2dhpGZBf+EUWP0u9TNSJ/RFO0ViAriL5J9kjF9hFvG36B9kRSiMrn
|
||||
mCp9NCdtRYOHjzkvbY5uRMqP8H4/nAXNMA+odPnOPDUOIcH2ztaFOtQgZxa9x/eS
|
||||
eGmnJ/V/rLvS04uVw5d7juJstEspnM4MxPHSFEDN7NG13bN+c1jTY1/85icIeRBi
|
||||
nP47M2kDQ6RrEdgYfPbdlx1wGdTUIeAm3duptTiwpwa5Q2Js22TMJYRTnbM=
|
||||
-----END rsa private key-----
|
||||
51
cryptor/rsa_private_example.pem
Normal file
51
cryptor/rsa_private_example.pem
Normal file
@@ -0,0 +1,51 @@
|
||||
-----BEGIN rsa private key-----
|
||||
MIIJJwIBAAKCAgEAwGdN8KE2NTK41cVN7i6mZZS5J86gjNs0LJDHylb2GG+K4O8s
|
||||
fq98EMKMJ2xGnKoVRJXucVohr5Eiuf5zgxQe9mpYDyDQ0vnpBkoNkfzJNZQvcQFa
|
||||
IllUeH+eN4hSBhMegPspCr2BcmC/m/N40+PjBMDaHSzeNE2SyIuyflLC7GhQvHnk
|
||||
cQXkqJVNC1yesV7zYKDV/xYPI0NxN0kE+4eR650A77jso4gloRUek0cpU4ztpe6Z
|
||||
z4za7AEKHmZO8pVHpQJihbNMhItbo6BcgeOFWImXyJfcbCtu1ayciaJ0Q45Z1btu
|
||||
F2wFwQjwZGt7DAvbzYwMBBiTpGxig/8kzibm7bL1Td7huW6Knqbfh4/v+2m+2aNK
|
||||
1u0TfncFUr17wDDfeVj/xeNOSbPu2X/AppjVX0rxmvWN+AByFfAuw7/kqMK7QZlA
|
||||
+5nNjmOojvryGOSu1he4PUnhRyJ7jofOIrLZ9YYBXpRiY/WB8t+xWIlaoPXFmsOx
|
||||
SgMwzQFGMlnSFy7nK9T4znE0QFknOQNbELPEB4UGLOEa5Tg6YD2ORDDSqCzMRdkE
|
||||
1kAgoMRC9DkRXE45KEcQlhMX9Pahwx3mPS4lMWABVudiEWyhGaR279OWjezqvtoL
|
||||
LBJ5GD9QL1XqaqCaJjp+qsHmX8re+MTA3ZJuyUtRoPXPsKCe2nZ6Ma87DlUCAwEA
|
||||
AQKCAgAWT+SJ8ygGI0ur/qV66Y4CWazfIOcdbo4uXNvOayc+zjCcxR+z0UXh6621
|
||||
JKlLoa21tm1gV8NwSLRuPUPH/51Xlh2AI54T2Udco1nPhDERNY4K3M1HDnTtRF9k
|
||||
sTpR2gW/j2DDDhbk3LNbsnBgohzBgFvK5lkeV6CeARVB8PcJ008JjFkhgj1yD15P
|
||||
4v3EM+6lVgF7A2PeAwQuFRmu0ZnqaNqi8h7/F9rFQ124VphESCOHCpRrrTn2BGjX
|
||||
/aVKHGWijRQ/zPsio8aMwxv3NBtSmSIw8Otu39qKjOnaTCyPaQKh9opdzPkd2ZuH
|
||||
Ca/LRdTHkWYTU4ZLmwYRqJTsEzbURlaTULIvsUjVAjHJd3derDeFrBOa8txYqzQi
|
||||
HSKk52vC5mhfeGYmm415SQGhsL1blxuQE6yoAClNeY+16FSjIoZOcFBA46xkc6I/
|
||||
y3nWNcJOTcYkYOpb/R2voDabAen98sZHdcD/V86wNAt/JtwdUveeBKCX7YPtAMhu
|
||||
3m6Me5c8b7F5dRTe0bnzdjjaReywooW9+XGRhbmPijqiPBjsHb8dfkZW9vtkyORL
|
||||
l8wtMvowTDLxJPB1qgPZDOFpsY/0whZpZi14vNnmGjaFRNrwWwqF5eWBy+eGsQpj
|
||||
VsvAx9PqTwkoof37h1xkdPT9Ft6T5X6gl+l83H9y9XVksenAQQKCAQEA1HRmshIk
|
||||
RSlGrLrVqiAnndRAHV6flhKsF0+1IOzr7dL7WVfVNoQV2jPcaHGW+bZoi4hP8kIj
|
||||
YXo2IBF6xSiPiIksJJ2xBmFY+afu/HLtBMwwNhF3oFGunu8ab/ZEDlLg2oRQ1616
|
||||
229MCRvgGSM59Q3JTZF0svSHu4xGZvIriRw2g500fTKh9+YiNl1hTeCp3A4f/MKl
|
||||
mo4XvFgcIC9DdfMrb0ST/RtnM9vLCIXYl5ej862PcWD0y2FbvpXtD+WA05bWUsPW
|
||||
PBseF6PUKC1IgVMo7oCBAkmnth5gkK1+a6cdZ5j+LC+q5rmK+cDa5IIJzCbXapuA
|
||||
f6NrRSd18203EwKCAQEA59bPN2eNf90W7pi2+bmGETtgz/wl4DBmVH/PsOCuMlGr
|
||||
MnnufkBD9ig7ZAK1iZhZw3tgDrlh7rBGHdFPtwLad9tH5MhwK39WSfqUwLt6CRjx
|
||||
3s6U61riGQzVLKb8iWlxek1IE7s0y/3m4YH17wdLjCOTEe1Jyi1dXcu3+oHGqFy+
|
||||
HJyBesyroaHswcwV1tUh3QgzuT6McJEolEVdu6XPvXnerYd+LNgYiz8gsrViU8E0
|
||||
WKrLnvdRMnn3ySJH7wkLBdeFi8N0glrEcF/Kcbyh6vTKuQkPzIC7szIy+Yvkinva
|
||||
6fSBoeL72i2najXWFhZsXJbpHxMmw95ZeC7SH4/J9wKCAQAaK7CO1O9E2b3L/0Pc
|
||||
rhNTPNcdBw/vg6NRR89PHABADpJJwikQixrKA0NuVje70P112rfGZuFG27AZKS4P
|
||||
ZVyw+/zFEevBlnJIZqhozptl0OVLc8FhrU4uY9PE4PgnL4xlPpFa0BLnPwGFybpE
|
||||
PnOgPS+D75wJg1fJAZGWktRMEn6gndfeaENNbzrdqYkX98nUwqSsFSojLMe9urjU
|
||||
Oh48RFUgYrk8H4kJ+VQ8W4h/u/1FQib+V2wwNXEAvCU0pRfGeLkz/s3AH7MIRHUY
|
||||
8eMRkzXik0/RAVO4emt4xvZgunhDz7PXq5OI0mhNNbWBGoesb0hv6HHexzmqjh7Y
|
||||
eqajAoIBAFiIpJsw1U1l3bMB6KYW3gbImSDz1nb1pK5SHLscIgmfPHRLMfNOkWV4
|
||||
Wa3IhxDjeCv5emZFDwv6jtwmKX3m/gzVVXAdxxAlUYtwwMuVDHZa60q9swrpqvwL
|
||||
9YBWyIulE6uzxXmbfP8Fl9y4J3W/YG9Eyo4HAq3NgyElgb2NP5Ldz8/XSG7fqA9S
|
||||
abpcOF7RB1yEHFR6eWEnXcq5bqERIfLmjk3QNzPi1gSe99qm/8SiPF474wRyx7Qx
|
||||
9Zj+mV/EIUx60EneOyjohqmvOv0SHvc9wgjFWB4tbwBwhBzd+kmUILZFJBfxOWJJ
|
||||
GuypYHcQ2xLEooO2aZBU4e/OWXmqDGMCggEAU+t1zgjUM2MTUMYDQry49j0SEQmc
|
||||
nGAxhpUxwWHH9LDJeMiD/Tb5DMlqSUwpl5CMCWyvieoG+dyydIT9T3NRa9j+8ga3
|
||||
MSVrpDtM8O6m1t/8TdbWHFH/En48KNAIQFP5DOLydF0zIfNzLlhlDn03HoIKf5XD
|
||||
mcoKiuqr9ycnh1Yp6ns9EJLRMBR2w5yJXE0eAMfj2De+GQFUzSRfHkCFSs5kK+Wp
|
||||
JGzruiS0pX24KrTV4boOfhc9yNOJ+p/1t/lbBdp0ruEeATzQO2XaUvyY2iyctllp
|
||||
fOQtpLwQSFnxDn/hkd9R/fQThQzcXinqCAv8db1hYUR4sVTmPH9lYjW2Og==
|
||||
-----END rsa private key-----
|
||||
14
cryptor/rsa_public.pem
Normal file
14
cryptor/rsa_public.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5IqWfYbW1NlTDWE2plFW
|
||||
qD6CTquA0Ar/1E66lY8OMtrdpxTmchirmoISWN0BD7r2tV9T/kHs44Sy3raAfkR5
|
||||
ixYF5FRkb63FdIAtoynsxS6MEE26fgWuDAa1xwNt+t/uivnpfJk25htpBNkKGT8i
|
||||
i0TPPLn1N15hMHenT6PzWVjGjQxWcp4dUA4gXTDuqaeu7Oy7Ku2yP90/ra+cjTV8
|
||||
DnBJ9enQhAfu1LivJO3FgmXeuC3uqhhM3t9ZbNy7tvJI5PXDCaS8iesBvCp5carT
|
||||
SXWLpFEgvIhXQIsXtxezKAP3gRd8r5JPQI9FZlxyUcyf+Htkn2A4qyKhFElnP1z9
|
||||
j0YLFhL/gQMdtNIY7yhSb29PyuCG7noz25swrfxbA7ZVppM0J19JNhlpqmusBKLB
|
||||
NqN+KMD8EDli7NLX17S9Dj2pQF9I8fVXPEhkdTb67rr7y3OUANKjh0Opnt3JLoj9
|
||||
u1X7BfCeUSR/qq3E8RFPeyxvP1tc5QVqKBG6UPBo8nLQqdzJhUd8a1YEfXIUbdHL
|
||||
s2q5WVFu2MDavIp634+fzfcIFRoBtdxf5aCdxLaLocsA/aLLyL1pK6K0rpdrSUtc
|
||||
EBMST26qIlU0Ht+SQtaMdE2gyjkMM5RpLh1q/gpow+0j3zu6f5tDsu3qwgjLIx78
|
||||
YCTGUuCpsVMzFK4tahYSPNkCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
14
cryptor/rsa_public_example.pem
Normal file
14
cryptor/rsa_public_example.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN rsa public key-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwGdN8KE2NTK41cVN7i6m
|
||||
ZZS5J86gjNs0LJDHylb2GG+K4O8sfq98EMKMJ2xGnKoVRJXucVohr5Eiuf5zgxQe
|
||||
9mpYDyDQ0vnpBkoNkfzJNZQvcQFaIllUeH+eN4hSBhMegPspCr2BcmC/m/N40+Pj
|
||||
BMDaHSzeNE2SyIuyflLC7GhQvHnkcQXkqJVNC1yesV7zYKDV/xYPI0NxN0kE+4eR
|
||||
650A77jso4gloRUek0cpU4ztpe6Zz4za7AEKHmZO8pVHpQJihbNMhItbo6BcgeOF
|
||||
WImXyJfcbCtu1ayciaJ0Q45Z1btuF2wFwQjwZGt7DAvbzYwMBBiTpGxig/8kzibm
|
||||
7bL1Td7huW6Knqbfh4/v+2m+2aNK1u0TfncFUr17wDDfeVj/xeNOSbPu2X/AppjV
|
||||
X0rxmvWN+AByFfAuw7/kqMK7QZlA+5nNjmOojvryGOSu1he4PUnhRyJ7jofOIrLZ
|
||||
9YYBXpRiY/WB8t+xWIlaoPXFmsOxSgMwzQFGMlnSFy7nK9T4znE0QFknOQNbELPE
|
||||
B4UGLOEa5Tg6YD2ORDDSqCzMRdkE1kAgoMRC9DkRXE45KEcQlhMX9Pahwx3mPS4l
|
||||
MWABVudiEWyhGaR279OWjezqvtoLLBJ5GD9QL1XqaqCaJjp+qsHmX8re+MTA3ZJu
|
||||
yUtRoPXPsKCe2nZ6Ma87DlUCAwEAAQ==
|
||||
-----END rsa public key-----
|
||||
@@ -7,6 +7,7 @@ package datastructure
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var defaultMapCapacity uint64 = 1 << 10
|
||||
@@ -45,13 +46,24 @@ func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
|
||||
func (hm *HashMap) Get(key any) any {
|
||||
hashValue := hm.hash(key)
|
||||
node := hm.table[hashValue]
|
||||
if node != nil {
|
||||
return node.value
|
||||
for node != nil {
|
||||
if reflect.DeepEqual(node.key, key) {
|
||||
return node.value
|
||||
}
|
||||
node = node.next
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrDefault return the value of given key in hashmap, if not found return default value
|
||||
func (hm *HashMap) GetOrDefault(key any, defaultValue any) any {
|
||||
value := hm.Get(key)
|
||||
if value == nil {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Put new key value in hashmap
|
||||
func (hm *HashMap) Put(key any, value any) {
|
||||
hm.putValue(hm.hash(key), key, value)
|
||||
@@ -90,7 +102,13 @@ func (hm *HashMap) Delete(key any) {
|
||||
// Contains checks if given key is in hashmap or not
|
||||
func (hm *HashMap) Contains(key any) bool {
|
||||
node := hm.table[hm.hash(key)]
|
||||
return node != nil
|
||||
for node != nil {
|
||||
if reflect.DeepEqual(node.key, key) {
|
||||
return true
|
||||
}
|
||||
node = node.next
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Iterate executes iteratee funcation for every key and value pair of hashmap (random order)
|
||||
@@ -105,6 +123,25 @@ func (hm *HashMap) Iterate(iteratee func(key, value any)) {
|
||||
}
|
||||
}
|
||||
|
||||
// FilterByValue returns a filtered HashMap.
|
||||
// If any value is not matching the perdicate function then it returns nil
|
||||
// otherwise it returns the HashMap with selected values.
|
||||
func (hm *HashMap) FilterByValue(perdicate func(value any) bool) *HashMap {
|
||||
var filteredHM *HashMap
|
||||
if hm.size > 0 {
|
||||
for i := 0; i < len(hm.table); i++ {
|
||||
item := hm.table[i]
|
||||
if item != nil && perdicate(item.value) {
|
||||
if filteredHM == nil {
|
||||
filteredHM = NewHashMap()
|
||||
}
|
||||
filteredHM.Put(item.key, item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredHM
|
||||
}
|
||||
|
||||
// Keys returns a slice of the hashmap's keys (random order)
|
||||
func (hm *HashMap) Keys() []any {
|
||||
keys := make([]any, int(hm.size))
|
||||
@@ -150,6 +187,11 @@ func (hm *HashMap) resize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns current size of Hashmap
|
||||
func (hm *HashMap) Size() uint64 {
|
||||
return hm.size
|
||||
}
|
||||
|
||||
func (hm *HashMap) hash(key any) uint64 {
|
||||
h := fnv.New64a()
|
||||
_, _ = h.Write([]byte(fmt.Sprintf("%v", key)))
|
||||
|
||||
@@ -74,3 +74,55 @@ func TestHashMap_KeysValues(t *testing.T) {
|
||||
assert.Equal(3, len(values))
|
||||
assert.Equal(3, len(keys))
|
||||
}
|
||||
|
||||
func TestHashMap_Keys(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHashMap_Keys")
|
||||
|
||||
hm := NewHashMap()
|
||||
|
||||
hm.Put("a", 1)
|
||||
hm.Put("b", 2)
|
||||
hm.Put("c", 3)
|
||||
|
||||
keys := hm.Keys()
|
||||
|
||||
assert.Equal(3, len(keys))
|
||||
}
|
||||
|
||||
func TestHashMap_GetOrDefault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHashMap_GetOrDefault")
|
||||
|
||||
hm := NewHashMap()
|
||||
|
||||
hm.Put("a", 1)
|
||||
hm.Put("b", 2)
|
||||
hm.Put("c", 3)
|
||||
|
||||
assert.Equal(1, hm.GetOrDefault("a", 5))
|
||||
assert.Equal(5, hm.GetOrDefault("d", 5))
|
||||
}
|
||||
|
||||
func TestHashMap_FilterByValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestHashMap_FilterByValue")
|
||||
|
||||
hm := NewHashMap()
|
||||
|
||||
hm.Put("a", 1)
|
||||
hm.Put("b", 2)
|
||||
hm.Put("c", 3)
|
||||
hm.Put("d", 4)
|
||||
hm.Put("e", 5)
|
||||
hm.Put("f", 6)
|
||||
|
||||
filteredHM := hm.FilterByValue(func(value any) bool {
|
||||
return value.(int) == 1 || value.(int) == 3
|
||||
})
|
||||
|
||||
assert.Equal(uint64(2), filteredHM.Size())
|
||||
}
|
||||
|
||||
@@ -7,18 +7,18 @@ package datastructure
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
)
|
||||
|
||||
// MaxHeap implements a binary max heap
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
// type T should implements Compare function in constraints.Comparator interface.
|
||||
type MaxHeap[T any] struct {
|
||||
data []T
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
// NewMaxHeap returns a MaxHeap instance with the given comparator.
|
||||
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T] {
|
||||
return &MaxHeap[T]{
|
||||
data: make([]T, 0),
|
||||
comparator: comparator,
|
||||
@@ -26,7 +26,7 @@ func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
}
|
||||
|
||||
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
|
||||
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
|
||||
func BuildMaxHeap[T any](data []T, comparator constraints.Comparator) *MaxHeap[T] {
|
||||
heap := &MaxHeap[T]{
|
||||
data: make([]T, 0, len(data)),
|
||||
comparator: comparator,
|
||||
|
||||
@@ -209,7 +209,7 @@ func (dl *DoublyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (dl *DoublyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, dl.length)
|
||||
current := dl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
@@ -212,7 +212,7 @@ func (sl *SinglyLink[T]) Size() int {
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (sl *SinglyLink[T]) Values() []T {
|
||||
result := []T{}
|
||||
result := make([]T, 0, sl.length)
|
||||
current := sl.Head
|
||||
for current != nil {
|
||||
result = append(result, current.Value)
|
||||
|
||||
379
datastructure/list/copyonwritelist.go
Normal file
379
datastructure/list/copyonwritelist.go
Normal file
@@ -0,0 +1,379 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type CopyOnWriteList[T any] struct {
|
||||
data []T
|
||||
lock sync.Locker
|
||||
}
|
||||
|
||||
// NewCopyOnWriteList Creates an empty list.
|
||||
func NewCopyOnWriteList[T any](data []T) *CopyOnWriteList[T] {
|
||||
return &CopyOnWriteList[T]{data: data, lock: &sync.RWMutex{}}
|
||||
}
|
||||
|
||||
func (c *CopyOnWriteList[T]) getList() []T {
|
||||
return c.data
|
||||
}
|
||||
func (c *CopyOnWriteList[T]) setList(data []T) {
|
||||
c.data = data
|
||||
}
|
||||
|
||||
// Size returns the number of elements in this list.
|
||||
func (c *CopyOnWriteList[T]) Size() int {
|
||||
return len(c.getList())
|
||||
}
|
||||
|
||||
// IsEmpty returns true if this list contains no elements.
|
||||
func (c *CopyOnWriteList[T]) IsEmpty() bool {
|
||||
return c.Size() == 0
|
||||
}
|
||||
|
||||
// Contain returns true if this list contains the specified element.
|
||||
func (c *CopyOnWriteList[T]) Contain(e T) bool {
|
||||
list := c.getList()
|
||||
return indexOf(e, list, 0, c.Size()) >= 0
|
||||
}
|
||||
|
||||
// ValueOf returns the index of the first occurrence of the specified element in this list, or null if this list does not contain the element.
|
||||
func (c *CopyOnWriteList[T]) ValueOf(index int) (*T, bool) {
|
||||
list := c.getList()
|
||||
if index < 0 || index >= len(c.data) {
|
||||
return nil, false
|
||||
}
|
||||
return get(list, index), true
|
||||
}
|
||||
|
||||
// IndexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
|
||||
func (c *CopyOnWriteList[T]) IndexOf(e T) int {
|
||||
list := c.getList()
|
||||
return indexOf(e, list, 0, c.Size())
|
||||
}
|
||||
|
||||
// indexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
|
||||
// start the start position of the search (inclusive)
|
||||
// end the end position of the search (exclusive)
|
||||
func indexOf[T any](o T, e []T, start int, end int) int {
|
||||
if start >= end {
|
||||
return -1
|
||||
}
|
||||
for i := start; i < end; i++ {
|
||||
if reflect.DeepEqual(e[i], o) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
|
||||
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int {
|
||||
list := c.getList()
|
||||
return lastIndexOf(e, list, 0, c.Size())
|
||||
}
|
||||
|
||||
// lastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
|
||||
// start the start position of the search (inclusive)
|
||||
// end the end position of the search (exclusive)
|
||||
func lastIndexOf[T any](o T, e []T, start int, end int) int {
|
||||
if start >= end {
|
||||
return -1
|
||||
}
|
||||
for i := end - 1; i >= start; i-- {
|
||||
if reflect.DeepEqual(e[i], o) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying the
|
||||
// functional predicate f(T) bool
|
||||
// if not found return -1.
|
||||
func (l *CopyOnWriteList[T]) LastIndexOfFunc(f func(T) bool) int {
|
||||
index := -1
|
||||
data := l.getList()
|
||||
for i := len(data) - 1; i >= 0; i-- {
|
||||
if f(data[i]) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// IndexOfFunc returns the first index satisfying the functional predicate f(v) bool
|
||||
// if not found return -1.
|
||||
func (l *CopyOnWriteList[T]) IndexOfFunc(f func(T) bool) int {
|
||||
index := -1
|
||||
data := l.getList()
|
||||
for i, v := range data {
|
||||
if f(v) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// get returns the element at the specified position in this list.
|
||||
func get[T any](o []T, index int) *T {
|
||||
return &o[index]
|
||||
}
|
||||
|
||||
// Get returns the element at the specified position in this list.
|
||||
func (c *CopyOnWriteList[T]) Get(index int) *T {
|
||||
list := c.getList()
|
||||
if index < 0 || index >= len(list) {
|
||||
return nil
|
||||
}
|
||||
return get(list, index)
|
||||
}
|
||||
|
||||
func (c *CopyOnWriteList[T]) set(index int, e T) (oldValue *T) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
list := c.getList()
|
||||
oldValue = get(list, index)
|
||||
|
||||
if reflect.DeepEqual(oldValue, e) {
|
||||
c.setList(list)
|
||||
} else {
|
||||
newList := make([]T, len(list))
|
||||
copy(newList, list)
|
||||
newList[index] = e
|
||||
c.setList(newList)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Set replaces the element at the specified position in this list with the specified element.
|
||||
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool) {
|
||||
list := c.getList()
|
||||
if index < 0 || index >= len(list) {
|
||||
return oldValue, false
|
||||
}
|
||||
return c.set(index, e), true
|
||||
}
|
||||
|
||||
// Add appends the specified element to the end of this list.
|
||||
func (c *CopyOnWriteList[T]) Add(e T) bool {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
newList := make([]T, len(list)+1)
|
||||
copy(newList, list)
|
||||
newList[len(list)] = e
|
||||
c.setList(newList)
|
||||
return true
|
||||
}
|
||||
|
||||
// AddAll appends all the elements in the specified collection to the end of this list
|
||||
func (c *CopyOnWriteList[T]) AddAll(e []T) bool {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
newList := make([]T, len(list)+len(e))
|
||||
copy(newList, list)
|
||||
copy(newList[len(list):], e)
|
||||
c.setList(newList)
|
||||
return true
|
||||
}
|
||||
|
||||
// AddByIndex inserts the specified element at the specified position in this list.
|
||||
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
length := len(list)
|
||||
if index < 0 || index > length {
|
||||
return false
|
||||
}
|
||||
var newList []T
|
||||
var numMove = length - index
|
||||
if numMove == 0 {
|
||||
newList = make([]T, length+1)
|
||||
copy(newList, list)
|
||||
} else {
|
||||
newList = make([]T, length+1)
|
||||
copy(newList, list[:index])
|
||||
copy(newList[index+1:], list[index:])
|
||||
}
|
||||
newList[index] = e
|
||||
c.setList(newList)
|
||||
return true
|
||||
}
|
||||
|
||||
// delete removes the element at the specified position in this list.
|
||||
func (c *CopyOnWriteList[T]) delete(index int) *T {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
length := len(list)
|
||||
|
||||
oldValue := get(list, index)
|
||||
numMove := length - index - 1
|
||||
var newList []T
|
||||
if numMove == 0 {
|
||||
newList = make([]T, length-1)
|
||||
copy(newList, list[:index])
|
||||
} else {
|
||||
newList = make([]T, length-1)
|
||||
copy(newList, list[:index])
|
||||
copy(newList[index:], list[index+1:])
|
||||
}
|
||||
|
||||
c.setList(newList)
|
||||
return oldValue
|
||||
}
|
||||
|
||||
// DeleteAt removes the element at the specified position in this list.
|
||||
func (c *CopyOnWriteList[T]) DeleteAt(index int) (*T, bool) {
|
||||
list := c.getList()
|
||||
if index < 0 || index >= len(list) {
|
||||
return nil, false
|
||||
}
|
||||
return c.delete(index), true
|
||||
}
|
||||
|
||||
// DeleteBy removes the first occurrence of the specified element from this list, if it is present.
|
||||
func (c *CopyOnWriteList[T]) DeleteBy(o T) (*T, bool) {
|
||||
list := c.getList()
|
||||
index := indexOf(o, list, 0, len(list))
|
||||
if index == -1 {
|
||||
return nil, false
|
||||
}
|
||||
return c.delete(index), true
|
||||
}
|
||||
|
||||
// DeleteRange removes from this list all the elements whose index is between fromIndex, inclusive, and toIndex, exclusive.
|
||||
// left close and right open
|
||||
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
length := len(list)
|
||||
if start < 0 || end > length || start > end {
|
||||
return
|
||||
}
|
||||
var newList []T
|
||||
numMove := length - end
|
||||
if numMove == 0 {
|
||||
newList = make([]T, length-(end-start))
|
||||
copy(newList, list[:start])
|
||||
} else {
|
||||
newList = make([]T, length-(end-start))
|
||||
copy(newList, list[:start])
|
||||
copy(newList[start:], list[end:])
|
||||
}
|
||||
c.setList(newList)
|
||||
}
|
||||
|
||||
// DeleteIf removes all the elements of this collection that satisfy the given predicate.
|
||||
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
length := len(list)
|
||||
var newList []T
|
||||
for i := 0; i < length; i++ {
|
||||
if !f(list[i]) {
|
||||
newList = append(newList, list[i])
|
||||
}
|
||||
}
|
||||
c.setList(newList)
|
||||
}
|
||||
|
||||
// Equal returns true if the specified object is equal to this list.
|
||||
func (c *CopyOnWriteList[T]) Equal(other *[]T) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if c.Size() != len(*other) {
|
||||
return false
|
||||
}
|
||||
list := c.getList()
|
||||
otherList := NewCopyOnWriteList(*other).getList()
|
||||
for i := 0; i < len(list); i++ {
|
||||
if !reflect.DeepEqual(list[i], otherList[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Clear removes all the elements from this list.
|
||||
func (c *CopyOnWriteList[T]) Clear() {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
list = make([]T, 0)
|
||||
c.setList(list)
|
||||
}
|
||||
|
||||
// Merge a tow list to one, change the list
|
||||
func (c *CopyOnWriteList[T]) Merge(other []T) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := c.getList()
|
||||
list = append(list, other...)
|
||||
c.setList(list)
|
||||
}
|
||||
|
||||
// ForEach performs the given action for each element of the Iterable until all elements have been processed
|
||||
// or the action throws an exception.
|
||||
func (c *CopyOnWriteList[T]) ForEach(f func(T)) {
|
||||
list := c.getList()
|
||||
for i := 0; i < len(list); i++ {
|
||||
f(list[i])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sort sorts this list according to the order induced by the specified Comparator.
|
||||
func (c *CopyOnWriteList[T]) Sort(compare func(o1 T, o2 T) bool) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
list := c.getList()
|
||||
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return compare(list[i], list[j])
|
||||
})
|
||||
|
||||
c.setList(list)
|
||||
}
|
||||
|
||||
func (c *CopyOnWriteList[T]) SubList(start int, end int) (newList []T) {
|
||||
lock := c.lock
|
||||
lock.Lock()
|
||||
list := c.getList()
|
||||
length := len(list)
|
||||
defer lock.Unlock()
|
||||
if start < 0 || end > length || start > end {
|
||||
return []T{}
|
||||
}
|
||||
newList = make([]T, end-start)
|
||||
copy(newList, list[start:end])
|
||||
c.setList(newList)
|
||||
return
|
||||
}
|
||||
268
datastructure/list/copyonwritelist_test.go
Normal file
268
datastructure/list/copyonwritelist_test.go
Normal file
@@ -0,0 +1,268 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestCopyOnWriteList_ValueOf(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
|
||||
of, ok := list.ValueOf(3)
|
||||
assert.Equal(4, *of)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = list.ValueOf(6)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Contain(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Contains")
|
||||
assert.Equal(true, list.Contain(3))
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_IsEmpty(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_IsEmpty")
|
||||
assert.Equal(true, list.IsEmpty())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Size(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_size")
|
||||
assert.Equal(5, list.Size())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_GetList(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_GetList")
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Get(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Get")
|
||||
i := list.Get(2)
|
||||
assert.Equal(3, *i)
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Set(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Set")
|
||||
list.Set(2, 6)
|
||||
assert.Equal(6, list.getList()[2])
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.Set(0, 6)
|
||||
assert.Equal(6, list.getList()[0])
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.Set(0, 1)
|
||||
assert.Equal(1, list.getList()[0])
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Add(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Add")
|
||||
list.Add(6)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_AddAll(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_AddAll")
|
||||
list.AddAll([]int{6, 7, 8})
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_AddByIndex(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_AddByIndex")
|
||||
list.AddByIndex(2, 6)
|
||||
assert.Equal([]int{1, 2, 6, 3, 4, 5}, list.getList())
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.AddByIndex(0, 6)
|
||||
assert.Equal([]int{6, 1, 2, 3, 4, 5}, list.getList())
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.AddByIndex(5, 6)
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_DeleteAt2(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByIndex")
|
||||
list.DeleteAt(2)
|
||||
assert.Equal([]int{1, 2, 4, 5}, list.getList())
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.DeleteAt(4)
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_RemoveByValue(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByValue")
|
||||
list.DeleteBy(3)
|
||||
assert.Equal([]int{1, 2, 4, 5}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_DeleteRange(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveRange")
|
||||
list.DeleteRange(1, 3)
|
||||
assert.Equal([]int{1, 4, 5}, list.getList())
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
|
||||
list.DeleteRange(0, 5)
|
||||
assert.Equal([]int{}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_LastIndexOf(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_LastIndexOf")
|
||||
assert.Equal(5, list.LastIndexOf(3))
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_DeleteAt(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteAt")
|
||||
list.DeleteAt(2)
|
||||
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_DeleteBy(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteBy")
|
||||
list.DeleteBy(3)
|
||||
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_DeleteIf(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteIf")
|
||||
|
||||
list.DeleteIf(func(i int) bool {
|
||||
return i%2 == 0
|
||||
})
|
||||
|
||||
assert.Equal([]int{1, 3, 5, 3}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Equal(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Equal")
|
||||
|
||||
assert.Equal(true, list.Equal(&[]int{1, 2, 3, 4, 5, 3, 6}))
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_ForEach(t *testing.T) {
|
||||
testList := make([]int, 0)
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_ForEach")
|
||||
|
||||
list.ForEach(func(i int) {
|
||||
testList = append(testList, i)
|
||||
})
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6}, testList)
|
||||
|
||||
list.ForEach(func(i int) {
|
||||
list.Add(i)
|
||||
})
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6, 1, 2, 3, 4, 5, 3, 6}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Clear(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Clear")
|
||||
|
||||
list.Clear()
|
||||
assert.Equal([]int{}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Merge(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Merge")
|
||||
|
||||
list.Merge([]int{2, 4, 6, 8, 10})
|
||||
assert.Equal([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10}, list.getList())
|
||||
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_Sort(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_Sort")
|
||||
|
||||
list.Sort(func(i, j int) bool {
|
||||
return i < j
|
||||
})
|
||||
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, list.getList())
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_IndexOf(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
|
||||
|
||||
assert.Equal(0, list.IndexOf(1))
|
||||
assert.Equal(9, list.IndexOf(10))
|
||||
assert.Equal(-1, list.IndexOf(11))
|
||||
}
|
||||
|
||||
func TestCopyOnWriteList_SubList(t *testing.T) {
|
||||
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
|
||||
assert := internal.NewAssert(t, "CopyOnWriteList_SubList")
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
subList := list.SubList(1, 3)
|
||||
assert.Equal([]int{3, 5}, subList)
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
subList = list.SubList(1, 1)
|
||||
assert.Equal([]int{}, subList)
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
assert.Equal(10, list.Size())
|
||||
subList = list.SubList(1, 10)
|
||||
assert.Equal([]int{3, 5, 7, 9, 2, 4, 6, 8, 10}, subList)
|
||||
|
||||
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
|
||||
subList = list.SubList(11, 1)
|
||||
assert.Equal([]int{}, subList)
|
||||
}
|
||||
|
||||
func TestCopyOnWriteListIndexOfFunc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestIndexOfFunc")
|
||||
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3})
|
||||
i := list.IndexOfFunc(func(a int) bool { return a == 1 })
|
||||
assert.Equal(0, i)
|
||||
|
||||
i = list.IndexOfFunc(func(a int) bool { return a == 4 })
|
||||
assert.Equal(-1, i)
|
||||
}
|
||||
|
||||
func TestNewCopyOnWriteListLastIndexOfFunc(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestLastIndexOfFunc")
|
||||
|
||||
list := NewCopyOnWriteList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
|
||||
i := list.LastIndexOfFunc(func(a int) bool { return a == 3 })
|
||||
assert.Equal(5, i)
|
||||
|
||||
i = list.LastIndexOfFunc(func(a int) bool { return a == 10 })
|
||||
assert.Equal(-1, i)
|
||||
|
||||
i = list.LastIndexOfFunc(func(a int) bool { return a == 4 })
|
||||
assert.Equal(6, i)
|
||||
|
||||
i = list.LastIndexOfFunc(func(a int) bool { return a == 1 })
|
||||
assert.Equal(0, i)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func (l *List[T]) Reverse() {
|
||||
}
|
||||
}
|
||||
|
||||
// Unique remove duplicate items in list.
|
||||
// Unique delete duplicate items in list.
|
||||
func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
@@ -294,7 +294,7 @@ func (l *List[T]) Unique() {
|
||||
l.data = uniqueData
|
||||
}
|
||||
|
||||
// Union creates a new list contain all element in list l and other, remove duplicate element.
|
||||
// Union creates a new list contain all element in list l and other, delete duplicate element.
|
||||
func (l *List[T]) Union(other *List[T]) *List[T] {
|
||||
result := NewList([]T{})
|
||||
|
||||
|
||||
108
datastructure/optional/optional.go
Normal file
108
datastructure/optional/optional.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package optional
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Optional is a type that may or may not contain a non-nil value.
|
||||
type Optional[T any] struct {
|
||||
value *T
|
||||
mu *sync.RWMutex
|
||||
}
|
||||
|
||||
// Default returns an default Optional instance.
|
||||
func Default[T any]() Optional[T] {
|
||||
return Optional[T]{mu: &sync.RWMutex{}}
|
||||
}
|
||||
|
||||
// Of returns an Optional with a non-nil value.
|
||||
func Of[T any](value T) Optional[T] {
|
||||
return Optional[T]{value: &value, mu: &sync.RWMutex{}}
|
||||
}
|
||||
|
||||
// FromNillable returns an Optional for a given value, which may be nil.
|
||||
func FromNillable[T any](value *T) Optional[T] {
|
||||
if value == nil {
|
||||
return Default[T]()
|
||||
}
|
||||
return Optional[T]{value: value, mu: &sync.RWMutex{}}
|
||||
}
|
||||
|
||||
// IsNotNil checks if there is a value present.
|
||||
func (o Optional[T]) IsNotNil() bool {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
return o.value != nil
|
||||
}
|
||||
|
||||
// IsNil checks if the Optional is nil.
|
||||
func (o Optional[T]) IsNil() bool {
|
||||
return !o.IsNotNil()
|
||||
}
|
||||
|
||||
// IfNotNil performs the given action with the value if a value is not nil.
|
||||
func (o Optional[T]) IfNotNil(action func(value T)) {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value != nil {
|
||||
action(*o.value)
|
||||
}
|
||||
}
|
||||
|
||||
// IfNotNilOrElse performs the action with the value if present, otherwise performs the fallback action.
|
||||
func (o Optional[T]) IfNotNilOrElse(action func(value T), fallbackAction func()) {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value != nil {
|
||||
action(*o.value)
|
||||
} else {
|
||||
fallbackAction()
|
||||
}
|
||||
}
|
||||
|
||||
// Unwarp returns the value if not nil, otherwise panics.
|
||||
func (o Optional[T]) Unwarp() T {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value == nil {
|
||||
panic("Optional.Get: no value present")
|
||||
}
|
||||
return *o.value
|
||||
}
|
||||
|
||||
// OrElse returns the value if is not nil, otherwise returns other.
|
||||
func (o Optional[T]) OrElse(other T) T {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value != nil {
|
||||
return *o.value
|
||||
}
|
||||
return other
|
||||
}
|
||||
|
||||
// OrElseGet returns the value if is not nil, otherwise invokes action and returns the result.
|
||||
func (o Optional[T]) OrElseGet(action func() T) T {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value != nil {
|
||||
return *o.value
|
||||
}
|
||||
return action()
|
||||
}
|
||||
|
||||
// OrElseTrigger returns the value if present, otherwise returns an error.
|
||||
func (o Optional[T]) OrElseTrigger(errorHandler func() error) (T, error) {
|
||||
o.mu.RLock()
|
||||
defer o.mu.RUnlock()
|
||||
|
||||
if o.value == nil {
|
||||
return *new(T), errorHandler()
|
||||
}
|
||||
return *o.value, nil
|
||||
}
|
||||
151
datastructure/optional/optional_test.go
Normal file
151
datastructure/optional/optional_test.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package optional
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestDefault(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEmpty")
|
||||
opt := Default[int]()
|
||||
|
||||
assert.ShouldBeTrue(opt.IsNil())
|
||||
}
|
||||
|
||||
func TestOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOf")
|
||||
value := 42
|
||||
opt := Of(value)
|
||||
|
||||
assert.ShouldBeTrue(opt.IsNotNil())
|
||||
assert.Equal(opt.Unwarp(), value)
|
||||
}
|
||||
|
||||
func TestFromNillable(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOfNullable")
|
||||
var value *int = nil
|
||||
opt := FromNillable(value)
|
||||
|
||||
assert.ShouldBeFalse(opt.IsNotNil())
|
||||
|
||||
value = new(int)
|
||||
*value = 42
|
||||
opt = FromNillable(value)
|
||||
|
||||
assert.ShouldBeTrue(opt.IsNotNil())
|
||||
}
|
||||
|
||||
func TestOrElse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrElse")
|
||||
optDefault := Default[int]()
|
||||
defaultValue := 100
|
||||
|
||||
val := optDefault.OrElse(defaultValue)
|
||||
assert.Equal(val, defaultValue)
|
||||
|
||||
optWithValue := Of(42)
|
||||
val = optWithValue.OrElse(defaultValue)
|
||||
assert.Equal(val, 42)
|
||||
}
|
||||
|
||||
func TestOrElseGetHappyPath(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrElseGetHappyPath")
|
||||
optWithValue := Of(42)
|
||||
action := func() int { return 100 }
|
||||
|
||||
val := optWithValue.OrElseGet(action)
|
||||
assert.Equal(val, 42)
|
||||
}
|
||||
|
||||
func TestOrElseGet(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOrElseGet")
|
||||
optDefault := Default[int]()
|
||||
action := func() int { return 100 }
|
||||
|
||||
val := optDefault.OrElseGet(action)
|
||||
assert.Equal(val, action())
|
||||
}
|
||||
|
||||
func TestOrElseTrigger(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "OrElseTrigger")
|
||||
optDefault := Default[int]()
|
||||
_, err := optDefault.OrElseTrigger(func() error { return errors.New("no value") })
|
||||
|
||||
assert.Equal(err.Error(), "no value")
|
||||
|
||||
optWithValue := Of(42)
|
||||
val, err := optWithValue.OrElseTrigger(func() error { return errors.New("no value") })
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(val, 42)
|
||||
}
|
||||
|
||||
func TestIfNotNil(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "IfNotNil")
|
||||
called := false
|
||||
action := func(value int) { called = true }
|
||||
|
||||
optDefault := Default[int]()
|
||||
optDefault.IfNotNil(action)
|
||||
|
||||
assert.ShouldBeFalse(called)
|
||||
|
||||
called = false // Reset for next test
|
||||
optWithValue := Of(42)
|
||||
optWithValue.IfNotNil(action)
|
||||
|
||||
assert.ShouldBeTrue(called)
|
||||
}
|
||||
|
||||
func TestIfNotNilOrElse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIfNotNilOrElse")
|
||||
|
||||
// Test when value is present
|
||||
calledWithValue := false
|
||||
valueAction := func(value int) { calledWithValue = true }
|
||||
fallbackAction := func() { t.Errorf("Empty action should not be called when value is present") }
|
||||
|
||||
optWithValue := Of(42)
|
||||
optWithValue.IfNotNilOrElse(valueAction, fallbackAction)
|
||||
|
||||
assert.ShouldBeTrue(calledWithValue)
|
||||
|
||||
// Test when value is not present
|
||||
calledWithEmpty := false
|
||||
valueAction = func(value int) { t.Errorf("Value action should not be called when value is not present") }
|
||||
fallbackAction = func() { calledWithEmpty = true }
|
||||
|
||||
optDefault := Default[int]()
|
||||
optDefault.IfNotNilOrElse(valueAction, fallbackAction)
|
||||
|
||||
assert.ShouldBeTrue(calledWithEmpty)
|
||||
}
|
||||
|
||||
func TestGetWithPanicStandard(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetWithPanicStandard")
|
||||
|
||||
// Test when value is present
|
||||
optWithValue := Of(42)
|
||||
func() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
assert.IsNil(r)
|
||||
}()
|
||||
val := optWithValue.Unwarp()
|
||||
if val != 42 {
|
||||
t.Errorf("Expected Unwarp to return 42, got %v", val)
|
||||
}
|
||||
}()
|
||||
|
||||
// Test when value is not present
|
||||
optDefault := Default[int]()
|
||||
func() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
assert.IsNotNil(r)
|
||||
}()
|
||||
_ = optDefault.Unwarp()
|
||||
}()
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// ArrayQueue implements queue with slice
|
||||
type ArrayQueue[T any] struct {
|
||||
items []T
|
||||
data []T
|
||||
head int
|
||||
tail int
|
||||
capacity int
|
||||
@@ -21,7 +21,7 @@ type ArrayQueue[T any] struct {
|
||||
|
||||
func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
return &ArrayQueue[T]{
|
||||
items: make([]T, 0, capacity),
|
||||
data: make([]T, 0, capacity),
|
||||
head: 0,
|
||||
tail: 0,
|
||||
capacity: capacity,
|
||||
@@ -31,9 +31,9 @@ func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *ArrayQueue[T]) Data() []T {
|
||||
items := []T{}
|
||||
items := make([]T, 0, q.tail-q.head)
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
items = append(items, q.items[i])
|
||||
items = append(items, q.data[i])
|
||||
}
|
||||
return items
|
||||
}
|
||||
@@ -55,40 +55,71 @@ func (q *ArrayQueue[T]) IsFull() bool {
|
||||
|
||||
// Front return front value of queue
|
||||
func (q *ArrayQueue[T]) Front() T {
|
||||
return q.items[0]
|
||||
return q.data[0]
|
||||
}
|
||||
|
||||
// Back return back value of queue
|
||||
func (q *ArrayQueue[T]) Back() T {
|
||||
return q.items[q.size-1]
|
||||
return q.data[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]
|
||||
if q.tail < q.capacity {
|
||||
q.data = append(q.data, item)
|
||||
// q.tail++
|
||||
q.data[q.tail] = item
|
||||
} else {
|
||||
//upgrade
|
||||
if q.head > 0 {
|
||||
for i := 0; i < q.tail-q.head; i++ {
|
||||
q.data[i] = q.data[i+q.head]
|
||||
}
|
||||
q.tail -= q.head
|
||||
q.head = 0
|
||||
} else {
|
||||
if q.capacity < 65536 {
|
||||
if q.capacity == 0 {
|
||||
q.capacity = 1
|
||||
}
|
||||
q.capacity *= 2
|
||||
} else {
|
||||
q.capacity += 2 ^ 16
|
||||
}
|
||||
|
||||
tmp := make([]T, q.capacity, q.capacity)
|
||||
copy(tmp, q.data)
|
||||
q.data = tmp
|
||||
}
|
||||
q.tail = q.tail - q.head
|
||||
q.head = 0
|
||||
|
||||
q.data[q.tail] = item
|
||||
}
|
||||
|
||||
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 {
|
||||
if q.size == 0 {
|
||||
return item, false
|
||||
}
|
||||
item = q.items[q.head]
|
||||
|
||||
item = q.data[q.head]
|
||||
q.head++
|
||||
|
||||
if q.head >= 1024 || q.head*2 > q.tail {
|
||||
q.capacity -= q.head
|
||||
q.tail -= q.head
|
||||
tmp := make([]T, q.capacity, q.capacity)
|
||||
copy(tmp, q.data[q.head:])
|
||||
q.data = tmp
|
||||
q.head = 0
|
||||
}
|
||||
|
||||
q.size--
|
||||
return item, true
|
||||
}
|
||||
@@ -96,7 +127,7 @@ func (q *ArrayQueue[T]) Dequeue() (T, bool) {
|
||||
// Clear the queue data
|
||||
func (q *ArrayQueue[T]) Clear() {
|
||||
capacity := q.capacity
|
||||
q.items = make([]T, 0, capacity)
|
||||
q.data = make([]T, 0, capacity)
|
||||
q.head = 0
|
||||
q.tail = 0
|
||||
q.size = 0
|
||||
@@ -105,7 +136,7 @@ func (q *ArrayQueue[T]) Clear() {
|
||||
|
||||
// Contain checks if the value is in queue or not
|
||||
func (q *ArrayQueue[T]) Contain(value T) bool {
|
||||
for _, v := range q.items {
|
||||
for _, v := range q.data {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return true
|
||||
}
|
||||
@@ -117,7 +148,7 @@ func (q *ArrayQueue[T]) Contain(value T) bool {
|
||||
func (q *ArrayQueue[T]) Print() {
|
||||
info := "["
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
info += fmt.Sprintf("%+v, ", q.items[i])
|
||||
info += fmt.Sprintf("%+v, ", q.data[i])
|
||||
}
|
||||
info += "]"
|
||||
fmt.Println(info)
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestArrayQueue_Enqueue(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
|
||||
|
||||
queue := NewArrayQueue[int](5)
|
||||
queue := NewArrayQueue[int](2)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewLinkedQueue[T any]() *LinkedQueue[T] {
|
||||
|
||||
// Data return slice of queue data
|
||||
func (q *LinkedQueue[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, q.length)
|
||||
current := q.head
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -8,20 +8,20 @@ package datastructure
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
)
|
||||
|
||||
// PriorityQueue is a priority queue implemented by binary heap tree
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
// type T should implements Compare function in constraints.Comparator interface.
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.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] {
|
||||
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T] {
|
||||
return &PriorityQueue[T]{
|
||||
items: make([]T, capacity+1),
|
||||
size: 0,
|
||||
|
||||
@@ -4,19 +4,21 @@
|
||||
// Package datastructure contains some data structure. Set is a data container, like slice, but element of set is not duplicate.
|
||||
package datastructure
|
||||
|
||||
import "sort"
|
||||
|
||||
// Set is a data container, like slice, but element of set is not duplicate.
|
||||
type Set[T comparable] map[T]struct{}
|
||||
|
||||
// NewSet return a instance of set
|
||||
func NewSet[T comparable](items ...T) Set[T] {
|
||||
set := make(Set[T])
|
||||
// New create a instance of set from given values.
|
||||
func New[T comparable](items ...T) Set[T] {
|
||||
set := make(Set[T], len(items))
|
||||
set.Add(items...)
|
||||
return set
|
||||
}
|
||||
|
||||
// NewSetFromSlice create a set from slice
|
||||
func NewSetFromSlice[T comparable](items []T) Set[T] {
|
||||
set := make(Set[T])
|
||||
// FromSlice create a set from given slice.
|
||||
func FromSlice[T comparable](items []T) Set[T] {
|
||||
set := make(Set[T], len(items))
|
||||
for _, item := range items {
|
||||
set.Add(item)
|
||||
}
|
||||
@@ -77,8 +79,7 @@ func (s Set[T]) ContainAll(other Set[T]) bool {
|
||||
|
||||
// Clone return a copy of set
|
||||
func (s Set[T]) Clone() Set[T] {
|
||||
set := NewSet[T]()
|
||||
set.Add(s.Values()...)
|
||||
set := FromSlice(s.ToSlice())
|
||||
return set
|
||||
}
|
||||
|
||||
@@ -116,14 +117,11 @@ func (s Set[T]) Size() int {
|
||||
}
|
||||
|
||||
// Values return all values of set
|
||||
// Deprecated: Values function is deprecated and will be removed in future versions. Please use ToSlice() function instead.
|
||||
//
|
||||
// The ToSlice() function provides the same functionality as Values and returns a slice containing all values of the set.
|
||||
func (s Set[T]) Values() []T {
|
||||
result := make([]T, 0, len(s))
|
||||
|
||||
s.Iterate(func(value T) {
|
||||
result = append(result, value)
|
||||
})
|
||||
|
||||
return result
|
||||
return s.ToSlice()
|
||||
}
|
||||
|
||||
// Union creates a new set contain all element of set s and other
|
||||
@@ -135,7 +133,7 @@ func (s Set[T]) Union(other Set[T]) Set[T] {
|
||||
|
||||
// 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]()
|
||||
set := New[T]()
|
||||
s.Iterate(func(value T) {
|
||||
if other.Contain(value) {
|
||||
set.Add(value)
|
||||
@@ -147,7 +145,7 @@ func (s Set[T]) Intersection(other Set[T]) Set[T] {
|
||||
|
||||
// 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]()
|
||||
set := New[T]()
|
||||
s.Iterate(func(value T) {
|
||||
if !other.Contain(value) {
|
||||
set.Add(value)
|
||||
@@ -163,9 +161,9 @@ func (s Set[T]) SymmetricDifference(other Set[T]) Set[T] {
|
||||
return set
|
||||
}
|
||||
|
||||
// Minus creates an set of whose element in origin set but not in compared set
|
||||
// Minus creates a 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]()
|
||||
set := New[T]()
|
||||
|
||||
s.Iterate(func(value T) {
|
||||
if !comparedSet.Contain(value) {
|
||||
@@ -189,11 +187,34 @@ func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
|
||||
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
|
||||
func (s Set[T]) Pop() (v T, ok bool) {
|
||||
if len(s) > 0 {
|
||||
items := s.Values()
|
||||
item := items[len(s)-1]
|
||||
delete(s, item)
|
||||
return item, true
|
||||
for item := range s {
|
||||
v = item
|
||||
delete(s, item)
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
|
||||
return v, false
|
||||
}
|
||||
|
||||
// ToSlice returns a slice containing all values of the set.
|
||||
func (s Set[T]) ToSlice() []T {
|
||||
if s.IsEmpty() {
|
||||
return []T{}
|
||||
}
|
||||
result := make([]T, 0, s.Size())
|
||||
s.Iterate(func(value T) {
|
||||
result = append(result, value)
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ToSortedSlice returns a sorted slice containing all values of the set.
|
||||
func (s Set[T]) ToSortedSlice(less func(v1, v2 T) bool) []T {
|
||||
result := s.ToSlice()
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
return less(result[i], result[j])
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestSet_NewSetFromSlice(t *testing.T) {
|
||||
func TestSet_FromSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_NewSetFromSlice")
|
||||
assert := internal.NewAssert(t, "TestSet_FromSlice")
|
||||
|
||||
s1 := NewSetFromSlice([]int{1, 2, 2, 3})
|
||||
s1 := FromSlice([]int{1, 2, 2, 3})
|
||||
assert.Equal(3, s1.Size())
|
||||
assert.Equal(true, s1.Contain(1))
|
||||
assert.Equal(true, s1.Contain(2))
|
||||
assert.Equal(true, s1.Contain(3))
|
||||
|
||||
s2 := NewSetFromSlice([]int{})
|
||||
s2 := FromSlice([]int{})
|
||||
assert.Equal(0, s2.Size())
|
||||
}
|
||||
|
||||
@@ -26,10 +28,10 @@ func TestSet_Add(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Add")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
cmpSet := NewSet(1, 2, 3)
|
||||
cmpSet := New(1, 2, 3)
|
||||
|
||||
assert.Equal(true, set.Equal(cmpSet))
|
||||
}
|
||||
@@ -39,12 +41,12 @@ func TestSet_AddIfNotExist(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_AddIfNotExist")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
assert.Equal(false, set.AddIfNotExist(1))
|
||||
assert.Equal(true, set.AddIfNotExist(4))
|
||||
assert.Equal(NewSet(1, 2, 3, 4), set)
|
||||
assert.Equal(New(1, 2, 3, 4), set)
|
||||
}
|
||||
|
||||
func TestSet_AddIfNotExistBy(t *testing.T) {
|
||||
@@ -52,7 +54,7 @@ func TestSet_AddIfNotExistBy(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_AddIfNotExistBy")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
set.Add(1, 2)
|
||||
|
||||
ok := set.AddIfNotExistBy(3, func(val int) bool {
|
||||
@@ -75,7 +77,7 @@ func TestSet_Contain(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Contain")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
assert.Equal(true, set.Contain(1))
|
||||
@@ -87,9 +89,9 @@ 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)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(1, 2)
|
||||
set3 := New(1, 2, 3, 4)
|
||||
|
||||
assert.Equal(true, set1.ContainAll(set2))
|
||||
assert.Equal(false, set1.ContainAll(set3))
|
||||
@@ -100,7 +102,7 @@ func TestSet_Clone(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Clone")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := set1.Clone()
|
||||
|
||||
assert.Equal(true, set1.Size() == set2.Size())
|
||||
@@ -112,11 +114,11 @@ func TestSet_Delete(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Delete")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
set.Add(1, 2, 3)
|
||||
set.Delete(3)
|
||||
|
||||
assert.Equal(true, set.Equal(NewSet(1, 2)))
|
||||
assert.Equal(true, set.Equal(New(1, 2)))
|
||||
}
|
||||
|
||||
func TestSet_Equal(t *testing.T) {
|
||||
@@ -124,9 +126,9 @@ 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)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(1, 2, 3)
|
||||
set3 := New(1, 2, 3, 4)
|
||||
|
||||
assert.Equal(true, set1.Equal(set2))
|
||||
assert.Equal(false, set1.Equal(set3))
|
||||
@@ -137,7 +139,7 @@ func TestSet_Iterate(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Iterate")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
set := New(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
@@ -151,7 +153,7 @@ func TestSet_IsEmpty(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_IsEmpty")
|
||||
|
||||
set := NewSet[int]()
|
||||
set := New[int]()
|
||||
assert.Equal(true, set.IsEmpty())
|
||||
}
|
||||
|
||||
@@ -160,7 +162,7 @@ func TestSet_Size(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Size")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
set := New(1, 2, 3)
|
||||
assert.Equal(3, set.Size())
|
||||
}
|
||||
|
||||
@@ -169,7 +171,7 @@ func TestSet_Values(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Values")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
set := New(1, 2, 3)
|
||||
values := set.Values()
|
||||
|
||||
assert.Equal(3, len(values))
|
||||
@@ -180,12 +182,12 @@ func TestSet_Union(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Union")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(2, 3, 4, 5)
|
||||
|
||||
unionSet := set1.Union(set2)
|
||||
|
||||
assert.Equal(NewSet(1, 2, 3, 4, 5), unionSet)
|
||||
assert.Equal(New(1, 2, 3, 4, 5), unionSet)
|
||||
}
|
||||
|
||||
func TestSet_Intersection(t *testing.T) {
|
||||
@@ -193,11 +195,11 @@ func TestSet_Intersection(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_Intersection")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(2, 3, 4, 5)
|
||||
intersectionSet := set1.Intersection(set2)
|
||||
|
||||
assert.Equal(NewSet(2, 3), intersectionSet)
|
||||
assert.Equal(New(2, 3), intersectionSet)
|
||||
}
|
||||
|
||||
func TestSet_SymmetricDifference(t *testing.T) {
|
||||
@@ -205,10 +207,10 @@ func TestSet_SymmetricDifference(t *testing.T) {
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(2, 3, 4, 5)
|
||||
|
||||
assert.Equal(NewSet(1, 4, 5), set1.SymmetricDifference(set2))
|
||||
assert.Equal(New(1, 4, 5), set1.SymmetricDifference(set2))
|
||||
}
|
||||
|
||||
func TestSet_Minus(t *testing.T) {
|
||||
@@ -216,16 +218,16 @@ 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)
|
||||
set1 := New(1, 2, 3)
|
||||
set2 := New(2, 3, 4, 5)
|
||||
set3 := New(2, 3)
|
||||
|
||||
assert.Equal(NewSet(1), set1.Minus(set2))
|
||||
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
||||
assert.Equal(New(1), set1.Minus(set2))
|
||||
assert.Equal(New(4, 5), set2.Minus(set3))
|
||||
}
|
||||
|
||||
func TestEachWithBreak(t *testing.T) {
|
||||
// s := NewSet(1, 2, 3, 4, 5)
|
||||
// s := New(1, 2, 3, 4, 5)
|
||||
|
||||
// var sum int
|
||||
|
||||
@@ -241,22 +243,93 @@ func TestEachWithBreak(t *testing.T) {
|
||||
// assert.Equal(6, sum)
|
||||
}
|
||||
|
||||
// func TestPop(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestPop")
|
||||
func TestPop(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestSet_Pop")
|
||||
|
||||
// s := NewSet[int]()
|
||||
s := New[int]()
|
||||
|
||||
// val, ok := s.Pop()
|
||||
// assert.Equal(0, val)
|
||||
// assert.Equal(false, ok)
|
||||
val, ok := s.Pop()
|
||||
assert.Equal(0, val)
|
||||
assert.Equal(false, ok)
|
||||
|
||||
// s.Add(1)
|
||||
// s.Add(2)
|
||||
// s.Add(3)
|
||||
s = New(1, 2, 3, 4, 5)
|
||||
sl := s.ToSlice()
|
||||
|
||||
// // s = NewSet(1, 2, 3, 4, 5)
|
||||
val, ok = s.Pop()
|
||||
assert.Equal(false, s.Contain(val))
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(len(sl)-1, s.Size())
|
||||
|
||||
// val, ok = s.Pop()
|
||||
// assert.Equal(3, val)
|
||||
// assert.Equal(true, ok)
|
||||
// }
|
||||
var found bool
|
||||
|
||||
for _, v := range sl {
|
||||
if v == val {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
assert.Equal(true, found)
|
||||
}
|
||||
|
||||
func TestSet_ToSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_ToSlice")
|
||||
|
||||
set1 := FromSlice([]int{6, 3, 1, 5, 6, 7, 1})
|
||||
set2 := FromSlice([]float64{-2.65, 4.25, 4.25 - 3.14, 0})
|
||||
set3 := New[string]()
|
||||
|
||||
slice1 := set1.ToSlice()
|
||||
slice2 := set2.ToSlice()
|
||||
slice3 := set3.ToSlice()
|
||||
|
||||
sort.Ints(slice1)
|
||||
sort.Float64s(slice2)
|
||||
|
||||
assert.Equal(5, len(slice1))
|
||||
assert.Equal(4, len(slice2))
|
||||
assert.Equal(0, len(slice3))
|
||||
|
||||
assert.Equal(true, reflect.DeepEqual(slice1, []int{1, 3, 5, 6, 7}))
|
||||
assert.Equal(true, reflect.DeepEqual(slice2, []float64{-2.65, 0, 1.11, 4.25}))
|
||||
assert.Equal("[]string", reflect.TypeOf(slice3).String())
|
||||
}
|
||||
|
||||
func TestSet_ToSortedSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestSet_ToSortedSlice")
|
||||
|
||||
set1 := FromSlice([]int{6, 3, 1, 5, 6, 7, 1})
|
||||
set2 := FromSlice([]float64{-2.65, 4.25, 4.25 - 3.14, 0})
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
set3 := FromSlice([]Person{{"Tom", 20}, {"Jerry", 18}, {"Spike", 25}})
|
||||
|
||||
slice1 := set1.ToSortedSlice(func(v1, v2 int) bool {
|
||||
return v1 < v2
|
||||
})
|
||||
slice2 := set2.ToSortedSlice(func(v1, v2 float64) bool {
|
||||
return v2 < v1
|
||||
})
|
||||
slice3 := set3.ToSortedSlice(func(v1, v2 Person) bool {
|
||||
return v1.Age < v2.Age
|
||||
})
|
||||
|
||||
assert.Equal(5, len(slice1))
|
||||
assert.Equal(4, len(slice2))
|
||||
assert.Equal(3, len(slice3))
|
||||
|
||||
assert.Equal(true, reflect.DeepEqual(slice1, []int{1, 3, 5, 6, 7}))
|
||||
assert.Equal(true, reflect.DeepEqual(slice2, []float64{4.25, 1.11, 0, -2.65}))
|
||||
assert.Equal(true, reflect.DeepEqual(slice3, []Person{
|
||||
{"Jerry", 18},
|
||||
{"Tom", 20},
|
||||
{"Spike", 25},
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewLinkedStack[T any]() *LinkedStack[T] {
|
||||
|
||||
// Data return stack data
|
||||
func (s *LinkedStack[T]) Data() []T {
|
||||
res := []T{}
|
||||
res := make([]T, 0, s.length)
|
||||
current := s.top
|
||||
|
||||
for current != nil {
|
||||
|
||||
@@ -7,22 +7,22 @@ package datastructure
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
"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 T should implements Compare function in constraints.Comparator interface.
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.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] {
|
||||
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T] {
|
||||
root := datastructure.NewTreeNode(rootData)
|
||||
return &BSTree[T]{root, comparator}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (t *BSTree[T]) HasSubTree(subTree *BSTree[T]) bool {
|
||||
}
|
||||
|
||||
func hasSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T],
|
||||
comparator lancetconstraints.Comparator) bool {
|
||||
comparator constraints.Comparator) bool {
|
||||
result := false
|
||||
|
||||
if superTreeRoot != nil && subTreeRoot != nil {
|
||||
|
||||
@@ -100,12 +100,6 @@ func TestBSTree_Delete(t *testing.T) {
|
||||
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
|
||||
//todo
|
||||
// bstree.DeletetNode(6, comparator)
|
||||
// bstree.Print()
|
||||
// acturl2 := bstree.InOrderTraverse()
|
||||
// assert.Equal([]int{2, 5, 7}, acturl2)
|
||||
}
|
||||
|
||||
func TestBSTree_Depth(t *testing.T) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/constraints"
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
@@ -86,7 +86,7 @@ func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T)
|
||||
}
|
||||
}
|
||||
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator constraints.Comparator) {
|
||||
if comparator.Compare(newNode.Value, rootNode.Value) == -1 {
|
||||
if rootNode.Left == nil {
|
||||
rootNode.Left = newNode
|
||||
@@ -103,7 +103,7 @@ func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], compara
|
||||
}
|
||||
|
||||
// todo, delete root node failed
|
||||
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
|
||||
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator constraints.Comparator) *datastructure.TreeNode[T] {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel i
|
||||
|
||||
printSpaces(firstSpaces)
|
||||
|
||||
newNodes := []*datastructure.TreeNode[T]{}
|
||||
newNodes := make([]*datastructure.TreeNode[T], 0, len(nodes)*2)
|
||||
for _, node := range nodes {
|
||||
if node != nil {
|
||||
fmt.Printf("%v", node.Value)
|
||||
@@ -216,7 +216,7 @@ func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
|
||||
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 {
|
||||
func isSubTree[T any](superTreeRoot, subTreeRoot *datastructure.TreeNode[T], comparator constraints.Comparator) bool {
|
||||
if subTreeRoot == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// Package datetime implements some functions to format date and time.
|
||||
// Note:
|
||||
// 1. `format` param in FormatTimeToStr function should be as flow:
|
||||
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
|
||||
// "yyyy-mm-dd hh:mm:ss"
|
||||
// "yyyy-mm-dd hh:mm"
|
||||
// "yyyy-mm-dd hh"
|
||||
@@ -18,14 +18,20 @@
|
||||
// "yyyy/mm"
|
||||
// "mm/dd"
|
||||
// "dd/mm/yy hh:mm:ss"
|
||||
// "yyyymmdd"
|
||||
// "mmddyy"
|
||||
// "yyyy"
|
||||
// "yy"
|
||||
// "mm"
|
||||
// "hh:mm:ss"
|
||||
// "hh:mm"
|
||||
// "mm:ss"
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -47,9 +53,13 @@ func init() {
|
||||
"yyyy/mm": "2006/01",
|
||||
"mm/dd": "01/02",
|
||||
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
|
||||
"yyyymmdd": "20060102",
|
||||
"mmddyy": "010206",
|
||||
"yyyy": "2006",
|
||||
"yy": "06",
|
||||
"mm": "01",
|
||||
"hh:mm:ss": "15:04:05",
|
||||
"hh:mm": "15:04",
|
||||
"mm:ss": "04:05",
|
||||
}
|
||||
}
|
||||
@@ -97,13 +107,13 @@ func GetNowDateTime() string {
|
||||
}
|
||||
|
||||
// GetTodayStartTime return the start time of today, format: yyyy-mm-dd 00:00:00.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/84siyYF7t99
|
||||
func GetTodayStartTime() string {
|
||||
return time.Now().Format("2006-01-02") + " 00:00:00"
|
||||
}
|
||||
|
||||
// GetTodayEndTime return the end time of today, format: yyyy-mm-dd 23:59:59.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/jjrLnfoqgn3
|
||||
func GetTodayEndTime() string {
|
||||
return time.Now().Format("2006-01-02") + " 23:59:59"
|
||||
}
|
||||
@@ -124,19 +134,40 @@ func GetNightTimestamp() int64 {
|
||||
|
||||
// FormatTimeToStr convert time to string.
|
||||
// Play: https://go.dev/play/p/_Ia7M8H_OvE
|
||||
func FormatTimeToStr(t time.Time, format string) string {
|
||||
return t.Format(timeFormat[format])
|
||||
func FormatTimeToStr(t time.Time, format string, timezone ...string) string {
|
||||
tf, ok := timeFormat[strings.ToLower(format)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return t.In(loc).Format(tf)
|
||||
}
|
||||
return t.Format(tf)
|
||||
}
|
||||
|
||||
// FormatStrToTime convert string to time.
|
||||
// Play: https://go.dev/play/p/1h9FwdU8ql4
|
||||
func FormatStrToTime(str, format string) (time.Time, error) {
|
||||
v, ok := timeFormat[format]
|
||||
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
|
||||
tf, ok := timeFormat[strings.ToLower(format)]
|
||||
if !ok {
|
||||
return time.Time{}, fmt.Errorf("format %s not found", format)
|
||||
return time.Time{}, fmt.Errorf("format %s not support", format)
|
||||
}
|
||||
|
||||
return time.Parse(v, str)
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.ParseInLocation(tf, str, loc)
|
||||
}
|
||||
|
||||
return time.Parse(tf, str)
|
||||
}
|
||||
|
||||
// BeginOfMinute return beginning minute time of day.
|
||||
@@ -262,6 +293,200 @@ func DayOfYear(t time.Time) int {
|
||||
|
||||
// IsWeekend checks if passed time is weekend or not.
|
||||
// Play: https://go.dev/play/p/cupRM5aZOIY
|
||||
// Deprecated Use '== Weekday' instead
|
||||
func IsWeekend(t time.Time) bool {
|
||||
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
|
||||
}
|
||||
|
||||
// NowDateOrTime return current datetime with specific format and timezone.
|
||||
// Play: https://go.dev/play/p/EZ-begEjtT0
|
||||
func NowDateOrTime(format string, timezone ...string) string {
|
||||
tf, ok := timeFormat[strings.ToLower(format)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return time.Now().In(loc).Format(tf)
|
||||
}
|
||||
|
||||
return time.Now().Format(tf)
|
||||
}
|
||||
|
||||
// Timestamp return current second timestamp.
|
||||
// Play: https://go.dev/play/p/iU5b7Vvjx6x
|
||||
func Timestamp(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
t = t.In(loc)
|
||||
}
|
||||
|
||||
return t.Unix()
|
||||
}
|
||||
|
||||
// TimestampMilli return current mill second timestamp.
|
||||
// Play: https://go.dev/play/p/4gvEusOTu1T
|
||||
func TimestampMilli(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
t = t.In(loc)
|
||||
}
|
||||
|
||||
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
|
||||
// TimestampMicro return current micro second timestamp.
|
||||
// Play: https://go.dev/play/p/2maANglKHQE
|
||||
func TimestampMicro(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
t = t.In(loc)
|
||||
}
|
||||
|
||||
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
|
||||
}
|
||||
|
||||
// TimestampNano return current nano second timestamp.
|
||||
// Play: https://go.dev/play/p/A9Oq_COrcCF
|
||||
func TimestampNano(timezone ...string) int64 {
|
||||
t := time.Now()
|
||||
|
||||
if timezone != nil && timezone[0] != "" {
|
||||
loc, err := time.LoadLocation(timezone[0])
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
t = t.In(loc)
|
||||
}
|
||||
|
||||
return t.UnixNano()
|
||||
}
|
||||
|
||||
// TrackFuncTime track the time of function execution.
|
||||
// call it at top of the func like `defer TrackFuncTime(time.Now())()`
|
||||
// Play: https://go.dev/play/p/QBSEdfXHPTp
|
||||
func TrackFuncTime(pre time.Time) func() {
|
||||
callerName := getCallerName()
|
||||
return func() {
|
||||
elapsed := time.Since(pre)
|
||||
fmt.Printf("Function %s execution time:\t %v", callerName, elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
func getCallerName() string {
|
||||
pc, _, _, ok := runtime.Caller(2)
|
||||
if !ok {
|
||||
return "Unknown"
|
||||
}
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
fullName := fn.Name()
|
||||
if lastDot := strings.LastIndex(fullName, "."); lastDot != -1 {
|
||||
return fullName[lastDot+1:]
|
||||
}
|
||||
|
||||
return fullName
|
||||
}
|
||||
|
||||
// DaysBetween returns the number of days between two times.
|
||||
// Play: https://go.dev/play/p/qD6qGb3TbOy
|
||||
func DaysBetween(start, end time.Time) int {
|
||||
duration := end.Sub(start)
|
||||
days := int(duration.Hours() / 24)
|
||||
|
||||
return days
|
||||
}
|
||||
|
||||
// GenerateDatetimesBetween returns a slice of strings between two times.
|
||||
// layout: the format of the datetime string
|
||||
// interval: the interval between two datetimes
|
||||
// Play: https://go.dev/play/p/6kHBpAxD9ZC
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error) {
|
||||
var result []string
|
||||
|
||||
if start.After(end) {
|
||||
start, end = end, start
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(interval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for current := start; !current.After(end); current = current.Add(duration) {
|
||||
result = append(result, current.Format(layout))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Min returns the earliest time among the given times.
|
||||
// Play: todo
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time {
|
||||
minTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return minTime
|
||||
}
|
||||
|
||||
// Max returns the latest time among the given times.
|
||||
// Play: todo
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time {
|
||||
maxTime := t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime
|
||||
}
|
||||
|
||||
// MaxMin returns the latest and earliest time among the given times.
|
||||
// Play: todo
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time) {
|
||||
maxTime = t1
|
||||
minTime = t1
|
||||
|
||||
for _, t := range times {
|
||||
if t.Before(minTime) {
|
||||
minTime = t
|
||||
}
|
||||
|
||||
if t.After(maxTime) {
|
||||
maxTime = t
|
||||
}
|
||||
}
|
||||
|
||||
return maxTime, minTime
|
||||
}
|
||||
|
||||
@@ -408,3 +408,61 @@ func ExampleIsWeekend() {
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleDaysBetween() {
|
||||
start := time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2024, time.September, 10, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
result := DaysBetween(start, end)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 9
|
||||
}
|
||||
|
||||
func ExampleGenerateDatetimesBetween() {
|
||||
start := time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2024, time.September, 1, 2, 0, 0, 0, time.UTC)
|
||||
|
||||
layout := "2006-01-02 15:04:05"
|
||||
interval := "1h"
|
||||
|
||||
result, err := GenerateDatetimesBetween(start, end, layout, interval)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result := Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result := Max(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMaxMin() {
|
||||
max, min := MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
@@ -147,6 +147,9 @@ func TestFormatTimeToStr(t *testing.T) {
|
||||
actual := FormatTimeToStr(datetime, cases[i])
|
||||
assert.Equal(expected[i], actual)
|
||||
}
|
||||
|
||||
ds := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss", "EST")
|
||||
t.Log(ds)
|
||||
}
|
||||
|
||||
func TestFormatStrToTime(t *testing.T) {
|
||||
@@ -163,19 +166,23 @@ func TestFormatStrToTime(t *testing.T) {
|
||||
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
|
||||
"yyyy/mm"}
|
||||
|
||||
datetimeStr := []string{
|
||||
expected := []string{
|
||||
"2021-01-02 16:04:08", "2021-01-02",
|
||||
"02-01-21 16:04:08", "2021/01/02 16:04:08",
|
||||
"2021/01"}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
|
||||
actual, err := FormatStrToTime(expected[i], cases[i])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected, _ := time.Parse(formats[i], datetimeStr[i])
|
||||
expected, _ := time.Parse(formats[i], expected[i])
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
estTime, err := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss", "EST")
|
||||
t.Log(estTime)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
func TestBeginOfMinute(t *testing.T) {
|
||||
@@ -368,3 +375,206 @@ func TestIsWeekend(t *testing.T) {
|
||||
result2 := IsWeekend(date2)
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
func TestNowDateOrTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
formats := []string{
|
||||
"yyyy-mm-dd hh:mm:ss",
|
||||
"yyyy-mm-dd",
|
||||
"dd-mm-yy hh:mm:ss",
|
||||
"yyyy/mm/dd hh:mm:ss",
|
||||
"hh:mm:ss",
|
||||
"yyyy/mm",
|
||||
"yyyy-mm-dd hh",
|
||||
}
|
||||
|
||||
for i := 0; i < len(formats); i++ {
|
||||
result := NowDateOrTime(formats[i], "UTC")
|
||||
t.Log(result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ts1 := Timestamp()
|
||||
t.Log(ts1)
|
||||
|
||||
ts2 := TimestampMilli()
|
||||
t.Log(ts2)
|
||||
|
||||
ts3 := TimestampMicro()
|
||||
t.Log(ts3)
|
||||
|
||||
ts4 := TimestampNano()
|
||||
t.Log(ts4)
|
||||
}
|
||||
|
||||
func TestTrackFuncTime(t *testing.T) {
|
||||
defer TrackFuncTime(time.Now())()
|
||||
|
||||
var n int
|
||||
for i := 0; i < 5000000; i++ {
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaysBetween(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestDaysBetween")
|
||||
|
||||
tests := []struct {
|
||||
start time.Time
|
||||
end time.Time
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
start: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 10, 0, 0, 0, 0, time.UTC),
|
||||
expected: 9,
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.September, 10, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
expected: -9,
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.December, 31, 0, 0, 0, 0, time.UTC),
|
||||
expected: 365,
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.March, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.March, 31, 0, 0, 0, 0, time.UTC),
|
||||
expected: 30,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := DaysBetween(tt.start, tt.end)
|
||||
assert.Equal(tt.expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateDatetimesBetween(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestGenerateDatetimesBetween")
|
||||
|
||||
tests := []struct {
|
||||
start time.Time
|
||||
end time.Time
|
||||
layout string
|
||||
interval string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
start: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 1, 2, 0, 0, 0, time.UTC),
|
||||
layout: "2006-01-02 15:04:05",
|
||||
interval: "30m",
|
||||
expected: []string{
|
||||
"2024-09-01 00:00:00",
|
||||
"2024-09-01 00:30:00",
|
||||
"2024-09-01 01:00:00",
|
||||
"2024-09-01 01:30:00",
|
||||
"2024-09-01 02:00:00",
|
||||
},
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
layout: "2006-01-02 15:04:05",
|
||||
interval: "1h",
|
||||
expected: []string{"2024-09-01 00:00:00"},
|
||||
},
|
||||
{
|
||||
start: time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC),
|
||||
end: time.Date(2024, time.September, 1, 3, 0, 0, 0, time.UTC),
|
||||
layout: "2006-01-02 15:04:05",
|
||||
interval: "2h",
|
||||
expected: []string{
|
||||
"2024-09-01 00:00:00",
|
||||
"2024-09-01 02:00:00",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result, err := GenerateDatetimesBetween(tt.start, tt.end, tt.layout, tt.interval)
|
||||
|
||||
assert.Equal(tt.expected, result)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
t.Run("Invalid interval", func(t *testing.T) {
|
||||
_, err := GenerateDatetimesBetween(time.Now(), time.Now(), "2006-01-02 15:04:05", "invalid")
|
||||
if err == nil {
|
||||
t.Fatal("Expected error, got nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(zeroTime, Min(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(zeroTime, Min(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAgo, Min(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(zeroTime, now, oneMinuteAgo, oneMinuteAfter))
|
||||
|
||||
assert.Equal(now, Max(now, zeroTime))
|
||||
|
||||
assert.Equal(oneMinuteAfter, Max(oneMinuteAgo, now, oneMinuteAfter))
|
||||
}
|
||||
|
||||
func TestMaxMin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestMinMax")
|
||||
|
||||
zeroTime := time.Time{}
|
||||
now := time.Now()
|
||||
oneMinuteAgo := now.Add(-time.Minute)
|
||||
oneMinuteAfter := now.Add(time.Minute)
|
||||
|
||||
max, min := MaxMin(zeroTime, now, oneMinuteAgo, oneMinuteAfter)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
|
||||
max, min = MaxMin(now, zeroTime)
|
||||
assert.Equal(zeroTime, min)
|
||||
assert.Equal(now, max)
|
||||
|
||||
max, min = MaxMin(oneMinuteAgo, now, oneMinuteAfter)
|
||||
assert.Equal(oneMinuteAgo, min)
|
||||
assert.Equal(oneMinuteAfter, max)
|
||||
}
|
||||
|
||||
90
docs/.vitepress/common.ts
Normal file
90
docs/.vitepress/common.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { defineConfig, HeadConfig } from 'vitepress'
|
||||
|
||||
export const META_IMAGE = '/lancet_logo.png'
|
||||
export const isProduction = process.env.NETLIFY && process.env.CONTEXT === 'production'
|
||||
|
||||
if (process.env.NETLIFY) {
|
||||
console.log('Netlify build', process.env.CONTEXT)
|
||||
}
|
||||
|
||||
const productionHead: HeadConfig[] = [
|
||||
[
|
||||
'script',
|
||||
{
|
||||
src: 'https://unpkg.com/thesemetrics@latest',
|
||||
async: '',
|
||||
type: 'text/javascript',
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
const rControl = /[\u0000-\u001f]/g
|
||||
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g
|
||||
const rCombining = /[\u0300-\u036F]/g
|
||||
|
||||
/**
|
||||
* Default slugification function
|
||||
*/
|
||||
export const slugify = (str: string): string =>
|
||||
str
|
||||
.normalize('NFKD')
|
||||
// Remove accents
|
||||
.replace(rCombining, '')
|
||||
// Remove control characters
|
||||
.replace(rControl, '')
|
||||
// Replace special characters
|
||||
.replace(rSpecial, '-')
|
||||
// ensure it doesn't start with a number
|
||||
.replace(/^(\d)/, '_$1')
|
||||
|
||||
export const commonConfig = defineConfig({
|
||||
title: 'Lancet',
|
||||
appearance: true,
|
||||
ignoreDeadLinks: true,
|
||||
|
||||
markdown: {
|
||||
theme: {
|
||||
dark: 'dracula-soft',
|
||||
light: 'vitesse-light',
|
||||
},
|
||||
|
||||
attrs: {
|
||||
leftDelimiter: '%{',
|
||||
rightDelimiter: '}%',
|
||||
},
|
||||
|
||||
anchor: {
|
||||
slugify,
|
||||
},
|
||||
},
|
||||
|
||||
head: [
|
||||
// ['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
|
||||
['link', { rel: 'icon', type: 'image/png', href: '/lancet_logo_mini.png' }],
|
||||
['meta', { name: 'theme-color', content: '#5f67ee' }],
|
||||
['meta', { name: 'og:type', content: 'website' }],
|
||||
['meta', { name: 'og:locale', content: 'zh' }],
|
||||
|
||||
...(isProduction ? productionHead : []),
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
logo: { src: '/lancet_logo_mini.png', width: 24, height: 24 },
|
||||
outline: [2, 3],
|
||||
|
||||
search: {
|
||||
provider: 'local',
|
||||
},
|
||||
socialLinks: [
|
||||
{
|
||||
icon: 'github',
|
||||
link: 'https://github.com/duke-git/lancet',
|
||||
},
|
||||
],
|
||||
|
||||
footer: {
|
||||
copyright: 'Copyright © 2023-present Duke Du',
|
||||
message: '<a href="https://beian.miit.gov.cn/" target="_blank">京ICP备2023022770号-1</a>',
|
||||
},
|
||||
},
|
||||
})
|
||||
14
docs/.vitepress/config.mts
Normal file
14
docs/.vitepress/config.mts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { commonConfig } from './common'
|
||||
import { zhConfig } from './zh'
|
||||
import { enConfig } from './en'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
...commonConfig,
|
||||
|
||||
locales: {
|
||||
root: { label: '简体中文', lang: 'zh-CN', link: '/', ...zhConfig },
|
||||
en: { label: 'English', lang: 'en-US', link: '/en/', ...enConfig },
|
||||
},
|
||||
})
|
||||
139
docs/.vitepress/en.ts
Normal file
139
docs/.vitepress/en.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
|
||||
|
||||
export const META_URL = 'https://www.golancet.cn/en/'
|
||||
export const META_TITLE = 'Lancet'
|
||||
export const META_DESCRIPTION = 'A powerful util function library of Go'
|
||||
|
||||
export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
description: META_DESCRIPTION,
|
||||
|
||||
head: [
|
||||
['meta', { property: 'og:url', content: META_URL }],
|
||||
['meta', { property: 'og:description', content: META_DESCRIPTION }],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
editLink: {
|
||||
pattern: 'https://github.com/duke-git/lancet/edit/v2/docs/:path',
|
||||
text: 'Suggest changes to this page',
|
||||
},
|
||||
nav: [
|
||||
{
|
||||
text: 'Home',
|
||||
link: '/en/',
|
||||
activeMatch: '^/en/',
|
||||
},
|
||||
{
|
||||
text: 'Guide',
|
||||
link: '/en/guide/introduction',
|
||||
activeMatch: '^/en/guide/',
|
||||
},
|
||||
{ text: 'API', link: '/en/api/overview', activeMatch: '^/en/api/' },
|
||||
{
|
||||
text: 'Links',
|
||||
items: [
|
||||
{
|
||||
text: 'Discussion',
|
||||
link: 'https://github.com/duke-git/lancet/discussions',
|
||||
},
|
||||
{
|
||||
text: 'Changelog',
|
||||
link: 'https://github.com/duke-git/lancet/releases',
|
||||
},
|
||||
{
|
||||
text: 'Contribution',
|
||||
link: 'https://github.com/duke-git/lancet/blob/main/CONTRIBUTION.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
'/en/guide/': [
|
||||
{
|
||||
text: 'Introduction',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: 'What is Lancet?',
|
||||
link: '/en/guide/introduction',
|
||||
},
|
||||
{
|
||||
text: 'Getting started',
|
||||
link: '/en/guide/getting_started',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Contribute Code',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: 'Contribution guide',
|
||||
link: '/en/guide/contribution_guide',
|
||||
},
|
||||
{
|
||||
text: 'Contributors',
|
||||
link: '/en/guide/contributors',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'API Reference',
|
||||
link: '/en/api/overview'
|
||||
},
|
||||
],
|
||||
'/en/api/': [
|
||||
{
|
||||
text: 'Overview',
|
||||
items: [{ text: 'API overview', link: '/en/api/overview' }],
|
||||
},
|
||||
{
|
||||
text: 'Packages',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'algorithm', link: '/en/api/packages/algorithm' },
|
||||
{ text: 'compare', link: '/en/api/packages/compare' },
|
||||
{ text: 'concurrency', link: '/en/api/packages/concurrency' },
|
||||
{ text: 'condition', link: '/en/api/packages/condition' },
|
||||
{ text: 'convertor', link: '/en/api/packages/convertor' },
|
||||
{ text: 'cryptor', link: '/en/api/packages/cryptor' },
|
||||
{
|
||||
text: 'datastructure',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'list', link: '/en/api/packages/datastructure/list' },
|
||||
{ text: 'safelist', link: '/en/api/packages/datastructure/copyonwritelist' },
|
||||
{ text: 'link', link: '/en/api/packages/datastructure/link' },
|
||||
{ text: 'stack', link: '/en/api/packages/datastructure/stack' },
|
||||
{ text: 'queue', link: '/en/api/packages/datastructure/queue' },
|
||||
{ text: 'heap', link: '/en/api/packages/datastructure/heap' },
|
||||
{ text: 'tree', link: '/en/api/packages/datastructure/tree' },
|
||||
{ text: 'set', link: '/en/api/packages/datastructure/set' },
|
||||
{ text: 'hashmap', link: '/en/api/packages/datastructure/hashmap' },
|
||||
],
|
||||
},
|
||||
{ text: 'datetime', link: '/en/api/packages/datetime' },
|
||||
{ text: 'fileutil', link: '/en/api/packages/fileutil' },
|
||||
{ text: 'formatter', link: '/en/api/packages/formatter' },
|
||||
{ text: 'function', link: '/en/api/packages/function' },
|
||||
{ text: 'mathutil', link: '/en/api/packages/mathutil' },
|
||||
{ text: 'maputil', link: '/en/api/packages/maputil' },
|
||||
{ text: 'netutil', link: '/en/api/packages/netutil' },
|
||||
{ text: 'pointer', link: '/en/api/packages/pointer' },
|
||||
{ text: 'random', link: '/en/api/packages/random' },
|
||||
{ text: 'retry', link: '/en/api/packages/retry' },
|
||||
{ text: 'slice', link: '/en/api/packages/slice' },
|
||||
{ text: 'stream', link: '/en/api/packages/stream' },
|
||||
{ text: 'struct', link: '/en/api/packages/struct' },
|
||||
{ text: 'strutil', link: '/en/api/packages/strutil' },
|
||||
{ text: 'system', link: '/en/api/packages/system' },
|
||||
{ text: 'tuple', link: '/en/api/packages/tuple' },
|
||||
{ text: 'validator', link: '/en/api/packages/validator' },
|
||||
{ text: 'xerror', link: '/en/api/packages/xerror' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
152
docs/.vitepress/zh.ts
Normal file
152
docs/.vitepress/zh.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress'
|
||||
|
||||
export const META_URL = 'https://www.golancet.cn'
|
||||
export const META_TITLE = 'Lancet'
|
||||
export const META_DESCRIPTION = '一个强大的Go语言工具函数库'
|
||||
|
||||
export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
description: META_DESCRIPTION,
|
||||
|
||||
head: [
|
||||
['meta', { property: 'og:url', content: META_URL }],
|
||||
['meta', { property: 'og:description', content: META_DESCRIPTION }],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
editLink: {
|
||||
pattern: 'https://github.com/duke-git/lancet/edit/v2/docs/:path',
|
||||
text: '对本页提出修改建议',
|
||||
},
|
||||
outline: {
|
||||
label: '本页内容',
|
||||
},
|
||||
|
||||
docFooter: {
|
||||
prev: '上一页',
|
||||
next: '下一页',
|
||||
},
|
||||
|
||||
nav: [
|
||||
{
|
||||
text: '首页',
|
||||
link: '/',
|
||||
activeMatch: '^/',
|
||||
},
|
||||
{
|
||||
text: '指南',
|
||||
link: '/guide/introduction',
|
||||
activeMatch: '^/guide/',
|
||||
},
|
||||
{ text: 'API', link: '/api/overview', activeMatch: '^/api/' },
|
||||
{
|
||||
text: '相关链接',
|
||||
items: [
|
||||
{
|
||||
text: '论坛',
|
||||
link: 'https://github.com/duke-git/lancet/discussions',
|
||||
},
|
||||
{
|
||||
text: '更新日志',
|
||||
link: 'https://github.com/duke-git/lancet/releases',
|
||||
},
|
||||
{
|
||||
text: '参与贡献',
|
||||
link: 'https://github.com/duke-git/lancet/blob/main/CONTRIBUTION.zh-CN.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{
|
||||
text: '介绍',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: 'Lancet是什么?',
|
||||
link: '/guide/introduction',
|
||||
},
|
||||
{
|
||||
text: '开始',
|
||||
link: '/guide/getting_started',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '贡献代码',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '贡献指南',
|
||||
link: '/guide/contribution_guide',
|
||||
},
|
||||
{
|
||||
text: '贡献者',
|
||||
link: '/guide/contributors',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'API手册',
|
||||
link: '/api/overview'
|
||||
},
|
||||
],
|
||||
|
||||
'/api/': [
|
||||
{
|
||||
text: '概览',
|
||||
items: [{ text: 'API概述', link: '/api/overview' }],
|
||||
},
|
||||
{
|
||||
text: 'API文档',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '算法', link: '/api/packages/algorithm' },
|
||||
{ text: '比较器', link: '/api/packages/compare' },
|
||||
{ text: '并发处理', link: '/api/packages/concurrency' },
|
||||
{ text: '条件判断', link: '/api/packages/condition' },
|
||||
{ text: '类型转换', link: '/api/packages/convertor' },
|
||||
{ text: '加密&解密', link: '/api/packages/cryptor' },
|
||||
{
|
||||
text: '数据结构',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: '线性表', link: '/api/packages/datastructure/list' },
|
||||
{
|
||||
text: '线性表(线程安全)',
|
||||
link: '/api/packages/datastructure/copyonwritelist',
|
||||
},
|
||||
{ text: '链表', link: '/api/packages/datastructure/link' },
|
||||
{ text: '栈', link: '/api/packages/datastructure/stack' },
|
||||
{ text: '队列', link: '/api/packages/datastructure/queue' },
|
||||
{ text: '堆', link: '/api/packages/datastructure/heap' },
|
||||
{ text: '树', link: '/api/packages/datastructure/tree' },
|
||||
{ text: '集合', link: '/api/packages/datastructure/set' },
|
||||
{ text: 'HashMap', link: '/api/packages/datastructure/hashmap' },
|
||||
],
|
||||
},
|
||||
{ text: '日期&时间', link: '/api/packages/datetime' },
|
||||
{ text: '文件', link: '/api/packages/fileutil' },
|
||||
{ text: '格式化工具', link: '/api/packages/formatter' },
|
||||
{ text: '函数', link: '/api/packages/function' },
|
||||
{ text: '数学工具', link: '/api/packages/mathutil' },
|
||||
{ text: 'Map', link: '/api/packages/maputil' },
|
||||
{ text: '网络', link: '/api/packages/netutil' },
|
||||
{ text: '指针', link: '/api/packages/pointer' },
|
||||
{ text: '随机数', link: '/api/packages/random' },
|
||||
{ text: '重试', link: '/api/packages/retry' },
|
||||
{ text: '切片', link: '/api/packages/slice' },
|
||||
{ text: '流', link: '/api/packages/stream' },
|
||||
{ text: '结构体', link: '/api/packages/struct' },
|
||||
{ text: '字符串', link: '/api/packages/strutil' },
|
||||
{ text: '系统', link: '/api/packages/system' },
|
||||
{ text: '元组', link: '/api/packages/tuple' },
|
||||
{ text: '验证器', link: '/api/packages/validator' },
|
||||
{ text: '错误处理', link: '/api/packages/xerror' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
69
docs/api/overview.md
Normal file
69
docs/api/overview.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# API概述
|
||||
|
||||
<b>lancet(柳叶刀)是一个功能强大、全面、高效、可复用的go语言工具函数库。包含25个包,超过600个工具函数。功能涵盖字符串处理、切片处理、网络、并发、加解密、文件处理、时间/日期、流处理、迭代器等等。</b>
|
||||
|
||||
|
||||
<style>
|
||||
.package-title {
|
||||
color: black;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.package-container {
|
||||
font-size: 16px;
|
||||
border: 1px dashed;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.package-cell {
|
||||
height: 40px;
|
||||
width: 140px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 40px;
|
||||
background: #10b981;
|
||||
border: 1px solid;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<p class="package-title">lancet功能模块</p>
|
||||
<div class="package-container">
|
||||
<div class="package-cell">algorithm</div>
|
||||
<div class="package-cell">compare</div>
|
||||
<div class="package-cell">concurrency</div>
|
||||
<div class="package-cell">condition</div>
|
||||
<div class="package-cell">convertor</div>
|
||||
<div class="package-cell">cryptor</div>
|
||||
<div class="package-cell">datastructure</div>
|
||||
<div class="package-cell">datetime</div>
|
||||
<div class="package-cell">fileutil</div>
|
||||
<div class="package-cell">formatter</div>
|
||||
<div class="package-cell">function</div>
|
||||
<div class="package-cell">iterator</div>
|
||||
<div class="package-cell">maputil</div>
|
||||
<div class="package-cell">mathutil</div>
|
||||
<div class="package-cell">netutil</div>
|
||||
<div class="package-cell">pointer</div>
|
||||
<div class="package-cell">random</div>
|
||||
<div class="package-cell">retry</div>
|
||||
<div class="package-cell">slice</div>
|
||||
<div class="package-cell">stream</div>
|
||||
<div class="package-cell">structs</div>
|
||||
<div class="package-cell">strutil</div>
|
||||
<div class="package-cell">system</div>
|
||||
<div class="package-cell">tuple</div>
|
||||
<div class="package-cell">validator</div>
|
||||
<div class="package-cell">xerror</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,15 +43,15 @@ import (
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
|
||||
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>冒泡排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -91,15 +91,15 @@ func main() {
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
|
||||
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>插入排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -117,7 +117,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
@@ -154,15 +154,15 @@ func main() {
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
|
||||
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>选择排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/oXovbkekayS)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -202,15 +202,15 @@ func main() {
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
|
||||
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>希尔排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/3ibkszpJEu3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -250,15 +250,15 @@ func main() {
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
|
||||
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>快速排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
func QuickSort[T any](slice []T comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -298,15 +298,15 @@ func main() {
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
|
||||
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>堆排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -346,15 +346,15 @@ func main() {
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
|
||||
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>归并排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ydinn9YzUJn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -394,15 +394,15 @@ func main() {
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
|
||||
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>计数排序,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -443,15 +443,15 @@ func main() {
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/t6MeGiUSN47)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -494,15 +494,15 @@ func main() {
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包constraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -553,7 +553,7 @@ func main() {
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/IsS7rgn5s3x)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -596,7 +596,7 @@ func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/-EZjgOURufP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -30,10 +30,12 @@ import (
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
- [InDelta](#InDelta)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
## 文档
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
|
||||
@@ -45,7 +47,7 @@ import (
|
||||
func Equal(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wmVxR-to4lz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -94,7 +96,7 @@ func main() {
|
||||
func EqualValue(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fxnna_LLD9u)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -133,7 +135,7 @@ func main() {
|
||||
func LessThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cYh7FQQj0ne)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -182,7 +184,7 @@ func main() {
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9-NYDFZmIMp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -234,7 +236,7 @@ func main() {
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/e4T_scwoQzp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -283,7 +285,7 @@ func main() {
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/vx8mP0U8DFk)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -324,3 +326,50 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="InDelta">InDelta</span>
|
||||
|
||||
<p>检查增量内两个值是否相等。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
|
||||
```
|
||||
|
||||
<b>示例: <span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TuDdcNtMkjo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := InDelta(1, 1, 0)
|
||||
result2 := InDelta(1, 2, 0)
|
||||
|
||||
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
|
||||
result4 := InDelta(2.0/3.0, 0.0, 0.001)
|
||||
|
||||
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
|
||||
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -1,15 +1,17 @@
|
||||
# Concurrency
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
|
||||
|
||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel 等。
|
||||
|
||||
<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)
|
||||
- [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"
|
||||
@@ -19,25 +21,28 @@ import (
|
||||
<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)
|
||||
|
||||
- [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>
|
||||
@@ -46,7 +51,8 @@ import (
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -70,7 +76,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -122,7 +129,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2VYFMexEvTm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -161,7 +169,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -199,7 +208,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/k5N_ALVmYjE)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -238,7 +248,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4J1zAWttP85)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -279,7 +290,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Wqz9rwioPww)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -322,7 +334,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/lm_GoS6aDjo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -360,7 +373,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9Utt-1pDr2J)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -406,7 +420,8 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/3TQPKnCirrP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -436,4 +451,4 @@ func main() {
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
## 目录
|
||||
|
||||
- [Bool](#Bool)
|
||||
- [And](#And)
|
||||
@@ -27,11 +27,12 @@ import (
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
- [Ternary](#Ternary)
|
||||
- [TernaryOperator<sup>deprecated</sup>](#TernaryOperator)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
## 文档
|
||||
|
||||
### <span id="Bool">Bool</span>
|
||||
<p>返回传入参数的bool值.<br/>
|
||||
@@ -45,7 +46,7 @@ slices和map的length大于0时,返回true,否则返回false<br/>
|
||||
```go
|
||||
func Bool[T any](value T) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ETzeDJRSvhm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -109,7 +110,7 @@ func main() {
|
||||
```go
|
||||
func And[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/W1SSUmt6pvr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -135,7 +136,7 @@ func main() {
|
||||
```go
|
||||
func Or[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UlQTxHaeEkq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -161,7 +162,7 @@ func main() {
|
||||
```go
|
||||
func Xor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gObZrW7ZbG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -187,7 +188,7 @@ func main() {
|
||||
```go
|
||||
func Nor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/g2j08F_zZky)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -213,7 +214,7 @@ func main() {
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OuDB9g51643)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -239,7 +240,7 @@ func main() {
|
||||
```go
|
||||
func Nand[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/vSRMLxLIbq8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -257,15 +258,51 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Ternary">Ternary</span>
|
||||
<p>三元运算符。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Ternary[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.Ternary(conditionTrue, 0, 1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.Ternary(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>三元运算符</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`Ternary`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
|
||||
```
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ElllPZY0guT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -43,6 +43,11 @@ import (
|
||||
- [ToInterface](#ToInterface)
|
||||
- [Utf8ToGbk](#Utf8ToGbk)
|
||||
- [GbkToUtf8](#GbkToUtf8)
|
||||
- [ToStdBase64](#ToStdBase64)
|
||||
- [ToUrlBase64](#ToUrlBase64)
|
||||
- [ToRawStdBase64](#ToRawStdBase64)
|
||||
- [ToRawUrlBase64](#ToRawUrlBase64)
|
||||
- [ToBigInt](#ToBigInt)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -58,7 +63,7 @@ import (
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/o7_ft-JCJBV)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -89,7 +94,7 @@ func main() {
|
||||
func ColorRGBToHex(red, green, blue int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nzKS2Ro87J1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -122,7 +127,7 @@ func main() {
|
||||
func ToBool(s string) (bool, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ARht2WnGdIN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -163,7 +168,7 @@ func main() {
|
||||
func ToBytes(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fAMXYFDvOvr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -196,7 +201,7 @@ func main() {
|
||||
func ToChar(s string) []string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JJ1SvbFkVdM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -232,7 +237,7 @@ func main() {
|
||||
func ToChannel[T any](array []T) <-chan T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/hOx_oYZbAnL)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -269,7 +274,7 @@ func main() {
|
||||
func ToFloat(value any) (float64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4YTmPCibqHJ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -314,7 +319,7 @@ func main() {
|
||||
func ToInt(value any) (int64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9_h9vIt-QZ_b)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -356,7 +361,7 @@ func main() {
|
||||
func ToJson(value any) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2rLIkMmXWvR)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -391,7 +396,7 @@ func main() {
|
||||
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tVFy7E-t24l)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -432,7 +437,7 @@ func main() {
|
||||
func ToPointer[T any](value T) *T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ASf_etHNlw1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -461,7 +466,7 @@ func main() {
|
||||
func ToString(value any) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nF1zOOslpQq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -509,7 +514,7 @@ func main() {
|
||||
func StructToMap(value any) (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/KYGYJqNUBOI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -547,7 +552,7 @@ func main() {
|
||||
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dmX4Ix5V6Wl)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -577,7 +582,7 @@ func main() {
|
||||
func EncodeByte(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/DVmM1G5JfuP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -606,7 +611,7 @@ func main() {
|
||||
func DecodeByte(data []byte, target any) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zI6xsmuQRbn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -642,7 +647,7 @@ func main() {
|
||||
func DeepClone[T any](src T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/j4DP5dquxnk)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -706,7 +711,7 @@ func main() {
|
||||
func CopyProperties[T, U any](dst T, src U) (err error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/oZujoB5Sgg5)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -785,7 +790,7 @@ func main() {
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/syqw0-WG7Xd)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -820,7 +825,7 @@ func main() {
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9FlIaFLArIL)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -854,7 +859,7 @@ func main() {
|
||||
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OphmHCN_9u8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -876,3 +881,302 @@ func main() {
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToStdBase64">ToStdBase64</span>
|
||||
|
||||
<p>将值转换为StdBase64编码的字符串。error类型的数据也会把error的原因进行编码,复杂的结构会转为JSON格式的字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToStdBase64(value any) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_fLJqJD3NMo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
afterEncode := convertor.ToStdBase64(nil)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
afterEncode = convertor.ToStdBase64("")
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode = convertor.ToStdBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = convertor.ToStdBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = convertor.ToStdBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = convertor.ToStdBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = convertor.ToStdBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = convertor.ToStdBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
//
|
||||
//
|
||||
// aGVsbG8=
|
||||
// aGVsbG8=
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||
// MTIzLjQ1Ng==
|
||||
// dHJ1ZQ==
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### <span id="ToUrlBase64">ToUrlBase64</span>
|
||||
|
||||
<p>值转换为 ToUrlBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToUrlBase64(value any) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/C_d0GlvEeUR)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
afterEncode := convertor.ToUrlBase64(nil)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode = convertor.ToUrlBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = convertor.ToUrlBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = convertor.ToUrlBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = convertor.ToUrlBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = convertor.ToUrlBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = convertor.ToUrlBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
//
|
||||
// aGVsbG8=
|
||||
// aGVsbG8=
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||
// MTIzLjQ1Ng==
|
||||
// dHJ1ZQ==
|
||||
// ZXJy
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### <span id="ToRawStdBase64">ToRawStdBase64</span>
|
||||
|
||||
<p>值转换为 ToRawStdBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToRawStdBase64(value any) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wSAr3sfkDcv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode = convertor.ToRawStdBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = convertor.ToRawStdBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = convertor.ToRawStdBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode := convertor.ToRawStdBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8
|
||||
// aGVsbG8
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||
// MTIzLjQ1Ng
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToRawUrlBase64">ToRawUrlBase64</span>
|
||||
|
||||
<p>值转换为 ToRawUrlBase64 编码的字符串。error 类型的数据也会把 error 的原因进行编码,复杂的结构会转为 JSON 格式的字符串</p>
|
||||
|
||||
<b>函数签名:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HwdDPFcza1O)</span></b>
|
||||
|
||||
```go
|
||||
func ToRawUrlBase64(value any) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
stringVal := "hello"
|
||||
afterEncode := convertor.ToRawUrlBase64(stringVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
byteSliceVal := []byte("hello")
|
||||
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
intVal := 123
|
||||
afterEncode = convertor.ToRawUrlBase64(intVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||
A string
|
||||
B int
|
||||
}{"hello", 3}}
|
||||
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
floatVal := 123.456
|
||||
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
boolVal := true
|
||||
afterEncode = convertor.ToRawUrlBase64(boolVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
errVal := errors.New("err")
|
||||
afterEncode = convertor.ToRawUrlBase64(errVal)
|
||||
fmt.Println(afterEncode)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8
|
||||
// aGVsbG8
|
||||
// MTIz
|
||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||
// MTIzLjQ1Ng
|
||||
// dHJ1ZQ
|
||||
// ZXJy
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToBigInt">ToBigInt</span>
|
||||
|
||||
<p>将整数值转换为bigInt。</p>
|
||||
|
||||
<b>函数签名:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
func ToBigInt[T any](v T) (*big.Int, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
n := 9876543210
|
||||
bigInt, _ := convertor.ToBigInt(n)
|
||||
|
||||
fmt.Println(bigInt)
|
||||
// Output:
|
||||
// 9876543210
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
525
docs/api/packages/datastructure/copyonwritelist.md
Normal file
525
docs/api/packages/datastructure/copyonwritelist.md
Normal file
@@ -0,0 +1,525 @@
|
||||
# CopyOnWriteList
|
||||
|
||||
CopyOnWriteList 是一个线程安全的 List 实现,底层使用 go 切片。写入时,会复制一份新的切片,写入完成后,再将新的切片赋值给原来的切片。读取时,直接读取原来的切片。
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go](https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go)
|
||||
|
||||
## 用法
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [NewCopyOnWriteList](#NewCopyOnWriteList)
|
||||
- [Size](#Size)
|
||||
- [Get](#Get)
|
||||
- [Set](#Set)
|
||||
- [Remove](#Remove)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
- [IndexOfFunc](#IndexOfFunc)
|
||||
- [LastIndexOfFunc](#LastIndexOfFunc)
|
||||
- [IsEmpty](#IsEmpty)
|
||||
- [Contain](#Contain)
|
||||
- [ValueOf](#ValueOf)
|
||||
- [Add](#Add)
|
||||
- [AddAll](#AddAll)
|
||||
- [AddByIndex](#AddByIndex)
|
||||
- [DeleteAt](#DeleteAt)
|
||||
- [DeleteIf](#DeleteIf)
|
||||
- [DeleteBy](#DeleteBy)
|
||||
- [DeleteRange](#DeleteRange)
|
||||
- [Equal](#Equal)
|
||||
|
||||
## 文档
|
||||
|
||||
### NewCopyOnWriteList
|
||||
|
||||
返回一个具有空切片的 CopyOnWriteList。
|
||||
|
||||
```go
|
||||
type CopyOnWriteList[T any] struct {
|
||||
data []T
|
||||
lock sync.Locker
|
||||
}
|
||||
|
||||
func NewCopyOnWriteList() *CopyOnWriteList
|
||||
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
返回 CopyOnWriteList 的长度。
|
||||
|
||||
```go
|
||||
func (l *CopyOnWriteList[T]) Size() int
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.Size())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Get
|
||||
|
||||
返回列表中指定位置的元素
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Get(index int) *T
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.Get(2))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Set
|
||||
|
||||
将此列表中指定位置的元素替换为指定元素。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.Set(2, 4))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Remove
|
||||
|
||||
### IndexOf
|
||||
|
||||
返回列表中值的索引,如果没有找到返回-1。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) IndexOf(e T) int
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.IndexOf(1))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### LastIndexOf
|
||||
|
||||
返回指定元素在此列表中最后出现的索引,如果此列表不包含该元素,则返回-1。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3,1})
|
||||
fmt.Println(l.LastIndexOf(1))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### <span id="IndexOfFunc">IndexOfFunc</span>
|
||||
<p>返回第一个满足判断函数f(v)的元素的索引,如果找不到则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *CopyOnWriteList[T]) IndexOfFunc(f func(T) bool) int
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(l.IndexOfFunc(func(a int) bool { return a == 1 })) //0
|
||||
fmt.Println(l.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
|
||||
<p>返回最后一个满足判断函数f(v)的元素的索引,如果找不到则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (l *CopyOnWriteList[T]) LastIndexOfFunc(f func(T) bool) int
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1, 2, 3, 1})
|
||||
|
||||
fmt.Println(l.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
|
||||
fmt.Println(l.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
|
||||
}
|
||||
```
|
||||
|
||||
### IsEmpty
|
||||
|
||||
如果此列表不包含任何元素,则返回 true。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) IsEmpty() bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{})
|
||||
fmt.Println(l.IsEmpty())
|
||||
}
|
||||
```
|
||||
|
||||
### Contain
|
||||
|
||||
判断 CopyOnWriteList 是否包含某个元素
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Contain(e T) bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.Contain(1))
|
||||
}
|
||||
```
|
||||
|
||||
### ValueOf
|
||||
|
||||
返回列表中索引处的值指针
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) ValueOf(index int) []T
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
fmt.Println(l.ValueOf(2))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Add
|
||||
|
||||
将指定的元素追加到此列表的末尾。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Add(e T) bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
l.Add(4)
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### AddAll
|
||||
|
||||
将指定集合中的所有元素追加到此列表的末尾
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) AddAll(e []T) bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
l.AddAll([]int{4,5,6})
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### AddByIndex
|
||||
|
||||
将指定元素插入此列表中的指定位置。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
list.AddByIndex(2, 6)
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### DeleteAt
|
||||
|
||||
移除此列表中指定位置的元素。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteAt(index int) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
list.DeleteAt(2)
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
```
|
||||
|
||||
### DeleteIf
|
||||
|
||||
从此列表中删除第一个出现的指定元素(如果该元素存在)。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) (oldValue *T, ok bool)
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
list.DeleteIf(func(i int) bool {
|
||||
return i == 2
|
||||
})
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
```
|
||||
|
||||
### DeleteBy
|
||||
|
||||
从此列表中删除第一个出现的指定元素(如果该元素存在)。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteBy(e T) (*T bool)
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3})
|
||||
list.DeleteBy(2)
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
```
|
||||
|
||||
### DeleteRange
|
||||
|
||||
从该列表中删除索引介于 fromIndex(包含)和 toIndex(不包含)之间的所有元素。
|
||||
(左闭右开)。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int)
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
|
||||
list.DeleteRange(2, 5)
|
||||
fmt.Println(l.getList())
|
||||
}
|
||||
```
|
||||
|
||||
### Equal
|
||||
|
||||
如果指定的对象等于此列表,则返回 true。
|
||||
|
||||
```go
|
||||
func (c *CopyOnWriteList[T]) Equal(e []T) bool
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/datastructure/list"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
|
||||
fmt.Println(l.Equal([]int{1,2,3,4,5,6,7,8,9}))
|
||||
}
|
||||
```
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
- [Iterate](#Iterate)
|
||||
- [Keys](#Keys)
|
||||
- [Values](#Values)
|
||||
- [FilterByValue](#FilterByValue)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -38,7 +39,7 @@ import (
|
||||
|
||||
### <span id="NewHashMap">NewHashMap</span>
|
||||
|
||||
<p>新建默认容量(1 << 10)的HashMap指针实例</p>
|
||||
<p>新建默认容量(1 << 10)的HashMap指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -276,7 +277,7 @@ func main() {
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
|
||||
<p>返回hashmap所有值的切片 (随机顺序).</p>
|
||||
<p>返回hashmap所有值的切片 (随机顺序)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -306,3 +307,40 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
### <span id="FilterByValue">FilterByValue</span>
|
||||
|
||||
<p>返回一个过滤后的HashMap。 如果任何值与 perdicate 函数不匹配,则返回 nil,否则返回包含选定值的 HashMap。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (hm *HashMap) FilterByValue(perdicate func(value any) bool) *HashMap
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
hm := hashmap.NewHashMap()
|
||||
|
||||
hm.Put("a", 1)
|
||||
hm.Put("b", 2)
|
||||
hm.Put("c", 3)
|
||||
hm.Put("d", 4)
|
||||
hm.Put("e", 5)
|
||||
hm.Put("f", 6)
|
||||
|
||||
filteredHM := hm.FilterByValue(func(value any) bool {
|
||||
return value.(int) == 1 || value.(int) == 3
|
||||
})
|
||||
|
||||
fmt.Println(filteredHM.Size()) //2
|
||||
}
|
||||
```
|
||||
@@ -44,9 +44,9 @@ MaxHeap是通过slice实现的二叉堆树,根节点的key既大于等于左
|
||||
```go
|
||||
type MaxHeap[T any] struct {
|
||||
data []T
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T]
|
||||
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
412
docs/api/packages/datastructure/optional.md
Normal file
412
docs/api/packages/datastructure/optional.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# Optional
|
||||
Optional类型代表一个可选的值,它要么包含一个实际值,要么为空。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/optional/optional.go](https://github.com/duke-git/lancet/blob/main/datastructure/optional/optional.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Of](#Of)
|
||||
- [FromNillable](#FromNillable)
|
||||
- [Default](#Default)
|
||||
- [IsNotNil](#IsNotNil)
|
||||
- [IsNil](#IsNil)
|
||||
- [IsNotNil](#IsNotNil)
|
||||
- [IfNotNilOrElse](#IfNotNilOrElse)
|
||||
- [Umwarp](#Umwarp)
|
||||
- [OrElse](#OrElse)
|
||||
- [OrElseGet](#OrElseGet)
|
||||
- [OrElseTrigger](#OrElseTrigger)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Of">Of</span>
|
||||
<p>返回一个包含非空值的Optional。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Of[T any](value T) Optional[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
value := 42
|
||||
opt := optional.Of(value)
|
||||
|
||||
fmt.Println(opt.Get())
|
||||
|
||||
// Output:
|
||||
// 42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FromNillable">FromNillable</span>
|
||||
<p>返回一个包含给定值的Optional,该值可能为空 (nil)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FromNillable[T any](value *T) Optional[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value *int = nil
|
||||
opt := optional.FromNillable(value)
|
||||
|
||||
fmt.Println(opt.IsNotNil())
|
||||
|
||||
value = new(int)
|
||||
*value = 42
|
||||
opt = optional.FromNillable(value)
|
||||
|
||||
fmt.Println(opt.IsNotNil())
|
||||
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Default">Default</span>
|
||||
<p>返回一个空Optional实例。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Default[T any]() Optional[T]
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
optDefault := optional.Default[int]()
|
||||
fmt.Println(optDefault.IsNil())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsNil">IsNil</span>
|
||||
<p>验证Optional是否为空。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) IsNil() bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
optDefault := optional.Default[int]()
|
||||
fmt.Println(optDefault.IsNil())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsNotNil">IsNotNil</span>
|
||||
<p>检查当前Optional内是否存在值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) IsNotNil() bool
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value *int = nil
|
||||
opt := optional.FromNillable(value)
|
||||
|
||||
fmt.Println(opt.IsNotNil())
|
||||
|
||||
value = new(int)
|
||||
*value = 42
|
||||
opt = optional.FromNillable(value)
|
||||
|
||||
fmt.Println(opt.IsNotNil())
|
||||
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IfNotNil">IfNotNil</span>
|
||||
<p>如果值存在,则使用action方法执行给定的操作。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) IfNotNil(action func(value T))
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
called := false
|
||||
action := func(value int) { called = true }
|
||||
|
||||
optDefault := optional.Default[int]()
|
||||
optDefault.IfNotNil(action)
|
||||
|
||||
fmt.Println(called)
|
||||
|
||||
called = false // Reset for next test
|
||||
optWithValue := optional.Of(42)
|
||||
optWithValue.IfNotNil(action)
|
||||
|
||||
fmt.Println(optWithValue.IsNotNil())
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IfNotNilOrElse">IfNotNilOrElse</span>
|
||||
<p>根据是否存在值执行相应的操作:有值则执行指定操作,没有值则执行默认操作。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) IfNotNilOrElse(action func(value T), fallbackAction func())
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledWithValue := false
|
||||
valueAction := func(value int) { calledWithValue = true }
|
||||
emptyAction := func() { t.Errorf("Empty action should not be called when value is present") }
|
||||
|
||||
optWithValue := optional.Of(42)
|
||||
optWithValue.IfNotNilOrElse(valueAction, emptyAction)
|
||||
|
||||
fmt.Println(calledWithValue)
|
||||
|
||||
calledWithEmpty := false
|
||||
valueAction = func(value int) { t.Errorf("Value action should not be called when value is not present") }
|
||||
emptyAction = func() { calledWithEmpty = true }
|
||||
|
||||
optDefault := optional.Default[int]()
|
||||
optDefault.IfNotNilOrElse(valueAction, emptyAction)
|
||||
|
||||
fmt.Println(calledWithEmpty)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
<p>如果存在,返回该值,否则引发panic。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) Unwrap() T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
value := 42
|
||||
opt := optional.Of(value)
|
||||
|
||||
fmt.Println(opt.Unwrap())
|
||||
|
||||
// Output:
|
||||
// 42
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OrElse">OrElse</span>
|
||||
<p>检查Optional值是否存在,如果存在,则直接返回该值。如果不存在,返回参数other值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) OrElse(other T) T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
optDefault := optional.Empty[int]()
|
||||
val := optDefault.OrElse(100)
|
||||
fmt.Println(val)
|
||||
|
||||
optWithValue := optional.Of(42)
|
||||
val = optWithValue.OrElse(100)
|
||||
fmt.Println(val)
|
||||
|
||||
// Output:
|
||||
// 100
|
||||
// 42
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="OrElseGet">OrElseGet</span>
|
||||
<p>检查Optional值是否存在,如果存在,则直接返回该值。如果不存在,则调用一个提供的函数 (supplier),并返回该函数的执行结果。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (o Optional[T]) OrElseGet(action func() T) T
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
optDefault := optional.Default[int]()
|
||||
action := func() int { return 100 }
|
||||
|
||||
val := optDefault.OrElseGet(action)
|
||||
fmt.Println(val)
|
||||
|
||||
// Output:
|
||||
// 100
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="OrElseTrigger">OrElseTrigger</span>
|
||||
<p>检查Optional值是否存在,如果存在,则直接返回该值,否则返回错误。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
OrElseTrigger(errorHandler func() error) (T, error)
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datastructure/optional"
|
||||
)
|
||||
|
||||
func main() {
|
||||
optDefault := optional.Default[int]()
|
||||
_, err := optDefault.OrElseTrigger(func() error { return errors.New("no value") })
|
||||
|
||||
fmt.Println(err.Error())
|
||||
|
||||
optWithValue := optional.Of(42)
|
||||
val, err := optWithValue.OrElseTrigger(func() error { return errors.New("no value") })
|
||||
|
||||
fmt.Println(val)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// no value
|
||||
// 42
|
||||
// nil
|
||||
}
|
||||
```
|
||||
@@ -1100,12 +1100,12 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewPriorityQueue[T any](capacity int, comparator lancetconstraints.Comparator) *PriorityQueue[T]
|
||||
func NewPriorityQueue[T any](capacity int, comparator constraints.Comparator) *PriorityQueue[T]
|
||||
|
||||
type PriorityQueue[T any] struct {
|
||||
items []T
|
||||
size int
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
```
|
||||
<b>示例:</b>
|
||||
@@ -1,6 +1,6 @@
|
||||
# Set
|
||||
|
||||
Set 集合数据结构,类似列表。Set 中元素不重复。
|
||||
集合数据结构,类似列表。Set中元素不重复。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
|
||||
## 目录
|
||||
|
||||
- [NewSet](#NewSet)
|
||||
- [NewSetFromSlice](#NewSetFromSlice)
|
||||
- [Values](#Values)
|
||||
- [New](#New)
|
||||
- [FromSlice](#FromSlice)
|
||||
- [Values<sup>deprecated</sup>](#Values)
|
||||
- [Add](#Add)
|
||||
- [AddIfNotExist](#AddIfNotExist)
|
||||
- [AddIfNotExistBy](#AddIfNotExistBy)
|
||||
@@ -40,20 +40,23 @@ import (
|
||||
- [Intersection](#Intersection)
|
||||
- [SymmetricDifference](#SymmetricDifference)
|
||||
- [Minus](#Minus)
|
||||
- [Pop](#Pop)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [ToSortedSlice](#ToSortedSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="NewSet">NewSet</span>
|
||||
### <span id="New">New</span>
|
||||
|
||||
<p>返回Set结构体对象</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Set[T comparable] map[T]bool
|
||||
func NewSet[T comparable](items ...T) Set[T]
|
||||
type Set[T comparable] map[T]struct{}
|
||||
func New[T comparable](items ...T) Set[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
@@ -67,19 +70,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
st := set.New[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||
### <span id="FromSlice">FromSlice</span>
|
||||
|
||||
<p>基于切片创建集合</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||
func FromSlice[T comparable](items []T) Set[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
@@ -93,14 +96,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSetFromSlice([]int{1, 2, 2, 3})
|
||||
st := set.FromSlice([]int{1, 2, 2, 3})
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
|
||||
<p>获取集合中所有元素的切片</p>
|
||||
<p>获取集合中所有元素的切片。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`ToSlice`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -119,7 +124,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int](1,2,2,3)
|
||||
st := set.New[int](1,2,2,3)
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
}
|
||||
```
|
||||
@@ -145,7 +150,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st := set.New[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Values()) //1,2,3
|
||||
@@ -173,7 +178,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st := set.New[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
r1 := st.AddIfNotExist(1)
|
||||
@@ -206,7 +211,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st := set.New[int]()
|
||||
st.Add(1, 2)
|
||||
|
||||
ok := st.AddIfNotExistBy(3, func(val int) bool {
|
||||
@@ -245,7 +250,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st := set.New[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
set.Delete(3)
|
||||
@@ -274,7 +279,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
st := set.NewSet[int]()
|
||||
st := set.New[int]()
|
||||
st.Add(1, 2, 3)
|
||||
|
||||
fmt.Println(st.Contain(1)) //true
|
||||
@@ -303,9 +308,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(1, 2)
|
||||
set3 := set.New(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.ContainAll(set2)) //true
|
||||
fmt.Println(set1.ContainAll(set3)) //false
|
||||
@@ -333,7 +338,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set1 := set.New(1, 2, 3)
|
||||
|
||||
fmt.Println(set1.Size()) //3
|
||||
}
|
||||
@@ -360,7 +365,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set1.Clone()
|
||||
|
||||
fmt.Println(set1.Size() == set2.Size()) //true
|
||||
@@ -389,9 +394,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(1, 2, 3)
|
||||
set3 := set.NewSet(1, 2, 3, 4)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(1, 2, 3)
|
||||
set3 := set.New(1, 2, 3, 4)
|
||||
|
||||
fmt.Println(set1.Equal(set2)) //true
|
||||
fmt.Println(set1.Equal(set3)) //false
|
||||
@@ -419,7 +424,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set1 := set.New(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(item int) {
|
||||
arr = append(arr, item)
|
||||
@@ -450,7 +455,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := set.NewSet(1, 2, 3, 4, 5)
|
||||
s := set.New(1, 2, 3, 4, 5)
|
||||
|
||||
var sum int
|
||||
|
||||
@@ -487,8 +492,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet()
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New()
|
||||
|
||||
fmt.Println(set1.IsEmpty()) //false
|
||||
fmt.Println(set2.IsEmpty()) //true
|
||||
@@ -516,8 +521,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(2, 3, 4, 5)
|
||||
set3 := set1.Union(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,2,3,4,5
|
||||
@@ -545,8 +550,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(2, 3, 4, 5)
|
||||
set3 := set1.Intersection(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //2,3
|
||||
@@ -574,8 +579,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(2, 3, 4, 5)
|
||||
set3 := set1.SymmetricDifference(set2)
|
||||
|
||||
fmt.Println(set3.Values()) //1,4,5
|
||||
@@ -603,9 +608,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
set1 := set.NewSet(1, 2, 3)
|
||||
set2 := set.NewSet(2, 3, 4, 5)
|
||||
set3 := set.NewSet(2, 3)
|
||||
set1 := set.New(1, 2, 3)
|
||||
set2 := set.New(2, 3, 4, 5)
|
||||
set3 := set.New(2, 3)
|
||||
|
||||
res1 := set1.Minus(set2)
|
||||
fmt.Println(res1.Values()) //1
|
||||
@@ -636,7 +641,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := set.NewSet[int]()
|
||||
s := set.New[int]()
|
||||
s.Add(1)
|
||||
s.Add(2)
|
||||
s.Add(3)
|
||||
@@ -647,3 +652,58 @@ func main() {
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSlice">ToSlice</span>
|
||||
|
||||
<p>以切片的形式返回集合中所有的元素(无序)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) ToSlice() (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
func main() {
|
||||
s := set.New(1, 2, 3, 4, 5)
|
||||
|
||||
val := s.ToSlice()
|
||||
fmt.Println(val) // [2 3 4 5 1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSortedSlice">ToSortedSlice</span>
|
||||
|
||||
<p>以切片的形式返回集合中所有的元素(按给定的规则排序)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Set[T]) ToSortedSlice() (v T, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
func main() {
|
||||
s1 := set.New(1, 2, 3, 4, 5)
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
s2 := FromSlice([]Person{{"Tom", 20}, {"Jerry", 18}, {"Spike", 25}})
|
||||
|
||||
res1 := s1.ToSortedSlice(func(v1, v2 int) bool {
|
||||
return v1 < v2
|
||||
})
|
||||
|
||||
res2 := s2.ToSortedSlice(func(v1, v2 Person) bool {
|
||||
return v1.Age < v2.Age
|
||||
})
|
||||
|
||||
fmt.Println(res1) // [1 2 3 4 5]
|
||||
fmt.Println(res2) // [{Jerry 18} {Tom 20} {Spike 25}]
|
||||
}
|
||||
```
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
## 文档
|
||||
|
||||
## 1. BSTree
|
||||
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现lancetconstraints.Comparator。
|
||||
BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子,分别称为左孩子和右孩子。 在 BSTree 中:leftNode < rootNode < rightNode。 T类型应该实现constraints.Comparator。
|
||||
|
||||
### <span id="NewBSTree">NewBSTree</span>
|
||||
<p>返回BSTree指针实例</p>
|
||||
@@ -49,11 +49,11 @@ BSTree是一种二叉搜索树数据结构,其中每个节点有两个孩子
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewBSTree[T any](rootData T, comparator lancetconstraints.Comparator) *BSTree[T]
|
||||
func NewBSTree[T any](rootData T, comparator constraints.Comparator) *BSTree[T]
|
||||
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
comparator lancetconstraints.Comparator
|
||||
comparator constraints.Comparator
|
||||
}
|
||||
|
||||
type TreeNode[T any] struct {
|
||||
@@ -58,8 +58,18 @@ import (
|
||||
- [IsLeapYear](#IsLeapYear)
|
||||
- [BetweenSeconds](#BetweenSeconds)
|
||||
- [DayOfYear](#DayOfYear)
|
||||
- [IsWeekend](#IsWeekend)
|
||||
|
||||
- [IsWeekend<sup>deprecated</sup>](#IsWeekend)
|
||||
- [NowDateOrTime](#NowDateOrTime)
|
||||
- [Timestamp](#Timestamp)
|
||||
- [TimestampMilli](#TimestampMilli)
|
||||
- [TimestampMicro](#TimestampMicro)
|
||||
- [TimestampNano](#TimestampNano)
|
||||
- [TrackFuncTime](#TrackFuncTime)
|
||||
- [DaysBetween](#DaysBetween)
|
||||
- [GenerateDatetimesBetween](#GenerateDatetimesBetween)
|
||||
- [Min](#Min)
|
||||
- [Max](#Max)
|
||||
- [MaxMin](#MaxMin)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -67,7 +77,7 @@ import (
|
||||
|
||||
## 注:
|
||||
|
||||
1. 方法 FormatTimeToStr 和 FormatStrToTime 中的 format 参数值需要传以下类型之一:
|
||||
1. 函数中`format`参数值需要传以下值之一 (忽略大小写):
|
||||
|
||||
- yyyy-mm-dd hh:mm:ss
|
||||
- yyyy-mm-dd hh:mm
|
||||
@@ -78,14 +88,18 @@ import (
|
||||
- dd-mm-yy hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm
|
||||
- yyyy-mm-dd hh
|
||||
- yyyy/mm/dd hh
|
||||
- yyyy/mm/dd
|
||||
- yyyy/mm
|
||||
- mm/dd
|
||||
- dd/mm/yy hh:mm:ss
|
||||
- yyyymmdd
|
||||
- mmddyy
|
||||
- yyyy
|
||||
- yy
|
||||
- mm
|
||||
- hh:mm:ss
|
||||
- hh:mm
|
||||
- mm:ss
|
||||
|
||||
### <span id="AddDay">AddDay</span>
|
||||
@@ -98,7 +112,7 @@ import (
|
||||
func AddDay(t time.Time, day int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dIGbs_uTdFa)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -137,7 +151,7 @@ func main() {
|
||||
func AddHour(t time.Time, hour int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rcMjd7OCsi5)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -176,7 +190,7 @@ func main() {
|
||||
func AddMinute(t time.Time, minute int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nT1heB1KUUK)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -215,7 +229,7 @@ func main() {
|
||||
func AddYear(t time.Time, year int64) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MqW2ujnBx10)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -254,7 +268,7 @@ func main() {
|
||||
func BeginOfMinute(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ieOLVJ9CiFT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -286,7 +300,7 @@ func main() {
|
||||
func BeginOfHour(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GhdGFnDWpYs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -318,7 +332,7 @@ func main() {
|
||||
func BeginOfDay(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/94m_UT6cWs9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -350,7 +364,7 @@ func main() {
|
||||
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ynjoJPz7VNV)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -382,7 +396,7 @@ func main() {
|
||||
func BeginOfMonth(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bWXVFsmmzwL)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -414,7 +428,7 @@ func main() {
|
||||
func BeginOfYear(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/i326DSwLnV8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -446,7 +460,7 @@ func main() {
|
||||
func EndOfMinute(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/yrL5wGzPj4z)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -478,7 +492,7 @@ func main() {
|
||||
func EndOfHour(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6ce3j_6cVqN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -510,7 +524,7 @@ func main() {
|
||||
func EndOfDay(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/eMBOvmq5Ih1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -542,7 +556,7 @@ func main() {
|
||||
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/i08qKXD9flf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -574,7 +588,7 @@ func main() {
|
||||
func EndOfMonth(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_GWh10B3Nqi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -606,7 +620,7 @@ func main() {
|
||||
func EndOfYear(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/G01cKlMCvNm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -638,7 +652,7 @@ func main() {
|
||||
func GetNowDate() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/PvfkPpcpBBf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -667,7 +681,7 @@ func main() {
|
||||
func GetNowTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/l7BNxCkTmJS)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -696,7 +710,7 @@ func main() {
|
||||
func GetNowDateTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pI4AqngD0al)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -717,7 +731,7 @@ func main() {
|
||||
|
||||
### <span id="GetTodayStartTime">GetTodayStartTime</span>
|
||||
|
||||
<p>返回当天开始时间, 格式: yyyy-mm-dd 00:00:00.</p>
|
||||
<p>返回当天开始时间, 格式: yyyy-mm-dd 00:00:00。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -725,7 +739,7 @@ func main() {
|
||||
func GetTodayStartTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/84siyYF7t99)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -746,7 +760,7 @@ func main() {
|
||||
|
||||
### <span id="GetTodayEndTime">GetTodayEndTime</span>
|
||||
|
||||
<p>返回当天结束时间,格式: yyyy-mm-dd 23:59:59.</p>
|
||||
<p>返回当天结束时间,格式: yyyy-mm-dd 23:59:59。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -754,7 +768,7 @@ func main() {
|
||||
func GetTodayEndTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jjrLnfoqgn3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -783,7 +797,7 @@ func main() {
|
||||
func GetZeroHourTimestamp() int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QmL2oIaGE3q)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -812,7 +826,7 @@ func main() {
|
||||
func GetNightTimestamp() int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UolysR3MYP1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -838,10 +852,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FormatTimeToStr(t time.Time, format string) string
|
||||
func FormatTimeToStr(t time.Time, format string, timezone ...string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_Ia7M8H_OvE)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -877,10 +891,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FormatStrToTime(str, format string) (time.Time, error)
|
||||
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/1h9FwdU8ql4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -919,7 +933,7 @@ type theTime struct {
|
||||
func NewUnixNow() *theTime
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/U4PPx-9D0oz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -951,7 +965,7 @@ type theTime struct {
|
||||
func NewUnix(unix int64) *theTime
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/psoSuh_kLRt)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -983,7 +997,7 @@ type theTime struct {
|
||||
func NewFormat(t string) (*theTime, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VkW08ZOaXPZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1015,7 +1029,7 @@ type theTime struct {
|
||||
func NewISO8601(iso8601 string) (*theTime, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mkhOHQkdeA2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1044,7 +1058,7 @@ func main() {
|
||||
func (t *theTime) ToUnix() int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_LUiwAdocjy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1073,7 +1087,7 @@ func main() {
|
||||
func (t *theTime) ToFormat() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VkW08ZOaXPZ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1102,7 +1116,7 @@ func main() {
|
||||
func (t *theTime) ToFormatForTpl(tpl string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nyXxXcQJ8L5)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1132,7 +1146,7 @@ func main() {
|
||||
func (t *theTime) ToIso8601() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mkhOHQkdeA2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1162,7 +1176,7 @@ func main() {
|
||||
func IsLeapYear(year int) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xS1eS2ejGew)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1195,7 +1209,7 @@ func main() {
|
||||
func BetweenSeconds(t1 time.Time, t2 time.Time) int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/n3YDRyfyXJu)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1232,7 +1246,7 @@ func main() {
|
||||
func DayOfYear(t time.Time) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0hjqhTwFNlH)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1263,7 +1277,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsWeekend">IsWeekend</span>
|
||||
### <span id="IsWeekend">IsWeekend(已废弃, 使用 '== Weekday')</span>
|
||||
|
||||
<p>判断日期是否是周末。</p>
|
||||
|
||||
@@ -1273,7 +1287,7 @@ func main() {
|
||||
func IsWeekend(t time.Time) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cupRM5aZOIY)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1302,3 +1316,353 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="NowDateOrTime">NowDateOrTime</span>
|
||||
|
||||
<p>根据指定的格式和时区返回当前时间字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NowDateOrTime(format string, timezone ...string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/EZ-begEjtT0)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
|
||||
|
||||
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2023-07-26 15:01:30
|
||||
// 2023-07-26 02:01:30
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Timestamp">Timestamp</span>
|
||||
|
||||
<p>返回当前秒级时间戳。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Timestamp(timezone ...string) int64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iU5b7Vvjx6x)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ts := datetime.Timestamp()
|
||||
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 1690363051
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="TimestampMilli">TimestampMilli</span>
|
||||
|
||||
<p>返回当前毫秒级时间戳。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TimestampMilli(timezone ...string) int64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4gvEusOTu1T)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ts := datetime.TimestampMilli()
|
||||
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 1690363051331
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TimestampMicro">TimestampMicro</span>
|
||||
|
||||
<p>返回当前微秒级时间戳。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TimestampMicro(timezone ...string) int64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2maANglKHQE)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ts := datetime.TimestampMicro()
|
||||
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 1690363051331784
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TimestampNano">TimestampNano</span>
|
||||
|
||||
<p>返回当前纳秒级时间戳。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TimestampNano(timezone ...string) int64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/A9Oq_COrcCF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ts := datetime.TimestampNano()
|
||||
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 1690363051331788000
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TrackFuncTime">TrackFuncTime</span>
|
||||
|
||||
<p>测试函数执行时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TrackFuncTime(pre time.Time) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/QBSEdfXHPTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer datetime.TrackFuncTime(time.Now())()
|
||||
|
||||
var n int
|
||||
for i := 0; i < 5000000; i++ {
|
||||
n++
|
||||
}
|
||||
|
||||
fmt.Println(1) // Function main execution time: 1.460287ms
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DaysBetween">DaysBetween</span>
|
||||
|
||||
<p>返回两个日期之间的天数差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DaysBetween(start, end time.Time) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qD6qGb3TbOy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2024, time.September, 10, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
result := datetime.DaysBetween(start, end)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 9
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GenerateDatetimesBetween">GenerateDatetimesBetween</span>
|
||||
|
||||
<p>生成从start到end的所有日期时间的字符串列表。layout参数表示时间格式,例如"2006-01-02 15:04:05",interval参数表示时间间隔,例如"1h"表示1小时,"30m"表示30分钟。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GenerateDatetimesBetween(start, end time.Time, layout string, interval string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6kHBpAxD9ZC)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC)
|
||||
end := time.Date(2024, time.September, 1, 2, 0, 0, 0, time.UTC)
|
||||
|
||||
layout := "2006-01-02 15:04:05"
|
||||
interval := "1h"
|
||||
|
||||
result, err := datetime.GenerateDatetimesBetween(start, end, layout, interval)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// [2024-09-01 00:00:00 2024-09-01 01:00:00 2024-09-01 02:00:00]
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>返回最早时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
minTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(minTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>返回最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max(t1 time.Time, times ...time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
maxTime := datetime.Min(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(maxTime)
|
||||
|
||||
// Output:
|
||||
// 2024-09-02 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MaxMin">MaxMin</span>
|
||||
|
||||
<p>返回最早和最晚时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxMin(t1 time.Time, times ...time.Time) (maxTime time.Time, minTime time.Time)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max, min := datetime.MaxMin(time.Date(2024, time.September, 1, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 2, 0, 0, 0, 0, time.UTC), time.Date(2024, time.September, 3, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
fmt.Println(max)
|
||||
fmt.Println(min)
|
||||
|
||||
// Output:
|
||||
// 2024-09-03 00:00:00 +0000 UTC
|
||||
// 2024-09-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [CopyDir](#CopyDir)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
@@ -45,8 +46,13 @@ import (
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteMapsToCsv](#WriteMapsToCsv)
|
||||
- [WriteStringToFile](#WriteStringToFile)
|
||||
- [WriteBytesToFile](#WriteBytesToFile)
|
||||
- [ReadFile](#ReadFile)
|
||||
- [ChunkRead](#ChunkRead)
|
||||
- [ParallelChunkRead](#ParallelChunkRead)
|
||||
- [GetExeOrDllVersion](#GetExeOrDllVersion)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -62,7 +68,7 @@ import (
|
||||
func ClearFile(path string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/NRZ0ZT-G94H)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -90,7 +96,7 @@ func main() {
|
||||
func CreateFile(path string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/lDt8PEsTNKI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -108,7 +114,7 @@ func main() {
|
||||
|
||||
### <span id="CreateDir">CreateDir</span>
|
||||
|
||||
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
|
||||
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -116,7 +122,7 @@ func main() {
|
||||
func CreateDir(absPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qUuCe1OGQnM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -127,7 +133,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.CreateDir("/a/")
|
||||
err := fileutil.CreateDir("/a/b") // will create folder /a/b
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
@@ -142,7 +148,7 @@ func main() {
|
||||
func CopyFile(srcPath string, dstPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Jg9AMJMLrJi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -160,6 +166,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CopyDir">CopyDir</span>
|
||||
|
||||
<p>拷贝文件夹到目标路径,会递归复制文件夹下所有的文件及文件夹,并且访问权限也与源文件夹保持一致。当dstPath存在时会返回error</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CopyDir(srcPath string, dstPath string) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/YAyFTA_UuPb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.CopyFile("./test_src", "./test_dest")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurrentPath">CurrentPath</span>
|
||||
|
||||
<p>返回当前位置的绝对路径。</p>
|
||||
@@ -170,7 +204,7 @@ func main() {
|
||||
func CurrentPath() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/s74a9iBGcSw)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -196,7 +230,7 @@ func main() {
|
||||
func FileMode(path string) (fs.FileMode, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2l2hI42fA3p)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -225,7 +259,7 @@ func main() {
|
||||
func MiMeType(file any) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bd5sevSUZNu)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -256,7 +290,7 @@ func main() {
|
||||
func IsExist(path string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nKKXt8ZQbmh)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -283,7 +317,7 @@ func main() {
|
||||
func IsLink(path string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TL-b-Kzvf44)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -309,7 +343,7 @@ func main() {
|
||||
func IsDir(path string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/WkVwEKqtOWk)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -338,7 +372,7 @@ func main() {
|
||||
func ListFileNames(path string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Tjd7Y07rejl)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -364,7 +398,7 @@ func main() {
|
||||
func RemoveFile(path string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/P2y0XW8a1SH)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -392,7 +426,7 @@ func main() {
|
||||
func ReadFileToString(path string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cmfwp_5SQTp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -425,7 +459,7 @@ func main() {
|
||||
func ReadFileByLine(path string)([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/svJP_7ZrBrD)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -459,7 +493,7 @@ func main() {
|
||||
func Zip(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/j-3sWBp8ik_P)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -487,7 +521,7 @@ func main() {
|
||||
func ZipAppendEntry(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cxvaT8TRNQp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -515,7 +549,7 @@ func main() {
|
||||
func UnZip(zipFile string, destPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/g0w34kS7B8m)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -526,7 +560,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.Zip("./test.zip", "./unzip/test.txt")
|
||||
err := fileutil.UnZip("./test.zip", "./test.txt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -543,7 +577,7 @@ func main() {
|
||||
func IsZipFile(filepath string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9M0g2j_uF_e)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -569,7 +603,7 @@ func main() {
|
||||
func FileSize(path string) (int64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/H9Z05uD-Jjc)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -601,7 +635,7 @@ func main() {
|
||||
func MTime(filepath string) (int64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/s_Tl7lZoAaY)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -633,7 +667,7 @@ func main() {
|
||||
func Sha(filepath string, shaType ...int) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/VfEEcO2MJYf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -668,10 +702,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReadCsvFile(filepath string) ([][]string, error)
|
||||
func ReadCsvFile(filepath string, delimiter ...rune) ([][]string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OExTkhGEd3_u)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -700,10 +734,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool, delimiter ...rune) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dAXm58Q5U1o)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -742,6 +776,59 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteMapsToCsv">WriteMapsToCsv</span>
|
||||
|
||||
<p>将map切片写入csv文件中。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
// filepath: CSV文件路径。
|
||||
// records: 写入文件的map切片。map值必须为基本类型。会以map键的字母顺序写入。
|
||||
// appendToExistingFile: 是否为追加写模式。
|
||||
// delimiter: CSV文件分割符。
|
||||
// headers: CSV文件表头顺序(需要与map key保持一致),不指定时按字母排序。
|
||||
func WriteMapsToCsv(filepath string, records []map[string]any, appendToExistingFile bool, delimiter rune, headers ...[]string) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/umAIomZFV1c)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fpath := "./test.csv"
|
||||
fileutil.CreateFile(fpath)
|
||||
|
||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
records := []map[string]any{
|
||||
{"Name": "Lili", "Age": "22", "Gender": "female"},
|
||||
{"Name": "Jim", "Age": "21", "Gender": "male"},
|
||||
}
|
||||
|
||||
headers := []string{"Name", "Age", "Gender"}
|
||||
err := fileutil.WriteMapsToCsv(csvFilePath, records, false, ';', headers)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadCsvFile(csvFilePath, ';')
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Name Age Gender] [Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||
|
||||
<p>将bytes写入文件。</p>
|
||||
@@ -752,7 +839,7 @@ func main() {
|
||||
func WriteBytesToFile(filepath string, content []byte) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/s7QlDxMj3P8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -801,7 +888,7 @@ func main() {
|
||||
func WriteStringToFile(filepath string, content string, append bool) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GhLS6d8lH_g)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -839,3 +926,185 @@ func main() {
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ReadFile">ReadFile</span>
|
||||
|
||||
<p>读取文件或者URL。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uNep3Tr8fqF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
reader, fn, err := fileutil.ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fn()
|
||||
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(dat))
|
||||
|
||||
// Output:
|
||||
// User-agent: *
|
||||
// Disallow: /deny
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ChunkRead">ChunkRead</span>
|
||||
|
||||
<p>从文件的指定偏移读取块并返回块内所有行。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ChunkRead(file *os.File, offset int64, size int, bufPool *sync.Pool) ([]string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/r0hPmKWhsgf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const mb = 1024 * 1024
|
||||
const defaultChunkSizeMB = 100
|
||||
|
||||
// test1.csv file content:
|
||||
// Lili,22,female
|
||||
// Jim,21,male
|
||||
filePath := "./testdata/test1.csv" // 替换为你的文件路径
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, 0, defaultChunkSizeMB*mb)
|
||||
},
|
||||
}
|
||||
|
||||
lines, err := fileutil.ChunkRead(f, 0, 100, &bufPool)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(lines[0])
|
||||
fmt.Println(lines[1])
|
||||
|
||||
// Output:
|
||||
// Lili,22,female
|
||||
// Jim,21,male
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParallelChunkRead">ParallelChunkRead</span>
|
||||
|
||||
<p>并行读取文件并将每个块的行发送到指定通道。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
// filePath:文件路径
|
||||
// chunkSizeMB: 分块的大小(单位MB,设置为0时使用默认100MB),设置过大反而不利,视情调整
|
||||
// maxGoroutine: 并发读取分块的数量,设置为0时使用CPU核心数
|
||||
// linesCh: 用于接收返回结果的通道。
|
||||
func ParallelChunkRead(filePath string, linesCh chan<- []string, chunkSizeMB, maxGoroutine int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/teMXnCsdSEw)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const mb = 1024 * 1024
|
||||
const defaultChunkSizeMB = 100 // 默认值
|
||||
|
||||
numParsers := runtime.NumCPU()
|
||||
|
||||
linesCh := make(chan []string, numParsers)
|
||||
|
||||
// test1.csv file content:
|
||||
// Lili,22,female
|
||||
// Jim,21,male
|
||||
filePath := "./testdata/test1.csv"
|
||||
|
||||
go fileutil.ParallelChunkRead(filePath, linesCh, defaultChunkSizeMB, numParsers)
|
||||
|
||||
var totalLines int
|
||||
for lines := range linesCh {
|
||||
totalLines += len(lines)
|
||||
|
||||
for _, line := range lines {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(totalLines)
|
||||
|
||||
// Output:
|
||||
// Lili,22,female
|
||||
// Jim,21,male
|
||||
// 2
|
||||
}
|
||||
```
|
||||
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
|
||||
|
||||
<p>返回exe,dll文件版本号(仅Window平台).</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetExeOrDllVersion(filePath string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
// Output:
|
||||
// 3.9.10.19
|
||||
}
|
||||
```
|
||||
@@ -37,15 +37,15 @@ import (
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
|
||||
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||
<p>用逗号每隔3位分割数字/字符串,支持添加前缀符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, prefixSymbol string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/eRD5k2vzUVX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -81,7 +81,7 @@ func main() {
|
||||
func Pretty(v any) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/YsciGj3FH2x)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -120,7 +120,7 @@ func main() {
|
||||
func PrettyToWriter(v any, out io.Writer) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/LPLZ3lDi5ma)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -163,7 +163,7 @@ func main() {
|
||||
func DecimalBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/FPXs1suwRcs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -202,7 +202,7 @@ func main() {
|
||||
func BinaryBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/G9oHHMCAZxP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -241,7 +241,7 @@ func main() {
|
||||
func ParseDecimalBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Am98ybWjvjj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -280,7 +280,7 @@ func main() {
|
||||
func ParseBinaryBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/69v1tTT62x8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
786
docs/api/packages/function.md
Normal file
786
docs/api/packages/function.md
Normal file
@@ -0,0 +1,786 @@
|
||||
# Function
|
||||
|
||||
function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/predicate.go](https://github.com/duke-git/lancet/blob/main/function/predicate.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounce](#Debounce)
|
||||
- [Debounced<sup>deprecated</sup>](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Schedule](#Schedule)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Watcher](#Watcher)
|
||||
- [And](#And)
|
||||
- [Or](#Or)
|
||||
- [Negate](#Negate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [AcceptIf](#AcceptIf)
|
||||
- [Throttle](#Throttle)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/eRD5k2vzUVX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fn := function.After(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
|
||||
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0HqUDIFZ3IL)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fn := function.Before(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
<p>创建柯里化函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/5HopfDwANKX)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry function.CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/KKfugD4PKYF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := function.Compose(toUpper, toLower)
|
||||
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Debounce">Debounce</span>
|
||||
|
||||
<p>创建一个函数的去抖动版本。该去抖动函数仅在上次调用后的指定延迟时间过去之后才会调用原始函数。支持取消去抖动。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Debounce(fn func(), delay time.Duration) (debouncedFn func(), cancelFn func())
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/-dGFrYn_1Zi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
callCount := 0
|
||||
fn := func() {
|
||||
callCount++
|
||||
}
|
||||
|
||||
debouncedFn, _ := function.Debounce(fn, 500*time.Millisecond)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
debouncedFn()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println(callCount)
|
||||
|
||||
debouncedFn()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println(callCount)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个函数的去抖动版本。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用. 使用 `Debounce` 代替.
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Debounced(fn func(), duration time.Duration) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/absuEGB_GN7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Delay">Delay</span>
|
||||
|
||||
<p>延迟delay时间后调用函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Delay(delay time.Duration, fn any, args ...any)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Ivtc2ZE-Tye)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
function.Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Schedule">Schedule</span>
|
||||
|
||||
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/hbON-Xeyn5N)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
|
||||
increase := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
stop := function.Schedule(2*time.Second, increase)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pipeline">Pipeline</span>
|
||||
|
||||
<p>执行函数pipeline.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mPdUVvj6HD6)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
fn := function.Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start()
|
||||
func (w *Watcher) Stop()
|
||||
func (w *Watcher) Reset()
|
||||
func (w *Watcher) GetElapsedTime() time.Duration
|
||||
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/l2yrOpCLd1I)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
fmt.Println(w.excuting) //true
|
||||
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### <span id="And">And</span>
|
||||
|
||||
<p>返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑and操作。只有当所有谓词判断函数对于给定的值都返回true时,返回true, 否则返回false。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func And[T any](predicates ...func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dTBHJMQ0zD2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isNumericAndLength5 := function.And(
|
||||
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
|
||||
func(s string) bool { return len(s) == 5 },
|
||||
)
|
||||
|
||||
fmt.Println(isNumericAndLength5("12345"))
|
||||
fmt.Println(isNumericAndLength5("1234"))
|
||||
fmt.Println(isNumericAndLength5("abcde"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑or操作。只有当所有谓词判断函数对于给定的值都返回false时,返回false, 否则返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Or[T any](predicates ...func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/LitCIsDFNDA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
containsDigitOrSpecialChar := function.Or(
|
||||
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
|
||||
func(s string) bool { return strings.ContainsAny(s, "!@#$%") },
|
||||
)
|
||||
|
||||
fmt.Println(containsDigitOrSpecialChar("hello!"))
|
||||
fmt.Println(containsDigitOrSpecialChar("hello"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Negate">Negate</span>
|
||||
|
||||
<p>返回一个谓词函数,该谓词函数表示当前谓词的逻辑否定。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Negate[T any](predicate func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jbI8BtgFnVE)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Define some simple predicates for demonstration
|
||||
isUpperCase := func(s string) bool {
|
||||
return strings.ToUpper(s) == s
|
||||
}
|
||||
isLowerCase := func(s string) bool {
|
||||
return strings.ToLower(s) == s
|
||||
}
|
||||
isMixedCase := function.Negate(function.Or(isUpperCase, isLowerCase))
|
||||
|
||||
fmt.Println(isMixedCase("ABC"))
|
||||
fmt.Println(isMixedCase("AbC"))
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Nor">Nor</span>
|
||||
|
||||
<p>返回一个组合谓词函数,表示给定值上所有谓词逻辑非或 (nor) 的结果。只有当所有谓词函数对给定值都返回false时,该组合谓词函数才返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Nor[T any](predicates ...func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2KdCoBEOq84)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
match := function.Nor(
|
||||
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
|
||||
func(s string) bool { return len(s) == 5 },
|
||||
)
|
||||
|
||||
fmt.Println(match("dbcdckkeee"))
|
||||
|
||||
|
||||
match = function.Nor(
|
||||
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
|
||||
func(s string) bool { return len(s) == 5 },
|
||||
)
|
||||
|
||||
fmt.Println(match("0123456789"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
|
||||
<p>返回一个复合谓词函数,表示给定谓词函数列表的逻辑非与 (NAND)。仅当列表中所有函数对给定参数返回false时,才返回true,否则返回false。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Nand[T any](predicates ...func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Rb-FdNGpgSO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isNumericAndLength5 := function.Nand(
|
||||
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
|
||||
func(s string) bool { return len(s) == 5 },
|
||||
)
|
||||
|
||||
fmt.Println(isNumericAndLength5("12345"))
|
||||
fmt.Println(isNumericAndLength5("1234"))
|
||||
fmt.Println(isNumericAndLength5("abcdef"))
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
|
||||
<p>返回一个复合谓词函数,表示给定一组谓词函数的逻辑异或 (XNOR)。只有当所有 谓词函数对给参数都返回true或false时,该谓词函数才返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T any](predicates ...func(T) bool) func(T) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/FJxko8SFbqc)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isEven := func(i int) bool { return i%2 == 0 }
|
||||
isPositive := func(i int) bool { return i > 0 }
|
||||
|
||||
match := function.Xnor(isEven, isPositive)
|
||||
|
||||
fmt.Println(match(2))
|
||||
fmt.Println(match(-3))
|
||||
fmt.Println(match(3))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AcceptIf">AcceptIf</span>
|
||||
|
||||
<p>AcceptIf函数会返回另一个函数,该函数的签名与 apply 函数相同,但同时还会包含一个布尔值来表示成功或失败。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/XlXHHtzCf7d)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
adder := function.AcceptIf(
|
||||
function.And(
|
||||
func(x int) bool {
|
||||
return x > 10
|
||||
}, func(x int) bool {
|
||||
return x%2 == 0
|
||||
}),
|
||||
func(x int) int {
|
||||
return x + 1
|
||||
},
|
||||
)
|
||||
|
||||
result, ok := adder(20)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
result, ok = adder(21)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 21
|
||||
// true
|
||||
// 0
|
||||
// false
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### <span id="Throttle">Throttle</span>
|
||||
|
||||
<p>创建一个函数的节流版本。返回的函数保证在每个时间间隔内最多只会被调用一次。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Throttle(fn func(), interval time.Duration) func()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HpoMov-tJSN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
callCount := 0
|
||||
|
||||
fn := func() {
|
||||
callCount++
|
||||
}
|
||||
|
||||
throttledFn := function.Throttle(fn, 1*time.Second)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
throttledFn()
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
fmt.Println(callCount)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
2310
docs/api/packages/maputil.md
Normal file
2310
docs/api/packages/maputil.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,11 @@ import (
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [T运行cRound](#T运行cRound)
|
||||
- [CeilToFloat](#CeilToFloat)
|
||||
- [CeilToString](#CeilToString)
|
||||
- [FloorToFloat](#FloorToFloat)
|
||||
- [FloorToString](#FloorToString)
|
||||
- [Range](#Range)
|
||||
- [RangeWithStep](#RangeWithStep)
|
||||
- [AngleToRadian](#AngleToRadian)
|
||||
@@ -47,10 +51,15 @@ import (
|
||||
- [Log](#Log)
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
- [Div](#Div)
|
||||
- [Variance](#Variance)
|
||||
- [StdDev](#StdDev)
|
||||
- [Permutation](#Permutation)
|
||||
- [Combination](#Combination)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
## 文档
|
||||
|
||||
### <span id="Average">Average</span>
|
||||
|
||||
@@ -59,10 +68,10 @@ import (
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -82,7 +91,7 @@ func main() {
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.5
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
@@ -97,7 +106,7 @@ func main() {
|
||||
func Exponent(x, n int64) int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Vv7LBwER-pz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -133,7 +142,7 @@ func main() {
|
||||
func Fibonacci(first, second, n int) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/IscseUNMuUc)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -169,7 +178,7 @@ func main() {
|
||||
func Factorial(x uint) uint
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tt6LdOK67Nx)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -205,7 +214,7 @@ func main() {
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cN8DHI0rTkH)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -238,7 +247,7 @@ func main() {
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pbe2MT-7DV2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -282,7 +291,7 @@ func main() {
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pbe2MT-7DV2)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -315,7 +324,7 @@ func main() {
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/N9qgYg_Ho6f)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -359,7 +368,7 @@ func main() {
|
||||
func Percent(val, total float64, n int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/s0NdFCtwuyd)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -392,10 +401,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RoundToFloat(x float64, n int) float64
|
||||
func RoundToFloat[T constraints.Float | constraints.Integer](x T, n int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ghyb528JRJL)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -428,10 +437,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RoundToString(x float64, n int) string
|
||||
func RoundToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/kZwpBRAcllO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -457,17 +466,17 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
### <span id="T运行cRound">T运行cRound</span>
|
||||
|
||||
<p>截短n位小数(不进行四舍五入)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TruncRound(x float64, n int) float64
|
||||
func T运行cRound[T constraints.Float | constraints.Integer](x T, n int) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/aumarSHIGzP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -478,9 +487,9 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.TruncRound(0.124, 2)
|
||||
result2 := mathutil.TruncRound(0.125, 2)
|
||||
result3 := mathutil.TruncRound(0.125, 3)
|
||||
result1 := mathutil.T运行cRound(0.124, 2)
|
||||
result2 := mathutil.T运行cRound(0.125, 2)
|
||||
result3 := mathutil.T运行cRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -493,6 +502,150 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CeilToFloat">CeilToFloat</span>
|
||||
|
||||
<p>向上舍入(进一法),保留n位小数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CeilToFloat[T constraints.Float | constraints.Integer](x T, n int) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8hOeSADZPCo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.CeilToFloat(3.14159, 1)
|
||||
result2 := mathutil.CeilToFloat(3.14159, 2)
|
||||
result3 := mathutil.CeilToFloat(5, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3.2
|
||||
// 3.15
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CeilToString">CeilToString</span>
|
||||
|
||||
<p>向上舍入(进一法),保留n位小数,返回字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wy5bYEyUKKG)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.CeilToString(3.14159, 1)
|
||||
result2 := mathutil.CeilToString(3.14159, 2)
|
||||
result3 := mathutil.CeilToString(5, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3.2
|
||||
// 3.15
|
||||
// 5.0000
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FloorToFloat">FloorToFloat</span>
|
||||
|
||||
<p>向下舍入(去尾法),保留n位小数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FloorToFloat[T constraints.Float | constraints.Integer](x T, n int) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/vbCBrQHZEED)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.FloorToFloat(3.14159, 1)
|
||||
result2 := mathutil.FloorToFloat(3.14159, 2)
|
||||
result3 := mathutil.FloorToFloat(5, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3.1
|
||||
// 3.14
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FloorToString">FloorToString</span>
|
||||
|
||||
<p>向下舍入(去尾法),保留n位小数,返回字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func FloorToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Qk9KPd2IdDb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.FloorToString(3.14159, 1)
|
||||
result2 := mathutil.FloorToString(3.14159, 2)
|
||||
result3 := mathutil.FloorToString(5, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3.1
|
||||
// 3.14
|
||||
// 5.0000
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Range">Range</span>
|
||||
|
||||
<p>根据指定的起始值和数量,创建一个数字切片。</p>
|
||||
@@ -503,7 +656,7 @@ func main() {
|
||||
func Range[T constraints.Integer | constraints.Float](start T, count int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9ke2opxa8ZP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -542,7 +695,7 @@ func main() {
|
||||
func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/akLWz0EqOSM)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -581,7 +734,7 @@ func main() {
|
||||
func AngleToRadian(angle float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CIvlICqrHql)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -617,7 +770,7 @@ func main() {
|
||||
func RadianToAngle(radian float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dQtmOTUOMgi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -653,7 +806,7 @@ func main() {
|
||||
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/RrG4JIaziM8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -683,7 +836,7 @@ func main() {
|
||||
func IsPrime(n int) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Rdd8UTHZJ7u)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -722,7 +875,7 @@ func main() {
|
||||
func GCD[T constraints.Integer](integers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CiEceLSoAKB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -764,7 +917,7 @@ func main() {
|
||||
func LCM[T constraints.Integer](integers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/EjcZxfY7G_g)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -800,7 +953,7 @@ func main() {
|
||||
func Cos(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Sm89LoIfvFq)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -842,7 +995,7 @@ func main() {
|
||||
func Sin(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TWMQlMywDsP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -884,7 +1037,7 @@ func main() {
|
||||
func Log(n, base float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_d4bi8oyhat)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -896,8 +1049,8 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
result2 := mathutil.T运行cRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.T运行cRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -920,7 +1073,7 @@ func main() {
|
||||
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/1To2ImAMJA7)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -953,7 +1106,7 @@ func main() {
|
||||
func Abs[T constraints.Integer | constraints.Float](x T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fsyBh1Os-1d)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -965,16 +1118,184 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := Abs(-1)
|
||||
result2 := Abs(-0.1)
|
||||
result3 := Abs(float32(0.2))
|
||||
result2 := Abs(-0.1)
|
||||
result3 := Abs(float32(0.2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 0.1
|
||||
// 0.2
|
||||
// Output:
|
||||
// 1
|
||||
// 0.1
|
||||
// 0.2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Div">Div</span>
|
||||
|
||||
<p>除法运算。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Div[T constraints.Float | constraints.Integer](x T, y T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/WLxDdGXXYat)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Div(9, 4)
|
||||
result2 := mathutil.Div(1, 2)
|
||||
result3 := mathutil.Div(0, 666)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 2.25
|
||||
// 0.5
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Variance">Variance</span>
|
||||
|
||||
<p>计算方差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Variance[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[示例](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Variance([]int{1, 2, 3, 4, 5})
|
||||
result2 := mathutil.Variance([]float64{1.1, 2.2, 3.3, 4.4, 5.5})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 2.42
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StdDev">StdDev</span>
|
||||
|
||||
<p>计算标准差。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StdDev[T constraints.Float | constraints.Integer](numbers []T) float64
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.T运行cRound(mathutil.StdDev([]int{1, 2, 3, 4, 5}), 2)
|
||||
result2 := mathutil.T运行cRound(mathutil.StdDev([]float64{1.1, 2.2, 3.3, 4.4, 5.5}), 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1.41
|
||||
// 1.55
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Permutation">Permutation</span>
|
||||
|
||||
<p>计算排列数P(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Permutation(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Permutation(5, 3)
|
||||
result2 := mathutil.Permutation(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 60
|
||||
// 120
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Combination">Combination</span>
|
||||
|
||||
<p>计算组合数C(n, k)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Combination(n, k uint) uint
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Combination(5, 3)
|
||||
result2 := mathutil.Combination(5, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -63,7 +63,7 @@ import (
|
||||
func ConvertMapToQueryString(param map[string]any) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jnNt_qoSnRi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -98,7 +98,7 @@ func main() {
|
||||
func EncodeUrl(urlStr string) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bsZ6BRC4uKI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -133,7 +133,7 @@ func main() {
|
||||
func GetInternalIp() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fxnna_LLD9u)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -165,7 +165,7 @@ func main() {
|
||||
func GetIps() []string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/NUFfcEmukx1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -195,7 +195,7 @@ func main() {
|
||||
func GetMacAddrs() []string {
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Rq9UUBS_Xp1)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -239,7 +239,7 @@ type PublicIpInfo struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/YDxIfozsRHR)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -269,7 +269,7 @@ func main() {
|
||||
func GetRequestPublicIp(req *http.Request) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/kxU-YDc_eBo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -307,7 +307,7 @@ func main() {
|
||||
func IsPublicIP(IP net.IP) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nmktSQpJZnn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -344,7 +344,7 @@ func main() {
|
||||
func IsInternalIP(IP net.IP) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sYGhXbgO4Cb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -388,7 +388,7 @@ type HttpRequest struct {
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jUSgynekH7G)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -445,7 +445,7 @@ func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
|
||||
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jUSgynekH7G)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -476,7 +476,7 @@ func main() {
|
||||
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jUSgynekH7G)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -530,7 +530,7 @@ func main() {
|
||||
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jUSgynekH7G)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -584,7 +584,7 @@ func main() {
|
||||
func StructToUrlValues(targetStruct any) url.Values
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pFqMkM40w9z)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -624,7 +624,9 @@ func main() {
|
||||
|
||||
### <span id="HttpGet">HttpGet</span>
|
||||
|
||||
<p>发送http get请求。(已废弃:使用SendRequest)</p>
|
||||
<p>发送http get请求。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`SendRequest`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -666,7 +668,9 @@ func main() {
|
||||
|
||||
### <span id="HttpPost">HttpPost</span>
|
||||
|
||||
<p>发送http post请求。(已废弃:使用SendRequest)</p>
|
||||
<p>发送http post请求。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`SendRequest`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -713,7 +717,9 @@ func main() {
|
||||
|
||||
### <span id="HttpPut">HttpPut</span>
|
||||
|
||||
<p>发送http put请求。(已废弃:使用SendRequest)</p>
|
||||
<p>发送http put请求。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`SendRequest`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -763,7 +769,9 @@ func main() {
|
||||
|
||||
### <span id="HttpDelete">HttpDelete</span>
|
||||
|
||||
<p>发送http delete请求。(已废弃:使用SendRequest)</p>
|
||||
<p>发送http delete请求。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`SendRequest`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -802,7 +810,9 @@ func main() {
|
||||
|
||||
### <span id="HttpPatch">HttpPatch</span>
|
||||
|
||||
<p>发送http patch请求。(已废弃:使用SendRequest)</p>
|
||||
<p>发送http patch请求。</p>
|
||||
|
||||
> ⚠️ 本函数已弃用,使用`SendRequest`代替。
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -966,7 +976,7 @@ func main() {
|
||||
func IsPingConnected(host string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/q8OzTijsA87)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -999,7 +1009,7 @@ func main() {
|
||||
func IsTelnetConnected(host string, port string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/yiLCGtQv_ZG)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
227
docs/api/packages/pointer.md
Normal file
227
docs/api/packages/pointer.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# Pointer
|
||||
|
||||
pointer 包支持一些指针类型的操作。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/pointer/pointer.go](https://github.com/duke-git/lancet/blob/main/pointer/pointer.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Of](#Of)
|
||||
- [Unwrap](#Unwrap)
|
||||
- [ExtractPointer](#ExtractPointer)
|
||||
- [UnwrapOr](#UnwrapOr)
|
||||
- [UnwrapOrDefault](#UnwrapOrDefault)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Of">Of</span>
|
||||
|
||||
<p>返回传入参数的指针值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Of[T any](v T) *T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HFd70x4DrMj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := pointer.Of(123)
|
||||
result2 := pointer.Of("abc")
|
||||
|
||||
fmt.Println(*result1)
|
||||
fmt.Println(*result2)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
|
||||
<p>返回传入指针指向的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Unwrap[T any](p *T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cgeu3g7cjWb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 123
|
||||
b := "abc"
|
||||
|
||||
result1 := pointer.Unwrap(&a)
|
||||
result2 := pointer.Unwrap(&b)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractPointer">ExtractPointer</span>
|
||||
|
||||
<p>返回传入interface的底层值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ExtractPointer(value any) any
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/D7HFjeWU2ZP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 1
|
||||
b := &a
|
||||
c := &b
|
||||
d := &c
|
||||
|
||||
result := pointer.ExtractPointer(d)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UnwrapOr">UnwrapOr</span>
|
||||
|
||||
<p>返回指针的值,如果指针为零值,则返回fallback。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
UnwrapOr[T any](p *T, fallback T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mmNaLC38W8C)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 123
|
||||
b := "abc"
|
||||
|
||||
var c *int
|
||||
var d *string
|
||||
|
||||
result1 := pointer.UnwrapOr(&a, 456)
|
||||
result2 := pointer.UnwrapOr(&b, "abc")
|
||||
result3 := pointer.UnwrapOr(c, 456)
|
||||
result4 := pointer.UnwrapOr(d, "def")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
// 456
|
||||
// def
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UnwrapOrDefault">UnwrapOrDefault</span>
|
||||
|
||||
<p>返回指针的值,如果指针为零值,则返回相应零值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
UnwrapOrDefault[T any](p *T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/pointer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 123
|
||||
b := "abc"
|
||||
|
||||
var c *int
|
||||
var d *string
|
||||
|
||||
result1 := pointer.UnwrapOrDefault(&a)
|
||||
result2 := pointer.UnwrapOrDefault(&b)
|
||||
result3 := pointer.UnwrapOrDefault(c)
|
||||
result4 := pointer.UnwrapOrDefault(d)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
// 0
|
||||
//
|
||||
}
|
||||
```
|
||||
551
docs/api/packages/random.md
Normal file
551
docs/api/packages/random.md
Normal file
@@ -0,0 +1,551 @@
|
||||
# Random
|
||||
|
||||
random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [RandBytes](#RandBytes)
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [RandFromGivenSlice](#RandFromGivenSlice)
|
||||
- [RandSliceFromGivenSlice](#RandSliceFromGivenSlice)
|
||||
- [RandUpper](#RandUpper)
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [RandSymbolChar](#RandSymbolChar)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandIntSlice](#RandIntSlice)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
- [RandFloat](#RandFloat)
|
||||
- [RandFloats](#RandFloats)
|
||||
- [RandStringSlice](#RandStringSlice)
|
||||
- [RandBool](#RandBool)
|
||||
- [RandBoolSlice](#RandBoolSlice)
|
||||
- [RandNumberOfLength](#RandNumberOfLength)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="RandBytes">RandBytes</span>
|
||||
|
||||
<p>生成随机字节切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandBytes(length int) []byte
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/EkiLESeXf8d)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randBytes := random.RandBytes(4)
|
||||
fmt.Println(randBytes)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandInt">RandInt</span>
|
||||
|
||||
<p>生成随机int, 范围[min, max)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandInt(min, max int) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pXyyAAI5YxD)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rInt := random.RandInt(1, 10)
|
||||
fmt.Println(rInt)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandString">RandString</span>
|
||||
|
||||
<p>生成给定长度的随机字符串,只包含字母(a-zA-Z)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandString(length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/W2xvRUXA7Mi)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr) //pGWsze
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFromGivenSlice">RandFromGivenSlice</span>
|
||||
|
||||
<p>从给定切片中随机生成元素。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandFromGivenSlice[T any](slice []T) T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/UrkWueF6yYo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nicknames := []string{"张三", "李四", "王五", "赵六", "钱七"}
|
||||
randElm := random.RandFromGivenSlice(nicknames)
|
||||
fmt.Println(randElm)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandSliceFromGivenSlice">RandSliceFromGivenSlice</span>
|
||||
|
||||
<p>从给定切片中生成长度为 num 的随机切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/68UikN9d6VT)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
|
||||
|
||||
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
|
||||
|
||||
fmt.Println(chosen3goods)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUpper">RandUpper</span>
|
||||
|
||||
<p>生成给定长度的随机大写字母字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandUpper(length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/29QfOh0DVuh)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/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>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/XJtZ471cmtI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/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>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/g4JWVpHsJcf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/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>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/19CEQvpx2jD)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandNumeralOrLetter(6)
|
||||
fmt.Println(randStr) //0aW7cQ
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandSymbolChar">RandSymbolChar</span>
|
||||
|
||||
<p>生成给定长度的随机符号字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandSymbolChar(length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Im6ZJxAykOm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandSymbolChar(6)
|
||||
fmt.Println(randStr) // 随机特殊字符字符串,例如: @#(_")
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UUIdV4">UUIdV4</span>
|
||||
|
||||
<p>生成UUID v4字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func UUIdV4() (string, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_Z9SFmr28ft)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uuid, err := random.UUIdV4()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(uuid)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandIntSlice">RandIntSlice</span>
|
||||
|
||||
<p>生成一个特定长度的随机int切片,数值范围[min, max)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GATTQ5xTEG8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[1 2 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||
|
||||
<p>生成一个特定长度的,数值不重复的随机int切片,数值范围[min, max)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandUniqueIntSlice(length, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uBkRSOz73Ec)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandUniqueIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloat">RandFloat</span>
|
||||
|
||||
<p>生成一个随机float64数值,可以指定精度。数值范围[min, max)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandFloat(min, max float64, precision int) float64
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zbD_tuobJtr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumber := random.RandFloat(1.0, 5.0, 2)
|
||||
fmt.Println(floatNumber) //2.14 (random number)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandFloats">RandFloats</span>
|
||||
|
||||
<p>生成一个特定长度的随机float64切片,可以指定数值精度。数值范围[min, max)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandFloats(n int, min, max float64, precision int) []float64
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/I3yndUQ-rhh)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
floatNumbers := random.RandFloats(5, 1.0, 5.0, 2)
|
||||
fmt.Println(floatNumber) //[3.42 3.99 1.3 2.38 4.23] (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandStringSlice">RandStringSlice</span>
|
||||
|
||||
<p>生成随机字符串slice. 字符串类型需要是以下几种或者它们的组合: random.Numeral, random.LowwerLetters, random.UpperLetters random.Letters, random.SymbolChars, random.AllChars。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandStringSlice(charset string, sliceLen, strLen int) []string
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2_-PiDv3tGn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
strs := random.RandStringSlice(random.Letters, 4, 6)
|
||||
fmt.Println(strs)
|
||||
|
||||
// output random string slice like below:
|
||||
//[CooSMq RUFjDz FAeMPf heRyGv]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandBool">RandBool</span>
|
||||
|
||||
<p>生成随机bool值(true or false)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandBool() bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/to6BLc26wBv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandBool()
|
||||
fmt.Println(result) // true or false (random)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandBoolSlice">RandBoolSlice</span>
|
||||
|
||||
<p>生成特定长度的随机bool slice。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandBoolSlice(length int) []bool
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/o-VSjPjnILI)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandBoolSlice(2)
|
||||
fmt.Println(result) // [true false] (random)
|
||||
}
|
||||
```
|
||||
### <span id="RandNumberOfLength">RandNumberOfLength</span>
|
||||
|
||||
<p>生成指定长度的随机数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumberOfLength(len int) int
|
||||
```
|
||||
|
||||
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i := random.RandNumberOfLength(2)
|
||||
fmt.Println(i) // 21 (random number of length 2)
|
||||
}
|
||||
```
|
||||
418
docs/api/packages/retry.md
Normal file
418
docs/api/packages/retry.md
Normal file
@@ -0,0 +1,418 @@
|
||||
# Retry
|
||||
|
||||
retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Context](#Context)
|
||||
- [Retry](#Retry)
|
||||
- [RetryFunc](#RetryFunc)
|
||||
- [RetryDuration](#RetryDuration)
|
||||
- [RetryTimes](#RetryTimes)
|
||||
- [BackoffStrategy](#BackoffStrategy)
|
||||
- [RetryWithCustomBackoff](#RetryWithCustomBackoff)
|
||||
- [RetryWithLinearBackoff](#RetryWithLinearBackoff)
|
||||
- [RetryWithExponentialWithJitterBackoff](#RetryWithExponentialWithJitterBackoff)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Context">Context</span>
|
||||
|
||||
<p>设置重试context参数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Context(ctx context.Context)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xnAOOXv9GkS)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"lancet-demo/retry"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
|
||||
|
||||
retry.Retry(increaseNumber,
|
||||
duration,
|
||||
retry.Context(ctx),
|
||||
)
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryFunc">RetryFunc</span>
|
||||
|
||||
<p>被重试执行的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type RetryFunc func() error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nk2XRmagfVF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
var increaseNumber retry.RetryFunc = func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
|
||||
|
||||
err := retry.Retry(increaseNumber, duration)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryTimes">RetryTimes</span>
|
||||
|
||||
<p>设置重试次数,默认5</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RetryTimes(n uint)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ssfVeU2SwLO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// function main.main.func1 run failed after 2 times retry
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Retry">Retry</span>
|
||||
|
||||
<p>重试执行函数retryFunc,直到函数运行成功,或被context停止</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Retry(retryFunc RetryFunc, opts ...Option) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/nk2XRmagfVF)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
duration := retry.RetryWithLinearBackoff(time.Microsecond*50)
|
||||
|
||||
err := retry.Retry(increaseNumber, duration)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BackoffStrategy">BackoffStrategy</span>
|
||||
|
||||
<p>定义计算退避间隔的方法的接口。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
// BackoffStrategy is an interface that defines a method for calculating backoff intervals.
|
||||
type BackoffStrategy interface {
|
||||
// CalculateInterval returns the time.Duration after which the next retry attempt should be made.
|
||||
CalculateInterval() time.Duration
|
||||
}
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
type ExampleCustomBackoffStrategy struct {
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||
return c.interval + 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&示例CustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryWithCustomBackoff">RetryWithCustomBackoff</span>
|
||||
|
||||
<p>设置自定义退避策略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jIm_o2vb5Y4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
type ExampleCustomBackoffStrategy struct {
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||
return c.interval + 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&示例CustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="RetryWithLinearBackoff">RetryWithLinearBackoff</span>
|
||||
|
||||
<p>设置线性策略退避。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RetryWithLinearBackoff(interval time.Duration) Option
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/PDet2ZQZwcB)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryWithLinearBackoff(time.Microsecond*50))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="RetryWithExponentialWithJitterBackoff">RetryWithExponentialWithJitterBackoff</span>
|
||||
|
||||
<p>设置指数策略退避。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RetryWithExponentialWithJitterBackoff(interval time.Duration, base uint64, maxJitter time.Duration) Option
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xp1avQmn16X)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryWithExponentialWithJitterBackoff(time.Microsecond*50, 2, time.Microsecond*25))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
# Stream
|
||||
|
||||
Stream 流,该包仅验证简单 stream 实现,功能有限。
|
||||
Stream流,该包仅验证简单stream实现,功能有限。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -48,6 +48,8 @@ import (
|
||||
- [NoneMatch](#NoneMatch)
|
||||
- [Count](#Count)
|
||||
- [ToSlice](#ToSlice)
|
||||
- [IndexOf](#IndexOf)
|
||||
- [LastIndexOf](#LastIndexOf)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -63,7 +65,7 @@ import (
|
||||
func Of[T any](elems ...T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jI6_iZZuVFE)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -93,7 +95,7 @@ func main() {
|
||||
func FromSlice[T any](source []T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wywTO0XZtI4)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -123,7 +125,7 @@ func main() {
|
||||
func FromChannel[T any](source <-chan T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9TZYugGMhXZ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -161,7 +163,7 @@ func main() {
|
||||
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9Ex1-zcg-B-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -190,7 +192,7 @@ func main() {
|
||||
func Generate[T any](generator func() func() (item T, ok bool)) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/rkOWL1yA3j9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -230,7 +232,7 @@ func main() {
|
||||
func Concat[T any](a, b stream[T]) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HM4OlYk_OUC)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -263,7 +265,7 @@ func main() {
|
||||
func (s stream[T]) Distinct() stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/eGkOSrm64cB)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -297,7 +299,7 @@ func main() {
|
||||
func (s stream[T]) Filter(predicate func(item T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/MFlSANo-buc)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -331,7 +333,7 @@ func main() {
|
||||
func (s stream[T]) Map(mapper func(item T) T) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/OtNQUImdYko)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -365,7 +367,7 @@ func main() {
|
||||
func (s stream[T]) Peek(consumer func(item T)) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/u1VNzHs6cb2)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -402,7 +404,7 @@ func main() {
|
||||
func (s stream[T]) Skip(n int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fNdHbqjahum)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -441,7 +443,7 @@ func main() {
|
||||
func (s stream[T]) Limit(maxSize int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qsO4aniDcGf)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -480,7 +482,7 @@ func main() {
|
||||
func (s stream[T]) Reverse() stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/A8_zkJnLHm4)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -510,7 +512,7 @@ func main() {
|
||||
func (s stream[T]) Range(start, end int) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/indZY5V2f4j)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -549,7 +551,7 @@ func main() {
|
||||
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/XXtng5uonFj)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -581,7 +583,7 @@ func main() {
|
||||
func (s stream[T]) ForEach(action func(item T))
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Dsm0fPqcidk)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -614,7 +616,7 @@ func main() {
|
||||
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6uzZjq_DJLU)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -646,7 +648,7 @@ func main() {
|
||||
func (s stream[T]) FindFirst() (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9xEf0-6C1e3)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -678,7 +680,7 @@ func main() {
|
||||
func (s stream[T]) FindLast() (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/WZD2rDAW-2h)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -710,7 +712,7 @@ func main() {
|
||||
func (s stream[T]) Max(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/fm-1KOPtGzn)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -734,7 +736,7 @@ func main() {
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>根据提供的less函数返回stream的最小元素。less函数: a < b</p>
|
||||
<p>根据提供的less函数返回stream的最小元素。less函数: a < b</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -742,7 +744,7 @@ func main() {
|
||||
func (s stream[T]) Min(less func(a, b T) bool) (T, bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/vZfIDgGNRe_0)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -774,7 +776,7 @@ func main() {
|
||||
func (s stream[T]) AllMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/V5TBpVRs-Cx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -812,7 +814,7 @@ func main() {
|
||||
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/PTCnWn4OxSn)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -850,7 +852,7 @@ func main() {
|
||||
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iWS64pL1oo3)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -888,7 +890,7 @@ func main() {
|
||||
func (s stream[T]) Count() int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/r3koY6y_Xo-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -919,7 +921,7 @@ func main() {
|
||||
func (s stream[T]) ToSlice() []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jI6_iZZuVFE)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -938,3 +940,69 @@ func main() {
|
||||
// [1 2 3]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IndexOf">IndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的第一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) IndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.IndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.IndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LastIndexOf">LastIndexOf</span>
|
||||
|
||||
<p>返回在stream中找到值的最后一个匹配项的索引,如果找不到值,则返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s Stream[T]) LastIndexOf(target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.FromSlice([]int{1, 2, 3, 2})
|
||||
|
||||
result1 := s.LastIndexOf(0, func(a, b int) bool { return a == b })
|
||||
result2 := s.LastIndexOf(2, func(a, b int) bool { return a == b })
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
@@ -1,11 +1,13 @@
|
||||
# Field
|
||||
# Structs
|
||||
|
||||
Field 包封装了一个抽象的`Field`结构体,提供了操作`struct`属性的相关函数
|
||||
structs 包封装了一个抽象的`Struct`结构体,提供了操作`struct`的相关函数
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/structs/struct.go](https://github.com/duke-git/lancet/blob/main/structs/struct.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/structs/field.go](https://github.com/duke-git/lancet/blob/main/structs/field.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -21,6 +23,12 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录:
|
||||
|
||||
- [New](#New)
|
||||
- [ToMap](#ToMap)
|
||||
- [Fields](#Fields)
|
||||
- [Field](#Field)
|
||||
- [IsStruct](#IsStruct)
|
||||
- [Tag](#Tag)
|
||||
- [Name](#Name)
|
||||
- [Value](#Value)
|
||||
@@ -29,18 +37,192 @@ import (
|
||||
- [IsExported](#IsExported)
|
||||
- [IsZero](#IsZero)
|
||||
- [IsSlice](#IsSlice)
|
||||
|
||||
> 注意:由于`Field`继承于`Struct`,所以同样拥有`Struct`所有方法,如下:
|
||||
|
||||
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)
|
||||
- [Fields](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)
|
||||
- [Field](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Field)
|
||||
- [IsStruct](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)
|
||||
- [IsTargetType](#IsTargetType)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## API 文档:
|
||||
|
||||
### <span id="New">New</span>
|
||||
|
||||
<p>`Struct`结构体的构造函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func New(value any, tagName ...string) *Struct
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
// to do something
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToMap">ToMap</span>
|
||||
|
||||
<p>将一个合法的struct对象转换为map[string]any</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *Struct) ToMap() (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>除此之外,提供一个便捷的静态方法 ToMap</b>
|
||||
|
||||
```go
|
||||
func ToMap(v any) (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s1 := structs.New(p1)
|
||||
m1, _ := s1.ToMap()
|
||||
|
||||
fmt.Println(m1)
|
||||
|
||||
// 如果不需要Struct更多的方法,可以直接使用ToMap
|
||||
m2, _ := structs.ToMap(p1)
|
||||
|
||||
fmt.Println(m2)
|
||||
|
||||
// Output:
|
||||
// map[name:11]
|
||||
// map[name:11]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Fields">Fields</span>
|
||||
|
||||
<p>获取一个struct对象的属性列表</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *Struct) Fields() []*Field
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
fields := s.Fields()
|
||||
|
||||
fmt.Println(len(fields))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Field">Field</span>
|
||||
|
||||
<p>根据属性名获取一个struct对象的属性</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *Struct) Field(name string) *Field
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
f := s.Field("Name")
|
||||
|
||||
fmt.Println(f.Value())
|
||||
|
||||
// Output:
|
||||
// 11
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsStruct">IsStruct</span>
|
||||
|
||||
<p>判断是否为一个合法的struct对象</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (s *Struct) IsStruct() bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
|
||||
fmt.Println(s.IsStruct())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Tag">Tag</span>
|
||||
|
||||
<p>获取`Field`的`Tag`,默认的tag key是json</p>
|
||||
@@ -350,4 +532,45 @@ func main() {
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsTargetType">IsTargetType</span>
|
||||
|
||||
<p>判断属性是否是目标类型</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (f *Field) IsTargetType(targetType reflect.Kind) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(n.IsTargetType(reflect.String))
|
||||
fmt.Println(a.IsTargetType(reflect.Slice))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -49,6 +49,7 @@ import (
|
||||
- [StringToBytes](#StringToBytes)
|
||||
- [BytesToString](#BytesToString)
|
||||
- [IsBlank](#IsBlank)
|
||||
- [IsNotBlank](#IsNotBlank)
|
||||
- [HasPrefixAny](#HasPrefixAny)
|
||||
- [HasSuffixAny](#HasSuffixAny)
|
||||
- [IndexOffset](#IndexOffset)
|
||||
@@ -59,10 +60,20 @@ import (
|
||||
- [ContainsAll](#ContainsAll)
|
||||
- [ContainsAny](#ContainsAny)
|
||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||
- [SubInBetween](#SubInBetween)
|
||||
- [HammingDistance](#HammingDistance)
|
||||
- [Concat](#Concat)
|
||||
- [Ellipsis](#Ellipsis)
|
||||
- [Shuffle](#Shuffle)
|
||||
- [Rotate](#Rotate)
|
||||
- [TemplateReplace](#TemplateReplace)
|
||||
- [RegexMatchAllGroups](#RegexMatchAllGroups)
|
||||
- [ExtractContent](#ExtractContent)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation 文档
|
||||
## 文档
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
@@ -74,7 +85,7 @@ import (
|
||||
func After(s, char string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/RbCOQqCDA7m)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -114,7 +125,7 @@ func main() {
|
||||
func AfterLast(s, char string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/1TegARrb8Yn)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -154,7 +165,7 @@ func main() {
|
||||
func Before(s, char string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/JAWTZDS4F5w)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -191,7 +202,7 @@ func main() {
|
||||
func BeforeLast(s, char string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pJfXXAoG_Te)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -228,7 +239,7 @@ func main() {
|
||||
func CamelCase(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9eXP3tn2tUy)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -263,7 +274,7 @@ func main() {
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dcZM9Oahw-Y)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -298,7 +309,7 @@ func main() {
|
||||
func UpperKebabCase(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zDyKNneyQXk)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -333,7 +344,7 @@ func main() {
|
||||
func Capitalize(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/2OAjgbmAqHZ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -368,7 +379,7 @@ func main() {
|
||||
func IsString(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/IOgq7oF9ERm)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -408,7 +419,7 @@ func main() {
|
||||
func LowerFirst(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/CbzAyZmtJwL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -442,7 +453,7 @@ func main() {
|
||||
func UpperFirst(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sBbBxRbs8MM)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -476,7 +487,7 @@ func main() {
|
||||
func Pad(source string, size int, padStr string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/NzImQq-VF8q)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -521,7 +532,7 @@ func main() {
|
||||
func PadEnd(source string, size int, padStr string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/9xP8rN0vz--)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -567,7 +578,7 @@ func main() {
|
||||
func PadStart(source string, size int, padStr string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xpTfzArDfvT)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -613,7 +624,7 @@ func main() {
|
||||
func Reverse(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/adfwalJiecD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -644,7 +655,7 @@ func main() {
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tgzQG11qBuN)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -676,10 +687,10 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
func UpperSnakeCase(s string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/4COPHpnLx38)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -714,7 +725,7 @@ func main() {
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Us-ySSbWh-3)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -755,7 +766,7 @@ func main() {
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/q3sM6ehnPDp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -798,7 +809,7 @@ func main() {
|
||||
func Wrap(str string, wrapWith string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/KoZOlZDDt9y)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -825,7 +836,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
|
||||
<p>用另一个字符串解开包裹一个字符串。</p>
|
||||
|
||||
@@ -835,7 +846,7 @@ func main() {
|
||||
func Unwrap(str string, wrapToken string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Ec2q4BzCpG-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -875,7 +886,7 @@ func main() {
|
||||
func SplitWords(s string) []string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/KLiX4WiysMM)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -918,7 +929,7 @@ func main() {
|
||||
func WordCount(s string) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bj7_odx3vRf)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -961,7 +972,7 @@ func main() {
|
||||
func RemoveNonPrintable(str string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/og47F5x_jTZ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -992,7 +1003,7 @@ func main() {
|
||||
func StringToBytes(str string) (b []byte)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7OyFBrf9AxA)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1022,7 +1033,7 @@ func main() {
|
||||
func BytesToString(bytes []byte) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6c68HRvJecH)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1051,7 +1062,7 @@ func main() {
|
||||
func IsBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/6zXRH_c0Qd3)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1075,6 +1086,45 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsNotBlank">IsNotBlank</span>
|
||||
|
||||
<p>Checks if a string is not whitespace or not empty.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsNotBlank(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/e_oJW0RAquA)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.IsNotBlank("")
|
||||
result2 := strutil.IsNotBlank(" ")
|
||||
result3 := strutil.IsNotBlank("\t\v\f\n")
|
||||
result4 := strutil.IsNotBlank(" 中文")
|
||||
result5 := strutil.IsNotBlank(" world ")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HasPrefixAny">HasPrefixAny</span>
|
||||
|
||||
<p>检查字符串是否以指定字符串数组中的任何一个开头。</p>
|
||||
@@ -1085,7 +1135,7 @@ func main() {
|
||||
func HasPrefixAny(str string, prefixes []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8UUTl2C5slo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1116,7 +1166,7 @@ func main() {
|
||||
func HasSuffixAny(str string, suffixes []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/sKWpCQdOVkx)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1147,7 +1197,7 @@ func main() {
|
||||
func IndexOffset(str string, substr string, idxFrom int) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qZo4lV2fomB)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1189,7 +1239,7 @@ func main() {
|
||||
func ReplaceWithMap(str string, replaces map[string]string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/h3t7CNj2Vvu)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1222,7 +1272,7 @@ func main() {
|
||||
func Trim(str string, characterMask ...string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Y0ilP0NRV3j)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1259,7 +1309,7 @@ func main() {
|
||||
func SplitAndTrim(str, delimiter string, characterMask ...string) []string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZNL6o4SkYQ7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1292,7 +1342,7 @@ func main() {
|
||||
func HideString(origin string, start, end int, replaceChar string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pzbaIVCTreZ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1331,7 +1381,7 @@ func main() {
|
||||
func ContainsAll(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/KECtK2Os4zq)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1364,7 +1414,7 @@ func main() {
|
||||
func ContainsAny(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dZGSSMB3LXE)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1400,7 +1450,7 @@ func main() {
|
||||
func RemoveWhiteSpace(str string, repalceAll bool) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/HzLC9vsTwkf)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1422,3 +1472,291 @@ func main() {
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SubInBetween">SubInBetween</span>
|
||||
|
||||
<p>获取字符串中指定的起始字符串start和终止字符串end直接的子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SubInBetween(str string, start string, end string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/EDbaRvjeNsv)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "abcde"
|
||||
|
||||
result1 := strutil.SubInBetween(str, "", "de")
|
||||
result2 := strutil.SubInBetween(str, "a", "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// bc
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HammingDistance">HammingDistance</span>
|
||||
|
||||
<p>计算两个字符串之间的汉明距离。汉明距离是指对应符号不同的位置数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HammingDistance(a, b string) (int, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/glNdQEA9HUi)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
result1, _ := strutil.HammingDistance("de", "de")
|
||||
result2, _ := strutil.HammingDistance("a", "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
|
||||
```
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>拼接字符串。length是拼接后字符串的长度,如果不确定则传0或负数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Concat(length int, str ...string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gD52SZHr4Kp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Concat(12, "Hello", " ", "World", "!")
|
||||
result2 := strutil.Concat(11, "Go", " ", "Language")
|
||||
result3 := strutil.Concat(0, "An apple a ", "day,", "keeps the", " doctor away")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// Hello World!
|
||||
// Go Language
|
||||
// An apple a day,keeps the doctor away
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Ellipsis">Ellipsis</span>
|
||||
|
||||
<p>将字符串截断到指定长度,并在末尾添加省略号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Ellipsis(str string, length int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/i1vbdQiQVRR)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Ellipsis("hello world", 5)
|
||||
result2 := strutil.Ellipsis("你好,世界!", 2)
|
||||
result3 := strutil.Ellipsis("😀😃😄😁😆", 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// hello...
|
||||
// 你好...
|
||||
// 😀😃😄...
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Shuffle">Shuffle</span>
|
||||
|
||||
<p>打乱给定字符串中的字符顺序。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Shuffle(str string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/iStFwBwyGY7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := strutil.Shuffle("hello")
|
||||
fmt.Println(result) //olelh (random order)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Rotate">Rotate</span>
|
||||
|
||||
<p>按指定的字符数旋转字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Rotate(str string, shift int) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Kf03iOeT5bd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Rotate("Hello", 0)
|
||||
result2 := strutil.Rotate("Hello", 1)
|
||||
result3 := strutil.Rotate("Hello", 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// Hello
|
||||
// oHell
|
||||
// loHel
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TemplateReplace">TemplateReplace</span>
|
||||
|
||||
<p>将模板字符串中的占位符替换为map中的相应值。占位符括在花括号中,例如 {key}。例如,模板字符串为“Hello, {name}!”,map为{"name": "world"},结果将为“Hello, world!”。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func TemplateReplace(template string, data map[string]string) string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/cXSuFvyZqv9)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
template := `Hello, my name is {name}, I'm {age} years old.`
|
||||
data := map[string]string{
|
||||
"name": "Bob",
|
||||
"age": "20",
|
||||
}
|
||||
|
||||
result := strutil.TemplateReplace(template, data)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// Hello, my name is Bob, I'm 20 years old.
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RegexMatchAllGroups">RegexMatchAllGroups</span>
|
||||
|
||||
<p>使用正则表达式匹配字符串中的所有子组并返回结果。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RegexMatchAllGroups(pattern, str string) [][]string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/JZiu0RXpgN-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pattern := `(\w+\.+\w+)@(\w+)\.(\w+)`
|
||||
str := "Emails: john.doe@example.com and jane.doe@example.com"
|
||||
|
||||
result := strutil.RegexMatchAllGroups(pattern, str)
|
||||
|
||||
fmt.Println(result[0])
|
||||
fmt.Println(result[1])
|
||||
|
||||
// Output:
|
||||
// [john.doe@example.com john.doe example com]
|
||||
// [jane.doe@example.com jane.doe example com]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExtractContent">ExtractContent</span>
|
||||
|
||||
<p>提取两个标记之间的内容。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ExtractContent(s, start, end string) []string
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
html := `<span>content1</span>aa<span>content2</span>bb<span>content1</span>`
|
||||
|
||||
result := strutil.ExtractContent(html, "<span>", "</span>")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [content1 content2 content1]
|
||||
}
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# System
|
||||
|
||||
system 包含 os, runtime, shell command 相关函数。
|
||||
system 包含 os, 运行time, shell command 相关函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -31,6 +31,11 @@ import (
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
- [StartProcess](#StartProcess)
|
||||
- [StopProcess](#StopProcess)
|
||||
- [KillProcess](#KillProcess)
|
||||
- [GetProcessInfo](#GetProcessInfo)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -46,7 +51,7 @@ import (
|
||||
func IsWindows() bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/zIflQgZNuxD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -64,7 +69,7 @@ func main() {
|
||||
|
||||
<p>检查当前操作系统是否是linux</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
<b>函数签名:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/zIflQgZNuxD)</span></b>
|
||||
|
||||
```go
|
||||
func IsLinux() bool
|
||||
@@ -94,7 +99,7 @@ func main() {
|
||||
func IsMac() bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/Mg4Hjtyq7Zc)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -118,7 +123,7 @@ func main() {
|
||||
func GetOsEnv(key string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/D88OYVCyjO-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -148,7 +153,7 @@ func main() {
|
||||
func SetOsEnv(key, value string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/D88OYVCyjO-)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -178,7 +183,7 @@ func main() {
|
||||
func RemoveOsEnv(key string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/fqyq4b3xUFQ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -216,7 +221,7 @@ func main() {
|
||||
func CompareOsEnv(key, comparedEnv string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/BciHrKYOHbp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -241,18 +246,19 @@ func main() {
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。
|
||||
函数的第二个参数是cmd选项控制参数,类型是func(*exec.Cmd),可以通过这个参数设置cmd属性。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/n-2fLyZef-4)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -262,7 +268,9 @@ import (
|
||||
|
||||
func main() {
|
||||
// linux or mac
|
||||
stdout, stderr, err := system.ExecCommand("ls")
|
||||
stdout, stderr, err := system.ExecCommand("ls", func(cmd *exec.Cmd) {
|
||||
cmd.Dir = "/tmp"
|
||||
})
|
||||
fmt.Println("std out: ", stdout)
|
||||
fmt.Println("std err: ", stderr)
|
||||
assert.Equal("", stderr)
|
||||
@@ -292,7 +300,7 @@ func main() {
|
||||
func GetOsBits() int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ml-_XH3gJbW)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -305,3 +313,132 @@ func main() {
|
||||
fmt.Println(osBit) // 32 or 64
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StartProcess">StartProcess</span>
|
||||
|
||||
<p>创建进程。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StartProcess(command string, args ...string) (int, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/5GVol6ryS_X)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pid, err := system.StartProcess("sleep", "2")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(pid)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="StopProcess">StopProcess</span>
|
||||
|
||||
<p>停止进程。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StopProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/jJZhRYGGcmD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pid, err := system.StartProcess("sleep", "10")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
err = system.StopProcess(pid)
|
||||
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="KillProcess">KillProcess</span>
|
||||
|
||||
<p>杀掉进程。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KillProcess(pid int) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/XKmvV-ExBWa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pid, err := system.StartProcess("sleep", "10")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
err = system.KillProcess(pid)
|
||||
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetProcessInfo">GetProcessInfo</span>
|
||||
|
||||
<p>根据进程id获取进程信息。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetProcessInfo(pid int) (*ProcessInfo, error)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/NQDVywEYYx7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pid, err := system.StartProcess("ls", "-a")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
processInfo, err := system.GetProcessInfo(pid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(processInfo)
|
||||
}
|
||||
```
|
||||
@@ -61,6 +61,7 @@ import (
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Tuple2">Tuple2</span>
|
||||
@@ -78,7 +79,7 @@ type Tuple2[A any, B any] struct {
|
||||
func NewTuple2[A any, B any](a A, b B) Tuple2[A, B]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/3sHVqBQpLYN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -106,7 +107,7 @@ func main() {
|
||||
func (t Tuple2[A, B]) Unbox() (A, B)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/0fD1qfCVwjm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -135,7 +136,7 @@ func main() {
|
||||
func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/4ncWJJ77Xio)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -163,7 +164,7 @@ func main() {
|
||||
func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/KBecr60feXb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -198,7 +199,7 @@ type Tuple3[A any, B any, C any] struct {
|
||||
func NewTuple3[A any, B any, C any](a A, b B c C) Tuple3[A, B, C]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/FtH2sdCLlCf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -226,7 +227,7 @@ func main() {
|
||||
func (t Tuple3[A, B, C]) Unbox() (A, B, C)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/YojLy-id1BS)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -239,7 +240,7 @@ import (
|
||||
func main() {
|
||||
t := tuple.NewTuple2(1, 0.1, "a")
|
||||
v1, v2, v3 := t.Unbox()
|
||||
fmt.Printf("%v %v %v", t.FieldA, t.FieldB, t.FieldC)
|
||||
fmt.Printf("%v %v %v", v1, v2, v3)
|
||||
|
||||
// Output: 1 0.1 a
|
||||
}
|
||||
@@ -255,7 +256,7 @@ func main() {
|
||||
func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/97NgmsTILfu)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -283,7 +284,7 @@ func main() {
|
||||
func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/bba4cpAa7KO)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -321,7 +322,7 @@ type Tuple4[A any, B any, C any, D any] struct {
|
||||
func NewTuple4[A any, B any, C any, D any](a A, b B, c C, d D) Tuple4[A, B, C, D]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/D2EqDz096tk)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -349,7 +350,7 @@ func main() {
|
||||
func (t Tuple4[A, B, C, D]) Unbox() (A, B, C, D)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ACj9YuACGgW)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -378,7 +379,7 @@ func main() {
|
||||
func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, C, D]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/PEmTYVK5hL4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -406,7 +407,7 @@ func main() {
|
||||
func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, []C, []D)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/rb8z4gyYSRN)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -445,7 +446,7 @@ type Tuple5[A any, B any, C any, D any, E any] struct {
|
||||
func NewTuple5[A any, B any, C any, D any, E any](a A, b B, c C, d D, e E) Tuple5[A, B, C, D, E]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/2WndmVxPg-r)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -473,7 +474,7 @@ func main() {
|
||||
func (t Tuple5[A, B, C, D, E]) Unbox() (A, B, C, D, E)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/GyIyZHjCvoS)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -502,7 +503,7 @@ func main() {
|
||||
func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) []Tuple5[A, B, C, D, E]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/fCAAJLMfBIP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -530,7 +531,7 @@ func main() {
|
||||
func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ([]A, []B, []C, []D, []E)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/gyl6vKfhqPb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -570,7 +571,7 @@ type Tuple6[A any, B any, C any, D any, E any, F any] struct {
|
||||
func NewTuple6[A any, B any, C any, D any, E any, F any](a A, b B, c C, d D, e E, f F) Tuple6[A, B, C, D, E, F]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/VjqcCwEJZbs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -598,7 +599,7 @@ func main() {
|
||||
func (t Tuple6[A, B, C, D, E, F]) Unbox() (A, B, C, D, E, F)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/FjIHV7lpxmW)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -627,7 +628,7 @@ func main() {
|
||||
func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, e []E, f []F) []Tuple6[A, B, C, D, E, F]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/oWPrnUYuFHo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -655,7 +656,7 @@ func main() {
|
||||
func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D, E, F]) ([]A, []B, []C, []D, []E, []F)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/l41XFqCyh5E)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -696,7 +697,7 @@ type Tuple7[A any, B any, C any, D any, E any, F any, G any] struct {
|
||||
func NewTuple7[A any, B any, C any, D any, E any, F any, G any](a A, b B, c C, d D, e E, f F, g G) Tuple7[A, B, C, D, E, F, G]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/dzAgv_Ezub9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -724,7 +725,7 @@ func main() {
|
||||
func (t Tuple7[A, B, C, D, E, F, G]) Unbox() (A, B, C, D, E, F, G)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/R9I8qeDk0zs)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -753,7 +754,7 @@ func main() {
|
||||
func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, d []D, e []E, f []F, g []G) []Tuple7[A, B, C, D, E, F, G]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/WUJuo897Egf)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -781,7 +782,7 @@ func main() {
|
||||
func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, B, C, D, E, F, G]) ([]A, []B, []C, []D, []E, []F, []G)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/hws_P1Fr2j3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -823,7 +824,7 @@ type Tuple8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
|
||||
func NewTuple8[A any, B any, C any, D any, E any, F any, G any, H any](a A, b B, c C, d D, e E, f F, g G, h H) Tuple8[A, B, C, D, E, F, G, H]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/YA9S0rz3dRz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -851,7 +852,7 @@ func main() {
|
||||
func (t Tuple8[A, B, C, D, E, F, G, H]) Unbox() (A, B, C, D, E, F, G, H)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/PRxLBBb4SMl)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -880,7 +881,7 @@ func main() {
|
||||
func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H) []Tuple8[A, B, C, D, E, F, G, H]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/8V9jWkuJfaQ)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -908,7 +909,7 @@ func main() {
|
||||
func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tuple8[A, B, C, D, E, F, G, H]) ([]A, []B, []C, []D, []E, []F, []G, []H)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/1SndOwGsZB4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -953,7 +954,7 @@ func NewTuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a
|
||||
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/yS2NGGtZpQr)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -981,7 +982,7 @@ func main() {
|
||||
func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unbox() (A, B, C, D, E, F, G, H, I)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/oFJFGTAuOa8)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1010,7 +1011,7 @@ func main() {
|
||||
func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I) []Tuple9[A, B, C, D, E, F, G, H, I]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/cgsL15QYnfz)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1038,7 +1039,7 @@ func main() {
|
||||
func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuples []Tuple9[A, B, C, D, E, F, G, H, I]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/91-BU_KURSA)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1084,7 +1085,7 @@ func NewTuple10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J
|
||||
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/799qqZg0hUv)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1115,7 +1116,7 @@ func main() {
|
||||
func (t Tuple10[A, B, C, D, E, F, G, H, I, J]) Unbox() (A, B, C, D, E, F, G, H, I, J)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/qfyx3x_X0Cu)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1134,8 +1135,6 @@ func main() {
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
|
||||
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1] {a}
|
||||
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1149,7 +1148,7 @@ func main() {
|
||||
func Zip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, j []J) []Tuple10[A, B, C, D, E, F, G, H, I, J]
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/YSR-2cXnrY4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1177,7 +1176,7 @@ func main() {
|
||||
func Unzip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](tuples []Tuple10[A, B, C, D, E, F, G, H, I, J]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I, []J)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/-taQB6Wfre_z)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -55,6 +55,15 @@ import (
|
||||
- [IsZeroValue](#IsZeroValue)
|
||||
- [IsGBK](#IsGBK)
|
||||
- [IsPrintable](#IsPrintable)
|
||||
- [IsBin](#IsBin)
|
||||
- [IsHex](#IsHex)
|
||||
- [IsBase64URL](#IsBase64URL)
|
||||
- [IsJWT](#IsJWT)
|
||||
- [IsVisa](#IsVisa)
|
||||
- [IsMasterCard](#IsMasterCard)
|
||||
- [IsAmericanExpress](#IsAmericanExpress)
|
||||
- [IsUnionPay](#IsUnionPay)
|
||||
- [IsChinaUnionPay](#IsChinaUnionPay)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -62,7 +71,7 @@ import (
|
||||
|
||||
### <span id="ContainChinese">ContainChinese</span>
|
||||
|
||||
<p>验证字符串是否包含中文字符</p>
|
||||
<p>验证字符串是否包含中文字符。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -70,7 +79,7 @@ import (
|
||||
func ContainChinese(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/7DpU0uElYeM)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -96,7 +105,7 @@ func main() {
|
||||
|
||||
### <span id="ContainLetter">ContainLetter</span>
|
||||
|
||||
<p>验证字符串是否包含至少一个英文字母</p>
|
||||
<p>验证字符串是否包含至少一个英文字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -104,7 +113,7 @@ func main() {
|
||||
func ContainLetter(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/lqFD04Yyewp)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -130,7 +139,7 @@ func main() {
|
||||
|
||||
### <span id="ContainLower">ContainLower</span>
|
||||
|
||||
<p>验证字符串是否包含至少一个英文小写字母</p>
|
||||
<p>验证字符串是否包含至少一个英文小写字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -138,7 +147,7 @@ func main() {
|
||||
func ContainLower(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/Srqi1ItvnAA)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -164,7 +173,7 @@ func main() {
|
||||
|
||||
### <span id="ContainUpper">ContainUpper</span>
|
||||
|
||||
<p>验证字符串是否包含至少一个英文大写字母.</p>
|
||||
<p>验证字符串是否包含至少一个英文大写字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -172,7 +181,7 @@ func main() {
|
||||
func ContainUpper(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/CmWeBEk27-z)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -198,7 +207,7 @@ func main() {
|
||||
|
||||
### <span id="IsAlpha">IsAlpha</span>
|
||||
|
||||
<p>验证字符串是否只包含英文字母</p>
|
||||
<p>验证字符串是否只包含英文字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -206,7 +215,7 @@ func main() {
|
||||
func IsAlpha(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/7Q5sGOz2izQ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -232,7 +241,7 @@ func main() {
|
||||
|
||||
### <span id="IsAllUpper">IsAllUpper</span>
|
||||
|
||||
<p>验证字符串是否全是大写英文字母</p>
|
||||
<p>验证字符串是否全是大写英文字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -240,7 +249,7 @@ func main() {
|
||||
func IsAllUpper(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ZHctgeK1n4Z)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -266,7 +275,7 @@ func main() {
|
||||
|
||||
### <span id="IsAllLower">IsAllLower</span>
|
||||
|
||||
<p>验证字符串是否全是小写英文字母</p>
|
||||
<p>验证字符串是否全是小写英文字母。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -274,7 +283,7 @@ func main() {
|
||||
func IsAllLower(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/GjqCnOfV6cM)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -308,7 +317,7 @@ func main() {
|
||||
func IsASCII(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/hfQNPLX0jNa)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -340,7 +349,7 @@ func main() {
|
||||
|
||||
### <span id="IsBase64">IsBase64</span>
|
||||
|
||||
<p>验证字符串是否是base64编码</p>
|
||||
<p>验证字符串是否是base64编码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -348,7 +357,7 @@ func main() {
|
||||
func IsBase64(base64 string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/sWHEySAt6hl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -371,7 +380,7 @@ func main() {
|
||||
|
||||
### <span id="IsChineseMobile">IsChineseMobile</span>
|
||||
|
||||
<p>验证字符串是否是中国手机号码</p>
|
||||
<p>验证字符串是否是中国手机号码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -379,7 +388,7 @@ func main() {
|
||||
func IsChineseMobile(mobileNum string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/GPYUlGTOqe3)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -402,7 +411,7 @@ func main() {
|
||||
|
||||
### <span id="IsChineseIdNum">IsChineseIdNum</span>
|
||||
|
||||
<p>验证字符串是否是中国身份证号码</p>
|
||||
<p>验证字符串是否是中国身份证号码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -410,7 +419,7 @@ func main() {
|
||||
func IsChineseIdNum(id string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/d8EWhl2UGDF)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -433,7 +442,7 @@ func main() {
|
||||
|
||||
### <span id="IsChinesePhone">IsChinesePhone</span>
|
||||
|
||||
<p>验证字符串是否是中国电话座机号码</p>
|
||||
<p>验证字符串是否是中国电话座机号码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -441,7 +450,7 @@ func main() {
|
||||
func IsChinesePhone(phone string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/RUD_-7YZJ3I)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -464,7 +473,7 @@ func main() {
|
||||
|
||||
### <span id="IsCreditCard">IsCreditCard</span>
|
||||
|
||||
<p>验证字符串是否是信用卡号码</p>
|
||||
<p>验证字符串是否是信用卡号码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -472,7 +481,7 @@ func main() {
|
||||
func IsCreditCard(creditCart string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/sNwwL6B0-v4)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -495,7 +504,7 @@ func main() {
|
||||
|
||||
### <span id="IsDns">IsDns</span>
|
||||
|
||||
<p>验证字符串是否是有效dns</p>
|
||||
<p>验证字符串是否是有效dns。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -503,7 +512,7 @@ func main() {
|
||||
func IsDns(dns string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/jlYApVLLGTZ)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -529,7 +538,7 @@ func main() {
|
||||
|
||||
### <span id="IsEmail">IsEmail</span>
|
||||
|
||||
<p>验证字符串是否是有效电子邮件地址</p>
|
||||
<p>验证字符串是否是有效电子邮件地址。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -537,7 +546,7 @@ func main() {
|
||||
func IsEmail(email string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/Os9VaFlT33G)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -560,7 +569,7 @@ func main() {
|
||||
|
||||
### <span id="IsEmptyString">IsEmptyString</span>
|
||||
|
||||
<p>验证字符串是否是空字符串</p>
|
||||
<p>验证字符串是否是空字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -568,7 +577,7 @@ func main() {
|
||||
func IsEmptyString(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/dpzgUjFnBCX)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -602,7 +611,7 @@ func main() {
|
||||
func IsInt(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/eFoIHbgzl-z)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -631,7 +640,7 @@ func main() {
|
||||
|
||||
### <span id="IsFloat">IsFloat</span>
|
||||
|
||||
<p>验证参数是否是浮点数((float32, float34)。</p>
|
||||
<p>验证参数是否是浮点数(float32, float34)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -639,7 +648,7 @@ func main() {
|
||||
func IsFloat(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/vsyG-sxr99_Z)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -668,7 +677,7 @@ func main() {
|
||||
|
||||
### <span id="IsNumber">IsNumber</span>
|
||||
|
||||
<p>验证参数是否是数字(integer or float)</p>
|
||||
<p>验证参数是否是数字(integer or float)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -676,7 +685,7 @@ func main() {
|
||||
func IsNumber(v any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/mdJHOAvtsvF)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -703,10 +712,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
<p>验证字符串是否是可以转换为整数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -714,7 +722,7 @@ func main() {
|
||||
func IsIntStr(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/jQRtFv-a0Rk)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -743,7 +751,7 @@ func main() {
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为浮点数</p>
|
||||
<p>验证字符串是否是可以转换为浮点数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -751,7 +759,7 @@ func main() {
|
||||
func IsFloatStr(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/LOYwS_Oyl7U)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -780,7 +788,7 @@ func main() {
|
||||
|
||||
### <span id="IsNumberStr">IsNumberStr</span>
|
||||
|
||||
<p>验证字符串是否是可以转换为数字</p>
|
||||
<p>验证字符串是否是可以转换为数字。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -788,7 +796,7 @@ func main() {
|
||||
func IsNumberStr(s string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/LzaKocSV79u)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -817,7 +825,7 @@ func main() {
|
||||
|
||||
### <span id="IsJSON">IsJSON</span>
|
||||
|
||||
<p>验证字符串是否是有效json</p>
|
||||
<p>验证字符串是否是有效json。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -825,7 +833,7 @@ func main() {
|
||||
func IsJSON(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/8Kip1Itjiil)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -854,7 +862,7 @@ func main() {
|
||||
|
||||
### <span id="IsRegexMatch">IsRegexMatch</span>
|
||||
|
||||
<p>验证字符串是否可以匹配正则表达式</p>
|
||||
<p>验证字符串是否可以匹配正则表达式。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -862,7 +870,7 @@ func main() {
|
||||
func IsRegexMatch(s, regex string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/z_XeZo_litG)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -883,11 +891,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsIp">IsIp</span>
|
||||
|
||||
<p>验证字符串是否是ip地址</p>
|
||||
<p>验证字符串是否是ip地址。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -895,7 +901,7 @@ func main() {
|
||||
func IsIp(ipstr string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/FgcplDvmxoD)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -924,7 +930,7 @@ func main() {
|
||||
|
||||
### <span id="IsIpV4">IsIpV4</span>
|
||||
|
||||
<p>验证字符串是否是ipv4地址</p>
|
||||
<p>验证字符串是否是ipv4地址。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -932,7 +938,7 @@ func main() {
|
||||
func IsIpV4(ipstr string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/zBGT99EjaIu)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -955,7 +961,7 @@ func main() {
|
||||
|
||||
### <span id="IsIpV6">IsIpV6</span>
|
||||
|
||||
<p>验证字符串是否是ipv6地址</p>
|
||||
<p>验证字符串是否是ipv6地址。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -963,7 +969,7 @@ func main() {
|
||||
func IsIpV6(ipstr string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/AHA0r0AzIdC)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -986,7 +992,7 @@ func main() {
|
||||
|
||||
### <span id="IsStrongPassword">IsStrongPassword</span>
|
||||
|
||||
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))</p>
|
||||
<p>验证字符串是否是强密码:(alpha(lower+upper) + number + special chars(!@#$%^&*()?><))。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -994,7 +1000,7 @@ func main() {
|
||||
func IsStrongPassword(password string, length int) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/QHdVcSQ3uDg)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1017,7 +1023,7 @@ func main() {
|
||||
|
||||
### <span id="IsUrl">IsUrl</span>
|
||||
|
||||
<p>验证字符串是否是url</p>
|
||||
<p>验证字符串是否是url。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1025,7 +1031,7 @@ func main() {
|
||||
func IsUrl(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/pbJGa7F98Ka)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1052,7 +1058,7 @@ func main() {
|
||||
### <span id="IsWeakPassword">IsWeakPassword</span>
|
||||
|
||||
<p>验证字符串是否是弱密码:(only letter or only number or letter + number)
|
||||
.</p>
|
||||
。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1060,7 +1066,7 @@ func main() {
|
||||
func IsWeakPassword(password string, length int) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/wqakscZH5gH)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1083,7 +1089,7 @@ func main() {
|
||||
|
||||
### <span id="IsZeroValue">IsZeroValue</span>
|
||||
|
||||
<p>判断传入的参数值是否为零值</p>
|
||||
<p>判断传入的参数值是否为零值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1091,7 +1097,7 @@ func main() {
|
||||
func IsZeroValue(value any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/UMrwaDCi_t4)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1128,7 +1134,7 @@ func main() {
|
||||
func IsGBK(data []byte) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/E2nt3unlmzP)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1150,7 +1156,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsPrintable">IsPrintable</span>
|
||||
|
||||
<p>检查字符串是否全部为可打印字符。</p>
|
||||
@@ -1161,7 +1166,7 @@ func main() {
|
||||
func IsPrintable(str string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/Pe1FE2gdtTP)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -1189,4 +1194,301 @@ func main() {
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
### <span id="IsBin">IsBin</span>
|
||||
|
||||
<p>检查字符串是否是有效的二进制数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsBin(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ogPeg2XJH4P)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsBin("0101")
|
||||
result2 := validator.IsBin("0b1101")
|
||||
result3 := validator.IsBin("b1101")
|
||||
result4 := validator.IsBin("1201")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsHex">IsHex</span>
|
||||
|
||||
<p>检查字符串是否是有效的十六进制数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsHex(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/M2qpHbEwmm7)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsHex("0xabcde")
|
||||
result2 := validator.IsHex("0XABCDE")
|
||||
result3 := validator.IsHex("cdfeg")
|
||||
result4 := validator.IsHex("0xcdfeg")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsBase64URL">IsBase64URL</span>
|
||||
|
||||
<p>检查字符串是否是有效的base64 url。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsBase64URL(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/vhl4mr8GZ6S)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ")
|
||||
result2 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ==")
|
||||
result3 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ=")
|
||||
result4 := validator.IsBase64URL("SAGsbG8sIHdvcmxkIQ===")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsJWT">IsJWT</span>
|
||||
|
||||
<p>检查字符串是否是有效的JSON Web Token (JWT)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsJWT(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/R6Op7heJbKI)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibWVzc2FnZSI6IlB1dGluIGlzIGFic29sdXRlIHNoaXQiLCJpYXQiOjE1MTYyMzkwMjJ9.wkLWA5GtCpWdxNOrRse8yHZgORDgf8TpJp73WUQb910")
|
||||
result2 := validator.IsJWT("abc")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsVisa">IsVisa</span>
|
||||
|
||||
<p>检查字符串是否是有效的visa卡号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsVisa(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/SdS2keOyJsl)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsVisa("4111111111111111")
|
||||
result2 := validator.IsVisa("123")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsMasterCard">IsMasterCard</span>
|
||||
|
||||
<p>检查字符串是否是有效的MasterCard卡号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsMasterCard(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/CwWBFRrG27b)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsMasterCard("5425233430109903")
|
||||
result2 := validator.IsMasterCard("4111111111111111")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsAmericanExpress">IsAmericanExpress</span>
|
||||
|
||||
<p>检查字符串是否是有效的American Express卡号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsAmericanExpress(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/HIDFpcOdpkd)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsAmericanExpress("342883359122187")
|
||||
result2 := validator.IsAmericanExpress("3782822463100007")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsUnionPay">IsUnionPay</span>
|
||||
|
||||
<p>检查字符串是否是有效的美国银联卡号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsUnionPay(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/CUHPEwEITDf)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsUnionPay("6221263430109903")
|
||||
result2 := validator.IsUnionPay("3782822463100007")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsChinaUnionPay">IsChinaUnionPay</span>
|
||||
|
||||
<p>检查字符串是否是有效的中国银联卡号。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsChinaUnionPay(v string) bool
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/yafpdxLiymu)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := validator.IsChinaUnionPay("6250941006528599")
|
||||
result2 := validator.IsChinaUnionPay("3782822463100007")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
@@ -35,9 +35,11 @@ import (
|
||||
- [XError_Info](#XError_Info)
|
||||
- [XError_Error](#XError_Error)
|
||||
- [TryUnwrap](#TryUnwrap)
|
||||
- [TryCatch](#TryCatch)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="New">New</span>
|
||||
@@ -58,7 +60,7 @@ type XError struct {
|
||||
func New(format string, args ...any) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/w4oWZts7q7f)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -87,7 +89,7 @@ func main() {
|
||||
func Wrap(cause error, message ...any) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/5385qT2dCi4)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -118,7 +120,7 @@ func main() {
|
||||
func Unwrap(err error) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/LKMLep723tu)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -153,24 +155,25 @@ func main() {
|
||||
func (e *XError) Wrap(cause error) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/RpjJ5u5sc97)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := xerror.New("wrong password")
|
||||
wrapErr := xerror.Wrap(err, "error")
|
||||
err1 := xerror.New("error").With("level", "high")
|
||||
err2 := err1.Wrap(errors.New("invalid username"))
|
||||
|
||||
fmt.Println(wrapErr.Error())
|
||||
fmt.Println(err2.Error())
|
||||
|
||||
// Output:
|
||||
// error: wrong password
|
||||
// error: invalid username
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,7 +187,7 @@ func main() {
|
||||
func (e *XError) Unwrap() error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/VUXJ8BST4c6)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -217,7 +220,7 @@ func main() {
|
||||
func (e *XError) With(key string, value any) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ow8UISXX_Dp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -249,7 +252,7 @@ func main() {
|
||||
func (e *XError) Id(id string) *XError
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/X6HBlsy58U9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -286,7 +289,7 @@ func main() {
|
||||
func (e *XError) Is(target error) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/X6HBlsy58U9)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -323,7 +326,7 @@ func main() {
|
||||
func (e *XError) Values() map[string]any
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/ow8UISXX_Dp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -356,7 +359,7 @@ func main() {
|
||||
func (e *XError) StackTrace() StackTrace
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/6FAvSQpa7pc)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -390,7 +393,7 @@ func main() {
|
||||
func (e *XError) Info() *errInfo
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/1ZX0ME1F-Jb)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -430,7 +433,7 @@ func main() {
|
||||
func (e *XError) Error() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/w4oWZts7q7f)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -459,7 +462,7 @@ func main() {
|
||||
func TryUnwrap[T any](val T, err error) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/acyZVkNZEeW)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -487,3 +490,56 @@ func main() {
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TryCatch">TryCatch</span>
|
||||
|
||||
<p>简单实现的java风格异常处理(try-catch-finally)。try catch不符合go错误处理风格,谨慎使用。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewTryCatch(ctx context.Context) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Try(tryFunc func(ctx context.Context) error) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Catch(catchFunc func(ctx context.Context, err error)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Finally(finallyFunc func(ctx context.Context)) *TryCatch
|
||||
|
||||
func (tc *TryCatch) Do()
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block">[运行](todo)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
calledFinally := false
|
||||
calledCatch := false
|
||||
|
||||
tc := xerror.NewTryCatch(context.Background())
|
||||
|
||||
tc.Try(func(ctx context.Context) error {
|
||||
return errors.New("error in try block")
|
||||
}).Catch(func(ctx context.Context, err error) {
|
||||
calledCatch = true
|
||||
// Error in try block at /path/xxx.go:{line_number} - Cause: error message
|
||||
// fmt.Println(err.Error())
|
||||
}).Finally(func(ctx context.Context) {
|
||||
calledFinally = true
|
||||
}).Do()
|
||||
|
||||
fmt.Println(calledCatch)
|
||||
fmt.Println(calledFinally)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
70
docs/en/api/overview.md
Normal file
70
docs/en/api/overview.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# API Overview
|
||||
|
||||
<b>Lancet (Lancet) is a powerful, comprehensive, efficient and reusable go language tool function library. Contains 25 packages, more than 600 utility functions. Functions cover string processing, slice processing, network, concurrency, encryption and decryption, file processing, time/date, stream processing, iterators, and more.</b>
|
||||
|
||||
|
||||
<style>
|
||||
.package-title {
|
||||
color: black;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.package-container {
|
||||
font-size: 16px;
|
||||
border: 1px dashed;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.package-cell {
|
||||
height: 40px;
|
||||
width: 140px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 40px;
|
||||
background: #059669;
|
||||
border: 1px solid;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<p class="package-title">Lancet function module</p>
|
||||
<div class="package-container">
|
||||
<div class="package-cell">algorithm</div>
|
||||
<div class="package-cell">compare</div>
|
||||
<div class="package-cell">concurrency</div>
|
||||
<div class="package-cell">condition</div>
|
||||
<div class="package-cell">convertor</div>
|
||||
<div class="package-cell">cryptor</div>
|
||||
<div class="package-cell">datastructure</div>
|
||||
<div class="package-cell">datetime</div>
|
||||
<div class="package-cell">fileutil</div>
|
||||
<div class="package-cell">formatter</div>
|
||||
<div class="package-cell">function</div>
|
||||
<div class="package-cell">iterator</div>
|
||||
<div class="package-cell">maputil</div>
|
||||
<div class="package-cell">mathutil</div>
|
||||
<div class="package-cell">netutil</div>
|
||||
<div class="package-cell">pointer</div>
|
||||
<div class="package-cell">random</div>
|
||||
<div class="package-cell">retry</div>
|
||||
<div class="package-cell">slice</div>
|
||||
<div class="package-cell">stream</div>
|
||||
<div class="package-cell">structs</div>
|
||||
<div class="package-cell">strutil</div>
|
||||
<div class="package-cell">system</div>
|
||||
<div class="package-cell">tuple</div>
|
||||
<div class="package-cell">validator</div>
|
||||
<div class="package-cell">xerror</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,15 +43,15 @@ import (
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func BubbleSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GNdv7Jg2Taj)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -91,15 +91,15 @@ func main() {
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func InsertionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/G5LJiWgJJW6)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -117,7 +117,7 @@ type people struct {
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
// Compare implements github.com/duke-git/lancet/constraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
@@ -154,15 +154,15 @@ func main() {
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func SelectionSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/oXovbkekayS)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -202,15 +202,15 @@ func main() {
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func ShellSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/3ibkszpJEu3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -250,15 +250,15 @@ func main() {
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
func QuickSort[T any](slice []T comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7Y7c1Elk3ax)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -298,15 +298,15 @@ func main() {
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func HeapSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/u6Iwa1VZS_f)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -346,15 +346,15 @@ func main() {
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
func MergeSort[T any](slice []T, comparator constraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ydinn9YzUJn)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -394,15 +394,15 @@ func main() {
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements constraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func CountSort[T any](slice []T, comparator constraints.Comparator) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tB-Umgm0DrP)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -448,10 +448,10 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/t6MeGiUSN47)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -499,10 +499,10 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator constraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Anozfr8ZLH3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -553,7 +553,7 @@ func main() {
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/IsS7rgn5s3x)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -596,7 +596,7 @@ func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/IsS7rgn5s3x)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
- [InDelta](#InDelta)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -39,7 +40,7 @@ import (
|
||||
|
||||
<p>Checks if two values are equal or not. (check both type and value)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/wmVxR-to4lz)</span></b>
|
||||
|
||||
```go
|
||||
func Equal(left, right any) bool
|
||||
@@ -88,7 +89,7 @@ func main() {
|
||||
|
||||
<p>Checks if two values are equal or not. (check value only)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/fxnna_LLD9u)</span></b>
|
||||
|
||||
```go
|
||||
func EqualValue(left, right any) bool
|
||||
@@ -127,7 +128,7 @@ func main() {
|
||||
|
||||
<p>Checks if value `left` less than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/cYh7FQQj0ne)</span></b>
|
||||
|
||||
```go
|
||||
func LessThan(left, right any) bool
|
||||
@@ -182,7 +183,7 @@ func main() {
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/9-NYDFZmIMp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -234,7 +235,7 @@ func main() {
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/e4T_scwoQzp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -277,7 +278,7 @@ func main() {
|
||||
|
||||
<p>Checks if value `left` less greater or equal than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/vx8mP0U8DFk)</span></b>
|
||||
|
||||
```go
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
@@ -324,3 +325,50 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="InDelta">InDelta</span>
|
||||
|
||||
<p>Checks if two values are equal or not within a delta.</p>
|
||||
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/TuDdcNtMkjo)</span></b>
|
||||
|
||||
```go
|
||||
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := InDelta(1, 1, 0)
|
||||
result2 := InDelta(1, 2, 0)
|
||||
|
||||
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
|
||||
result4 := InDelta(2.0/3.0, 0.0, 0.001)
|
||||
|
||||
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
|
||||
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -35,7 +35,6 @@ import (
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
## Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>Create a Channel pointer instance.</p>
|
||||
@@ -46,7 +45,7 @@ import (
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -70,7 +69,7 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qmWSy1NVF-Y)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -122,7 +121,7 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/2VYFMexEvTm)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -156,7 +155,7 @@ func main() {
|
||||
|
||||
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/k5N_ALVmYjE)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
@@ -200,7 +199,7 @@ func main() {
|
||||
```go
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
<b>Example: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7aB4KyMMp9A)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -233,7 +232,7 @@ func main() {
|
||||
|
||||
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/4J1zAWttP85)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
@@ -275,7 +274,7 @@ func main() {
|
||||
|
||||
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Wqz9rwioPww)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
@@ -318,7 +317,7 @@ func main() {
|
||||
|
||||
<p>Read a channel into another channel, will close until cancel context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/lm_GoS6aDjo)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
@@ -356,7 +355,7 @@ func main() {
|
||||
|
||||
<p>Create a channel whose values are taken from another channel with limit number.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/9Utt-1pDr2J)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
@@ -402,7 +401,7 @@ func main() {
|
||||
|
||||
<p>Split one chanel into two channels, until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
<b>Signature: <span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/3TQPKnCirrP)</span></b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user