mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 21:02:27 +08:00
Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb23c9eef8 | ||
|
|
b4cd0750e4 | ||
|
|
c960841491 | ||
|
|
5d6f9443fd | ||
|
|
5483380066 | ||
|
|
20b9e5353e | ||
|
|
1ec3a5af87 | ||
|
|
f31dde97b1 | ||
|
|
1718fd1cf1 | ||
|
|
513c0f829c | ||
|
|
c51a806aff | ||
|
|
3c16d50c4b | ||
|
|
21dd6ab8aa | ||
|
|
f5bf5183cc | ||
|
|
f28b5b2f92 | ||
|
|
79867e8a63 | ||
|
|
19939c2b03 | ||
|
|
bf7ffbfa8d | ||
|
|
cbb46f9cb4 | ||
|
|
3ad142d5d7 | ||
|
|
1a436aeb41 | ||
|
|
1af8fe8daf | ||
|
|
ae54c8db6f | ||
|
|
be942ec33e | ||
|
|
fafb59dad6 | ||
|
|
e36c01cac9 | ||
|
|
aa0afa8d94 | ||
|
|
18e0031e0e | ||
|
|
a5018c110c | ||
|
|
142deb83b2 | ||
|
|
ccc0188352 | ||
|
|
98dba83107 | ||
|
|
9c6aff9030 | ||
|
|
7fd9a94922 | ||
|
|
dd3b1f3aed | ||
|
|
f9dce592e8 | ||
|
|
c4b0967623 | ||
|
|
41613061d5 | ||
|
|
50ef63e27d | ||
|
|
3ae4a35d04 | ||
|
|
89ea0ee15a | ||
|
|
85399e23ed | ||
|
|
19a6f218e6 | ||
|
|
ccaf290b63 | ||
|
|
54745d512c | ||
|
|
39234d4722 | ||
|
|
4b4310265b | ||
|
|
d8a982bf07 | ||
|
|
0334a6f02b | ||
|
|
ae0c613b8e | ||
|
|
40b2560752 | ||
|
|
50c6e51393 | ||
|
|
1434e00712 | ||
|
|
76c941cff0 | ||
|
|
bb03f31a8b | ||
|
|
c939b26cb8 | ||
|
|
af480efa8c | ||
|
|
bc913d70b1 | ||
|
|
2bc87d8a6b | ||
|
|
2185c48eab | ||
|
|
59b5046a15 | ||
|
|
569902b528 | ||
|
|
78519088ab | ||
|
|
0c06cdb29f | ||
|
|
e8b8ff8927 | ||
|
|
06bd407a0c | ||
|
|
aa28479d11 | ||
|
|
bf7db0ded2 | ||
|
|
dd1cbf2ee3 | ||
|
|
9d5db895c9 | ||
|
|
6b09da6e6e | ||
|
|
b2b6710a1b | ||
|
|
e7ee2ed7cf | ||
|
|
1dfd1ec1d3 | ||
|
|
2e8834a2c1 | ||
|
|
df098392c2 | ||
|
|
5e318a78d2 | ||
|
|
d872d64fe0 | ||
|
|
c2257493a8 | ||
|
|
48c1f8ffad | ||
|
|
8a4c8218d2 | ||
|
|
92e1321d43 | ||
|
|
43fb907a81 | ||
|
|
f551c56921 | ||
|
|
85e1f711f5 | ||
|
|
ade567a620 | ||
|
|
a26e519a3f | ||
|
|
797e47363f | ||
|
|
20e1836eb7 | ||
|
|
5ae746a1f0 | ||
|
|
17d271190b | ||
|
|
310f8bd1e1 | ||
|
|
bf7a4e729f | ||
|
|
8d0ff28304 | ||
|
|
cee9bb538f | ||
|
|
eb59d02a08 | ||
|
|
10ed71a3a2 | ||
|
|
0e86244559 | ||
|
|
5ab150cad3 | ||
|
|
3546afe86c | ||
|
|
70077a6010 | ||
|
|
efdf36a817 | ||
|
|
e233788f69 | ||
|
|
957e6356f6 | ||
|
|
887eaa528a | ||
|
|
33126570bd | ||
|
|
5937183af0 | ||
|
|
4eaa0a39d5 | ||
|
|
18ec73839b | ||
|
|
89aef977a2 | ||
|
|
2612569500 | ||
|
|
acc8b59387 | ||
|
|
2878d389c8 | ||
|
|
3f8effb7a3 | ||
|
|
bd30855ae6 | ||
|
|
0efe2f57c3 | ||
|
|
8868fcabed | ||
|
|
dfbb9e30e0 | ||
|
|
b22be7cade | ||
|
|
87da6c6816 | ||
|
|
912f7052a3 | ||
|
|
e6f9b0954c | ||
|
|
98e861cf3b | ||
|
|
43e0ca7edf | ||
|
|
d491bea263 | ||
|
|
6f1feb96d6 | ||
|
|
d46d12f949 | ||
|
|
c6fc92a94c | ||
|
|
f4fa790b72 | ||
|
|
22798fd750 | ||
|
|
907df56f86 | ||
|
|
3dadfa234b | ||
|
|
f1d7154179 | ||
|
|
dc47b9ce98 | ||
|
|
6e626851cf | ||
|
|
c906d8aea7 | ||
|
|
e5e4e09308 | ||
|
|
7ed173849a | ||
|
|
24c0d95112 | ||
|
|
e9fed34729 | ||
|
|
9caefdb67d | ||
|
|
681d5b6bdf | ||
|
|
b0e9758e0d | ||
|
|
7b9a8a55e7 | ||
|
|
44ac82e8b8 | ||
|
|
c4b4cb1173 | ||
|
|
30d798366b | ||
|
|
3e9a2b5c59 | ||
|
|
1343683b08 |
2
.github/workflows/codecov.yml
vendored
2
.github/workflows/codecov.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
fetch-depth: 2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "1.16"
|
||||
go-version: "1.18"
|
||||
- name: Run coverage
|
||||
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
|
||||
- name: Upload coverage to Codecov
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -5,9 +5,5 @@ cryptor/*.txt
|
||||
fileutil/*.txt
|
||||
fileutil/*.zip
|
||||
fileutil/*.link
|
||||
fileutil/tempdir
|
||||
fileutil/unzip/*
|
||||
slice/testdata/*
|
||||
cryptor/*.pem
|
||||
docs/node_modules
|
||||
docs/.vitepress
|
||||
cryptor/*.pem
|
||||
791
README.md
791
README.md
@@ -3,14 +3,13 @@
|
||||
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||

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

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
[](https://codecov.io/gh/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/blob/v1/LICENSE)
|
||||
|
||||
[](https://github.com/duke-git/lancet/blob/main/LICENSE)
|
||||
</div>
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
@@ -20,516 +19,430 @@
|
||||
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
|
||||
## 特性
|
||||
|
||||
- 👏 全面、高效、可复用
|
||||
- 💪 400+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
|
||||
- 💅 只依赖 go 标准库
|
||||
- 🌍 所有导出函数单元测试覆盖率 100%
|
||||
- 👏 全面、高效、可复用
|
||||
- 💪 250+常用go工具函数,支持string、slice、datetime、net、crypt...
|
||||
- 💅 只依赖go标准库
|
||||
- 🌍 所有导出函数单元测试覆盖率100%
|
||||
|
||||
## 安装
|
||||
### Note:
|
||||
1. <b>对于使用go1.18及以上的用户,建议安装v2.x.x。 因为v2.x.x用go1.18的泛型重写了大部分函数。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet
|
||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用go1.18以下版本的用户,必须安装v1.x.x。目前最新的v1版本是v1.2.9。</b>
|
||||
```go
|
||||
go get github.com/duke-git/lancet@v1.2.9 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
```
|
||||
|
||||
## 用法
|
||||
|
||||
lancet 是以包的结构组织代码的,使用时需要导入相应的包名。例如:如果使用字符串相关函数,需要导入 strutil 包:
|
||||
lancet是以包的结构组织代码的,使用时需要导入相应的包名。例如:如果使用字符串相关函数,需要导入strutil包:
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/strutil"
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
```
|
||||
|
||||
## 例子
|
||||
|
||||
此处以字符串工具函数 Reverse(逆序字符串)为例,需要导入 strutil 包:
|
||||
此处以字符串工具函数ReverseStr(逆序字符串)为例,需要导入strutil包:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/strutil"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := "hello"
|
||||
rs := strutil.Reverse(s)
|
||||
rs := strutil.ReverseStr(s)
|
||||
fmt.Println(rs) //olleh
|
||||
}
|
||||
```
|
||||
|
||||
## API 文档
|
||||
## API文档
|
||||
|
||||
### algorithm算法包实现一些基本算法。eg. sort, search.
|
||||
|
||||
### 1. compare包提供几个轻量级的类型比较函数。
|
||||
```go
|
||||
import "github.com/duke-git/lancet/compare"
|
||||
import "github.com/duke-git/lancet/v2/algorithm"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
- [BubbleSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BubbleSort)
|
||||
- [CountSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#CountSort)
|
||||
- [HeapSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#HeapSort)
|
||||
- [InsertionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#InsertionSort)
|
||||
- [MergeSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#MergeSort)
|
||||
- [QuickSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#QuickSort)
|
||||
- [SelectionSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#SelectionSort)
|
||||
- [ShellSort](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#ShellSort)
|
||||
- [BinarySearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinarySearch)
|
||||
- [BinaryIterativeSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BinaryIterativeSearch)
|
||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
|
||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
|
||||
|
||||
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#Equal)
|
||||
- [EqualValue](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#EqualValue)
|
||||
- [LessThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessThan)
|
||||
- [GreaterThan](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterThan)
|
||||
- [LessOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#LessOrEqual)
|
||||
- [GreaterOrEqual](https://github.com/duke-git/lancet/blob/v1/docs/compare_zh-CN.md#GreaterOrEqual)
|
||||
|
||||
### 2. convertor转换器包支持一些常见的数据类型转换。
|
||||
### convertor转换器包支持一些常见的数据类型转换。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/convertor"
|
||||
import "github.com/duke-git/lancet/v2/convertor"
|
||||
```
|
||||
#### 函数列表:
|
||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorHexToRGB)
|
||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ColorRGBToHex)
|
||||
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
|
||||
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
|
||||
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
|
||||
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
|
||||
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
|
||||
|
||||
### cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/cryptor"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbEncrypt)
|
||||
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesEcbDecrypt)
|
||||
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcEncrypt)
|
||||
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCbcDecrypt)
|
||||
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCtrCrypt)
|
||||
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbEncrypt)
|
||||
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesCfbDecrypt)
|
||||
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbEncrypt)
|
||||
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#AesOfbDecrypt)
|
||||
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdEncode)
|
||||
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Base64StdDecode)
|
||||
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbEncrypt)
|
||||
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesEcbDecrypt)
|
||||
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcEncrypt)
|
||||
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCbcDecrypt)
|
||||
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCtrCrypt)
|
||||
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbEncrypt)
|
||||
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesCfbDecrypt)
|
||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbEncrypt)
|
||||
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#DesOfbDecrypt)
|
||||
- [HmacMd5](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)
|
||||
- [HmacSha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)
|
||||
- [HmacSha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)
|
||||
- [HmacSha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)
|
||||
- [Md5String](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)
|
||||
- [Md5File](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)
|
||||
- [Sha1](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)
|
||||
- [Sha256](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)
|
||||
- [Sha512](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)
|
||||
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)
|
||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)
|
||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)
|
||||
|
||||
### datetime日期时间处理包,格式化日期,比较日期。
|
||||
|
||||
- [ColorHexToRGB](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorHexToRGB)
|
||||
- [ColorRGBToHex](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ColorRGBToHex)
|
||||
- [ToBool](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBool)
|
||||
- [ToBytes](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToBytes)
|
||||
- [ToChar](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChar)
|
||||
- [ToChannel](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToChannel)
|
||||
- [ToInt](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInt)
|
||||
- [ToJson](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToJson)
|
||||
- [ToString](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToString)
|
||||
- [StructToMap](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#StructToMap)
|
||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#EncodeByte)
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DecodeByte)
|
||||
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
|
||||
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties)
|
||||
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInterface)
|
||||
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#Utf8ToGbk)
|
||||
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#GbkToUtf8)
|
||||
### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/cryptor"
|
||||
import "github.com/duke-git/lancet/v2/datetime"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [AddDay](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddDay)
|
||||
- [AddHour](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddHour)
|
||||
- [AddMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddMinute)
|
||||
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)
|
||||
- [BeginOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfHour)
|
||||
- [BeginOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfDay)
|
||||
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfWeek)
|
||||
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMonth)
|
||||
- [BeginOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfYear)
|
||||
- [EndOfMinute](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMinute)
|
||||
- [EndOfHour](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfHour)
|
||||
- [EndOfDay](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfDay)
|
||||
- [EndOfWeek](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfWeek)
|
||||
- [EndOfMonth](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfMonth)
|
||||
- [EndOfYear](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#EndOfYear)
|
||||
- [GetNowDate](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDate)
|
||||
- [GetNowTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowTime)
|
||||
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)
|
||||
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNightTimestamp)
|
||||
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatTimeToStr)
|
||||
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#FormatStrToTime)
|
||||
- [NewUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnix)
|
||||
- [NewUnixNow](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewUnixNow)
|
||||
- [NewFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewFormat)
|
||||
- [NewISO8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NewISO8601)
|
||||
- [ToUnix](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToUnix)
|
||||
- [ToFormat](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)
|
||||
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)
|
||||
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)
|
||||
|
||||
- [AesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbEncrypt)
|
||||
- [AesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesEcbDecrypt)
|
||||
- [AesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcEncrypt)
|
||||
- [AesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCbcDecrypt)
|
||||
- [AesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCtrCrypt)
|
||||
- [AesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbEncrypt)
|
||||
- [AesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesCfbDecrypt)
|
||||
- [AesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbEncrypt)
|
||||
- [AesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#AesOfbDecrypt)
|
||||
- [Base64StdEncode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdEncode)
|
||||
- [Base64StdDecode](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Base64StdDecode)
|
||||
- [DesEcbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbEncrypt)
|
||||
- [DesEcbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesEcbDecrypt)
|
||||
- [DesCbcEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcEncrypt)
|
||||
- [DesCbcDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCbcDecrypt)
|
||||
- [DesCtrCrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCtrCrypt)
|
||||
- [DesCfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbEncrypt)
|
||||
- [DesCfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesCfbDecrypt)
|
||||
- [DesOfbEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbEncrypt)
|
||||
- [DesOfbDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#DesOfbDecrypt)
|
||||
- [HmacMd5](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5)
|
||||
- [HmacMd5WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacMd5WithBase64)
|
||||
md#HmacSha256WithBase64)
|
||||
- [HmacSha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1)
|
||||
- [HmacSha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha1WithBase64)
|
||||
- [HmacSha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor.md#HmacSha256)
|
||||
- [HmacSha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha256WithBase64)
|
||||
- [HmacSha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512)
|
||||
- [HmacSha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#HmacSha512WithBase64)
|
||||
- [Md5String](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5String)
|
||||
- [Md5StringWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5StringWithBase64)
|
||||
- [Md5Byte](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5Byte)
|
||||
- [Md5ByteWithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5ByteWithBase64)
|
||||
- [Md5File](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Md5File)
|
||||
- [Sha1](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1)
|
||||
- [Sha1WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha1WithBase64)
|
||||
- [Sha256](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256)
|
||||
- [Sha256WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha256WithBase64)
|
||||
- [Sha512](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512)
|
||||
- [Sha512WithBase64](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#Sha512WithBase64)
|
||||
- [GenerateRsaKey](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKey)
|
||||
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncrypt)
|
||||
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecrypt)
|
||||
- [GenerateRsaKeyPair](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#GenerateRsaKeyPair)
|
||||
- [RsaEncryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaEncryptOAEP)
|
||||
- [RsaDecryptOAEP](https://github.com/duke-git/lancet/blob/v1/docs/cryptor_zh-CN.md#RsaDecryptOAEP)
|
||||
|
||||
|
||||
### 4. datetime 日期时间处理包,格式化日期,比较日期。
|
||||
### fileutil包支持文件基本操作。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/datetime"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [AddDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddDay)
|
||||
- [AddHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddHour)
|
||||
- [AddMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddMinute)
|
||||
- [AddYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#AddYear)
|
||||
- [BeginOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMinute)
|
||||
- [BeginOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfHour)
|
||||
- [BeginOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfDay)
|
||||
- [BeginOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfWeek)
|
||||
- [BeginOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfMonth)
|
||||
- [BeginOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#BeginOfYear)
|
||||
- [EndOfMinute](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMinute)
|
||||
- [EndOfHour](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfHour)
|
||||
- [EndOfDay](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfDay)
|
||||
- [EndOfWeek](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfWeek)
|
||||
- [EndOfMonth](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfMonth)
|
||||
- [EndOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime.md#EndOfYear)
|
||||
- [GetNowDate](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDate)
|
||||
- [GetNowTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowTime)
|
||||
- [GetNowDateTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNowDateTime)
|
||||
- [GetZeroHourTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#GetNightTimestamp)
|
||||
- [FormatTimeToStr](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatTimeToStr)
|
||||
- [FormatStrToTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#FormatStrToTime)
|
||||
- [NewUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnix)
|
||||
- [NewUnixNow](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewUnixNow)
|
||||
- [NewFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewFormat)
|
||||
- [NewISO8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NewISO8601)
|
||||
- [ToUnix](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToUnix)
|
||||
- [ToFormat](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormat)
|
||||
- [ToFormatForTpl](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToFormatForTpl)
|
||||
- [ToIso8601](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#ToIso8601)
|
||||
- [IsLeapYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsLeapYear)
|
||||
- [BetweenSeconds](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#BetweenSeconds)
|
||||
- [DayOfYear](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#DayOfYear)
|
||||
- [IsWeekend](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#IsWeekend)
|
||||
- [NowDateOrTime](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#NowDateOrTime)
|
||||
- [Timestamp](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#Timestamp)
|
||||
- [TimestampMilli](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMilli)
|
||||
- [TimestampMicro](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampMicro)
|
||||
- [TimestampNano](https://github.com/duke-git/lancet/blob/v1/docs/datetime_zh-CN.md#TimestampNano)
|
||||
|
||||
### 5. fileutil 包支持文件基本操作。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/fileutil"
|
||||
import "github.com/duke-git/lancet/v2/fileutil"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ClearFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ClearFile)
|
||||
- [CreateFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateFile)
|
||||
- [CreateDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CreateDir)
|
||||
- [CopyFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CopyFile)
|
||||
- [FileMode](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileMode)
|
||||
- [MiMeType](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MiMeType)
|
||||
- [IsExist](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsExist)
|
||||
- [IsLink](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsLink)
|
||||
- [IsDir](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsDir)
|
||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ListFileNames)
|
||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#RemoveFile)
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Zip)
|
||||
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ZipAppendEntry)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#UnZip)
|
||||
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CurrentPath)
|
||||
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsZipFile)
|
||||
- [FileSize](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#FileSize)
|
||||
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MTime)
|
||||
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
|
||||
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile)
|
||||
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteCsvFile)
|
||||
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteStringToFile)
|
||||
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteBytesToFile)
|
||||
- [ReadFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFile)
|
||||
- [ClearFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ClearFile)
|
||||
- [CreateFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CreateFile)
|
||||
- [CopyFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CopyFile)
|
||||
- [FileMode](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#FileMode)
|
||||
- [MiMeType](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#MiMeType)
|
||||
- [IsExist](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsExist)
|
||||
- [IsLink](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsLink)
|
||||
- [IsDir](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#IsDir)
|
||||
- [ListFileNames](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ListFileNames)
|
||||
- [RemoveFile](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#RemoveFile)
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
|
||||
|
||||
### 6. formatter 格式化器包含一些数据格式化处理方法。
|
||||
### formatter格式化器包含一些数据格式化处理方法。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/formatter"
|
||||
import "github.com/duke-git/lancet/v2/formatter"
|
||||
```
|
||||
#### 函数列表:
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
|
||||
|
||||
|
||||
### function函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/function"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#After)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Before)
|
||||
- [Curry](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Curry)
|
||||
- [Compose](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Compose)
|
||||
- [Debounced](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Debounced)
|
||||
- [Delay](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Delay)
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
||||
|
||||
- [Comma](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Comma)
|
||||
- [Pretty](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#Pretty)
|
||||
- [PrettyToWriter](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#PrettyToWriter)
|
||||
- [DecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#DecimalBytes)
|
||||
- [BinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#BinaryBytes)
|
||||
- [ParseDecimalBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseDecimalBytes)
|
||||
- [ParseBinaryBytes](https://github.com/duke-git/lancet/blob/v1/docs/formatter_zh-CN.md#ParseBinaryBytes)
|
||||
|
||||
### 7. function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
### maputil包包括一些操作map的函数.
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/function"
|
||||
import "github.com/duke-git/lancet/v2/maputil"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Filter)
|
||||
- [Intersect](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Intersect)
|
||||
- [Keys](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Keys)
|
||||
- [Merge](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Merge)
|
||||
- [Minus](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Minus)
|
||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#After)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Before)
|
||||
- [Curry](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Curry)
|
||||
- [Compose](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Compose)
|
||||
- [Debounced](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Debounced)
|
||||
- [Delay](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Delay)
|
||||
- [Pipeline](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Pipeline)
|
||||
- [Schedule](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Schedule)
|
||||
- [Watcher](https://github.com/duke-git/lancet/blob/v1/docs/function_zh-CN.md#Watcher)
|
||||
|
||||
### 8. mathutil 包实现了一些数学计算的函数。
|
||||
### mathutil包实现了一些数学计算的函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/mathutil"
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
```
|
||||
|
||||
#### Function list:
|
||||
- [Average](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)
|
||||
- [Exponent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Exponent)
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Factorial)
|
||||
- [Max](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Max)
|
||||
- [Min](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Min)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
||||
|
||||
- [Exponent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Exponent)
|
||||
- [Fibonacci](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Fibonacci)
|
||||
- [Factorial](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Factorial)
|
||||
- [Percent](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Percent)
|
||||
- [RoundToFloat](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToFloat)
|
||||
- [RoundToString](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RoundToString)
|
||||
- [TruncRound](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#TruncRound)
|
||||
- [AngleToRadian](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#AngleToRadian)
|
||||
- [RadianToAngle](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#RadianToAngle)
|
||||
- [PointDistance](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#PointDistance)
|
||||
- [IsPrime](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#IsPrime)
|
||||
- [GCD](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#GCD)
|
||||
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#LCM)
|
||||
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Cos)
|
||||
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Sin)
|
||||
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Log)
|
||||
### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
### netutil网络包支持获取ip地址,发送http请求。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/netutil"
|
||||
import "github.com/duke-git/lancet/v2/netutil"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ConvertMapToQueryString)
|
||||
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetInternalIp)
|
||||
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
|
||||
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
|
||||
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)
|
||||
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
|
||||
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
|
||||
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
|
||||
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
|
||||
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
|
||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||
|
||||
### random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/random"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [RandBytes](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandBytes)
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||
### retry重试执行函数直到函数运行成功或被context cancel。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/retry"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [Context](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Context)
|
||||
- [Retry](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#Retry)
|
||||
- [RetryFunc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryFunc)
|
||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
|
||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
||||
|
||||
|
||||
### slice包包含操作切片的方法集合。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/slice"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
|
||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
|
||||
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
|
||||
- [Compact](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Compact)
|
||||
- [Concat](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Concat)
|
||||
- [Count](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Count)
|
||||
- [Difference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Difference)
|
||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DifferenceBy)
|
||||
- [DifferenceWith](https://github.com/duke-git/lancet/blob/main/docs/slice.md#DifferenceWith)
|
||||
- [DeleteAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#DeleteAt)
|
||||
- [Drop](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Drop)
|
||||
- [Every](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Every)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Filter)
|
||||
- [Find](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Find)
|
||||
- [FindLast](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#FindLast)
|
||||
- [FlattenDeep](#FlattenDeep)
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)
|
||||
- [GroupBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)
|
||||
- [GroupWith](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupWith)
|
||||
- [IntSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#IntSlice)
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Intersection)
|
||||
- [InsertAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#InsertAt)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Map)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reverse)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Reduce)
|
||||
- [Shuffle](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Shuffle)
|
||||
- [SortByField](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SortByField)
|
||||
- [Some](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Some)
|
||||
- [StringSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#StringSlice)
|
||||
- [SymmetricDifference](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#SymmetricDifference)
|
||||
- [Unique](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Unique)
|
||||
- [Union](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Union)
|
||||
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#UpdateAt)
|
||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
||||
|
||||
|
||||
### strutil包含处理字符串的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/strutil"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ConvertMapToQueryString)
|
||||
- [EncodeUrl](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#EncodeUrl)
|
||||
- [GetInternalIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetInternalIp)
|
||||
- [GetIps](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetIps)
|
||||
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/v1/docs/netutil.md#GetMacAddrs)
|
||||
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetPublicIpInfo)
|
||||
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#GetRequestPublicIp)
|
||||
- [IsPublicIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPublicIP)
|
||||
- [IsInternalIP](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsInternalIP)
|
||||
- [HttpGet](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpGet)
|
||||
- [HttpDelete](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpDelete)
|
||||
- [HttpPost](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPost)
|
||||
- [HttpPut](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPut)
|
||||
- [HttpPatch](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#HttpPatch)
|
||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||
- [UploadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#UploadFile)
|
||||
- [DownloadFile](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#DownloadFile)
|
||||
- [IsPingConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsPingConnected)
|
||||
- [IsTelnetConnected](https://github.com/duke-git/lancet/blob/v1/docs/netutil_zh-CN.md#IsTelnetConnected)
|
||||
- [After](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#After)
|
||||
- [AfterLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#AfterLast)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Before)
|
||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#BeforeLast)
|
||||
- [CamelCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#CamelCase)
|
||||
- [Capitalize](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)
|
||||
- [IsString](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)
|
||||
- [KebabCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#KebabCase)
|
||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#LowerFirst)
|
||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
|
||||
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
|
||||
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
||||
|
||||
|
||||
### 10. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
### system包含os, runtime, shell command相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/random"
|
||||
import "github.com/duke-git/lancet/v2/system"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
- [IsWindows](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsWindows)
|
||||
- [IsLinux](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsLinux)
|
||||
- [IsMac](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#IsMac)
|
||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsEnv)
|
||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#SetOsEnv)
|
||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#RemoveOsEnv)
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
||||
|
||||
- [RandBytes](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandBytes)
|
||||
- [RandInt](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandInt)
|
||||
- [RandString](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandString)
|
||||
- [RandUpper](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandUpper)
|
||||
- [RandLower](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandLower)
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
|
||||
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
|
||||
|
||||
### 11. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
### validator验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/retry"
|
||||
import "github.com/duke-git/lancet/v2/validator"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [Context](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Context)
|
||||
- [Retry](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#Retry)
|
||||
- [RetryFunc](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryFunc)
|
||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryDuration)
|
||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/v1/docs/retry_zh-CN.md#RetryTimes)
|
||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainChinese)
|
||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLetter)
|
||||
- [ContainLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainLower)
|
||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#ContainUpper)
|
||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAlpha)
|
||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllUpper)
|
||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsAllLower)
|
||||
- [IsBase64](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsBase64)
|
||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseMobile)
|
||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChineseIdNum)
|
||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsChinesePhone)
|
||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsCreditCard)
|
||||
- [IsDns](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsDns)
|
||||
- [IsEmail](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmail)
|
||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsEmptyString)
|
||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)
|
||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)
|
||||
- [IsJSON](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsJSON)
|
||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsRegexMatch)
|
||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)
|
||||
- [IsIp](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIp)
|
||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV4)
|
||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIpV6)
|
||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)
|
||||
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
|
||||
|
||||
### 12. slice 包包含操作切片的方法集合。
|
||||
validator.md#IsWeakPassword)
|
||||
### xerror包实现一些错误处理函数
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/slice"
|
||||
import "github.com/duke-git/lancet/v2/xerror"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#AppendIfAbsent)
|
||||
- [Contain](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Contain)
|
||||
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ContainSubSlice)
|
||||
- [Chunk](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Chunk)
|
||||
- [Compact](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Compact)
|
||||
- [Concat](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Concat)
|
||||
- [Count](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Count)
|
||||
- [Difference](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Difference)
|
||||
- [DifferenceBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DifferenceBy)
|
||||
- [DeleteByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#DeleteByIndex)
|
||||
- [Drop](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Drop)
|
||||
- [Every](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Every)
|
||||
- [Equal](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Equal)
|
||||
- [EqualWith](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#EqualWith)
|
||||
- [Filter](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Filter)
|
||||
- [Find](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Find)
|
||||
- [FindLast](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#FindLast)
|
||||
- [FlattenDeep](https://github.com/duke-git/lancet/blob/v1/docs/slice.md#FlattenDeep)
|
||||
- [ForEach](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ForEach)
|
||||
- [GroupBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#GroupBy)
|
||||
- [IntSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IntSlice)
|
||||
- [IndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#IndexOf)
|
||||
- [LastIndexOf](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#LastIndexOf)
|
||||
- [InterfaceSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InterfaceSlice)
|
||||
- [Intersection](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Intersection)
|
||||
- [InsertByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#InsertByIndex)
|
||||
- [Map](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Map)
|
||||
- [ReverseSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ReverseSlice)
|
||||
- [Reduce](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Reduce)
|
||||
- [Shuffle](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Shuffle)
|
||||
- [SortByField](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#SortByField)
|
||||
- [Some](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Some)
|
||||
- [StringSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#StringSlice)
|
||||
- [ToSlice](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
|
||||
- [ToSlicePointer](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#ToSlice)
|
||||
- [Unique](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Unique)
|
||||
- [UniqueBy](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UniqueBy)
|
||||
- [Union](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Union)
|
||||
- [UpdateByIndex](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#UpdateByIndex)
|
||||
- [Without](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Without)
|
||||
- [Join](https://github.com/duke-git/lancet/blob/v1/docs/slice_zh-CN.md#Join)
|
||||
|
||||
### 13. strutil 包含处理字符串的相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/strutil"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [After](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#After)
|
||||
- [AfterLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#AfterLast)
|
||||
- [Before](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Before)
|
||||
- [BeforeLast](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BeforeLast)
|
||||
- [CamelCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#CamelCase)
|
||||
- [Capitalize](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Capitalize)
|
||||
- [ContainsAll](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAll)
|
||||
- [ContainsAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ContainsAny)
|
||||
- [IsString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsString)
|
||||
- [KebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#KebabCase)
|
||||
- [UpperKebabCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperKebabCase)
|
||||
- [LowerFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#LowerFirst)
|
||||
- [UpperFirst](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperFirst)
|
||||
- [Pad](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Pad)
|
||||
- [PadEnd](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadEnd)
|
||||
- [PadStart](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#PadStart)
|
||||
- [Reverse](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Reverse)
|
||||
- [SnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SnakeCase)
|
||||
- [UpperSnakeCase](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#UpperSnakeCase)
|
||||
- [SplitEx](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitEx)
|
||||
- [Wrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Wrap)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Unwrap)
|
||||
- [SplitWords](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitWords)
|
||||
- [WordCount](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#WordCount)
|
||||
- [RemoveNonPrintable](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveNonPrintable)
|
||||
- [StringToBytes](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#StringToBytes)
|
||||
- [BytesToString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#BytesToString)
|
||||
- [IsBlank](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IsBlank)
|
||||
- [HasPrefixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasPrefixAny)
|
||||
- [HasSuffixAny](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HasSuffixAny)
|
||||
- [IndexOffset](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#IndexOffset)
|
||||
- [ReplaceWithMap](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#ReplaceWithMap)
|
||||
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Trim)
|
||||
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
|
||||
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HideString)
|
||||
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveWhiteSpace)
|
||||
|
||||
### 14. system 包含 os, runtime, shell command 相关函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/system"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [IsWindows](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsWindows)
|
||||
- [IsLinux](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsLinux)
|
||||
- [IsMac](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#IsMac)
|
||||
- [GetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsEnv)
|
||||
- [SetOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#SetOsEnv)
|
||||
- [RemoveOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#RemoveOsEnv)
|
||||
- [CompareOsEnv](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#CompareOsEnv)
|
||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#ExecCommand)
|
||||
- [GetOsBits](https://github.com/duke-git/lancet/blob/v1/docs/system_zh-CN.md#GetOsBits)
|
||||
|
||||
### 15. validator 验证器包,包含常用字符串格式验证函数。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/validator"
|
||||
```
|
||||
|
||||
#### 函数列表:
|
||||
|
||||
- [ContainChinese](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainChinese)
|
||||
- [ContainLetter](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLetter)
|
||||
- [ContainLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainLower)
|
||||
- [ContainUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#ContainUpper)
|
||||
- [IsAlpha](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAlpha)
|
||||
- [IsAllUpper](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllUpper)
|
||||
- [IsAllLower](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAllLower)
|
||||
- [IsBase64](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64)
|
||||
- [IsChineseMobile](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseMobile)
|
||||
- [IsChineseIdNum](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChineseIdNum)
|
||||
- [IsChinesePhone](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinesePhone)
|
||||
- [IsCreditCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsCreditCard)
|
||||
- [IsDns](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsDns)
|
||||
- [IsEmail](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmail)
|
||||
- [IsEmptyString](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsEmptyString)
|
||||
- [IsInt](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsInt)
|
||||
- [IsFloat](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloat)
|
||||
- [IsNumber](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumber)
|
||||
- [IsIntStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIntStr)
|
||||
- [IsFloatStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsFloatStr)
|
||||
- [IsNumberStr](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsNumberStr)
|
||||
- [IsJSON](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJSON)
|
||||
- [IsRegexMatch](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsRegexMatch)
|
||||
- [IsIp](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIp)
|
||||
- [IsIpV4](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV4)
|
||||
- [IsIpV6](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsIpV6)
|
||||
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsStrongPassword)
|
||||
- [IsUrl](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUrl)
|
||||
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsWeakPassword)
|
||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsZeroValue)
|
||||
- [IsGBK](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsGBK)
|
||||
- [IsASCII](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsASCII)
|
||||
- [IsPrintable](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsPrintable)
|
||||
- [IsBin](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBin)
|
||||
- [IsHex](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsHex)
|
||||
- [IsBase64URL](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsBase64URL)
|
||||
- [IsJWT](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsJWT)
|
||||
- [IsVisa](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsVisa)
|
||||
- [IsMasterCard](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsMasterCard)
|
||||
- [IsAmericanExpress](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsAmericanExpress)
|
||||
- [IsUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsUnionPay)
|
||||
- [IsChinaUnionPay](https://github.com/duke-git/lancet/blob/v1/docs/validator_zh-CN.md#IsChinaUnionPay)
|
||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/xerror_zh-CN.md#Unwrap)
|
||||
|
||||
## 如何贡献代码
|
||||
|
||||
非常感激任何的代码提交以使 lancet 的功能越来越强大。创建 pull request 时请遵守以下规则。
|
||||
非常感激任何的代码提交以使lancet的功能越来越强大。创建pull request时请遵守以下规则。
|
||||
|
||||
1. Fork lancet 仓库。
|
||||
1. Fork lancet仓库。
|
||||
2. 创建自己的特性分支。
|
||||
3. 提交变更。
|
||||
4. Push 分支。
|
||||
5. 创建新的 pull request。
|
||||
4. Push分支。
|
||||
5. 创建新的pull request。
|
||||
|
||||
102
algorithm/lru_cache.go
Normal file
102
algorithm/lru_cache.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package algorithm
|
||||
|
||||
type lruNode[K comparable, V any] struct {
|
||||
key K
|
||||
value V
|
||||
pre *lruNode[K, V]
|
||||
next *lruNode[K, V]
|
||||
}
|
||||
|
||||
// newLruNode return a lruNode pointer
|
||||
func newLruNode[K comparable, V any](key K, value V) *lruNode[K, V] {
|
||||
return &lruNode[K, V]{
|
||||
key: key,
|
||||
value: value,
|
||||
pre: nil,
|
||||
next: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// LRUCache lru cache (thread unsafe)
|
||||
type LRUCache[K comparable, V any] struct {
|
||||
cache map[K]*lruNode[K, V]
|
||||
head *lruNode[K, V]
|
||||
tail *lruNode[K, V]
|
||||
capacity int
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLRUCache return a LRUCache pointer
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
return &LRUCache[K, V]{
|
||||
cache: make(map[K]*lruNode[K, V], capacity),
|
||||
head: nil,
|
||||
tail: nil,
|
||||
capacity: capacity,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Get value of key from lru cache
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
var value V
|
||||
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
l.moveToHead(node)
|
||||
return node.value, true
|
||||
}
|
||||
|
||||
return value, false
|
||||
}
|
||||
|
||||
// Put value of key into lru cache
|
||||
func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
node, ok := l.cache[key]
|
||||
if !ok {
|
||||
newNode := newLruNode(key, value)
|
||||
l.cache[key] = newNode
|
||||
l.addNode(newNode)
|
||||
|
||||
if len(l.cache) > l.capacity {
|
||||
oldKey := l.deleteNode(l.head)
|
||||
delete(l.cache, oldKey)
|
||||
}
|
||||
} else {
|
||||
node.value = value
|
||||
l.moveToHead(node)
|
||||
}
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
|
||||
if l.tail != nil {
|
||||
l.tail.next = node
|
||||
node.pre = l.tail
|
||||
node.next = nil
|
||||
}
|
||||
l.tail = node
|
||||
if l.head == nil {
|
||||
l.head = node
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
|
||||
if node == l.tail {
|
||||
l.tail = l.tail.pre
|
||||
} else if node == l.head {
|
||||
l.head = l.head.next
|
||||
} else {
|
||||
node.pre.next = node.next
|
||||
node.next.pre = node.pre
|
||||
}
|
||||
return node.key
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
|
||||
if l.tail == node {
|
||||
return
|
||||
}
|
||||
l.deleteNode(node)
|
||||
l.addNode(node)
|
||||
}
|
||||
36
algorithm/lru_cache_test.go
Normal file
36
algorithm/lru_cache_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package algorithm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestLRUCache(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
_, ok := cache.Get(0)
|
||||
asssert.Equal(false, ok)
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(1, v)
|
||||
|
||||
v, ok = cache.Get(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
|
||||
cache.Put(3, 3)
|
||||
v, ok = cache.Get(1)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.NotEqual(1, v)
|
||||
|
||||
v, ok = cache.Get(3)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(3, v)
|
||||
}
|
||||
63
algorithm/search.go
Normal file
63
algorithm/search.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
|
||||
for i, v := range slice {
|
||||
if comparator.Compare(v, target) == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// BinarySearch search for target within a sorted slice, recursive call itself.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
midIndex := int(lowIndex + (highIndex-lowIndex)/2)
|
||||
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
|
||||
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
|
||||
|
||||
if isMidValGreatTarget {
|
||||
return BinarySearch(sortedSlice, target, lowIndex, midIndex-1, comparator)
|
||||
} else if isMidValLessTarget {
|
||||
return BinarySearch(sortedSlice, target, midIndex+1, highIndex, comparator)
|
||||
}
|
||||
|
||||
return midIndex
|
||||
}
|
||||
|
||||
// BinaryIterativeSearch search for target within a sorted slice.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
var midIndex int
|
||||
for startIndex <= endIndex {
|
||||
midIndex = int(startIndex + (endIndex-startIndex)/2)
|
||||
isMidValGreatTarget := comparator.Compare(sortedSlice[midIndex], target) == 1
|
||||
isMidValLessTarget := comparator.Compare(sortedSlice[midIndex], target) == -1
|
||||
|
||||
if isMidValGreatTarget {
|
||||
endIndex = midIndex - 1
|
||||
} else if isMidValLessTarget {
|
||||
startIndex = midIndex + 1
|
||||
} else {
|
||||
return midIndex
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
33
algorithm/search_test.go
Normal file
33
algorithm/search_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package algorithm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
|
||||
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
188
algorithm/sorter.go
Normal file
188
algorithm/sorter.go
Normal file
@@ -0,0 +1,188 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// BubbleSort use bubble to sort slice.
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := 0; j < len(slice)-1-i; j++ {
|
||||
isCurrGreatThanNext := comparator.Compare(slice[j], slice[j+1]) == 1
|
||||
if isCurrGreatThanNext {
|
||||
swap(slice, j, j+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InsertionSort use insertion to sort slice.
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
isPreLessThanCurrent := comparator.Compare(slice[j], slice[j-1]) == -1
|
||||
if isPreLessThanCurrent {
|
||||
swap(slice, j, j-1)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionSort use selection to sort slice.
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
for j := i + 1; j < len(slice); j++ {
|
||||
if comparator.Compare(slice[j], slice[min]) == -1 {
|
||||
min = j
|
||||
}
|
||||
}
|
||||
swap(slice, i, min)
|
||||
}
|
||||
}
|
||||
|
||||
// ShellSort shell sort slice.
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
gap := 1
|
||||
for gap < size/3 {
|
||||
gap = 3*gap + 1
|
||||
}
|
||||
|
||||
for gap >= 1 {
|
||||
for i := gap; i < size; i++ {
|
||||
for j := i; j >= gap && comparator.Compare(slice[j], slice[j-gap]) == -1; j -= gap {
|
||||
swap(slice, j, j-gap)
|
||||
}
|
||||
}
|
||||
gap = gap / 3
|
||||
}
|
||||
}
|
||||
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
|
||||
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
p := partition(slice, lowIndex, highIndex, comparator)
|
||||
QuickSort(slice, lowIndex, p-1, comparator)
|
||||
QuickSort(slice, p+1, highIndex, comparator)
|
||||
}
|
||||
}
|
||||
|
||||
// partition split slice into two parts
|
||||
func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
p := slice[highIndex]
|
||||
i := lowIndex
|
||||
for j := lowIndex; j < highIndex; j++ {
|
||||
if comparator.Compare(slice[j], p) == -1 { //slice[j] < p
|
||||
swap(slice, i, j)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
swap(slice, i, highIndex)
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// HeapSort use heap to sort slice
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
for i := size/2 - 1; i >= 0; i-- {
|
||||
sift(slice, i, size-1, comparator)
|
||||
}
|
||||
for j := size - 1; j > 0; j-- {
|
||||
swap(slice, 0, j)
|
||||
sift(slice, 0, j-1, comparator)
|
||||
}
|
||||
}
|
||||
|
||||
func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := 2*i + 1
|
||||
|
||||
temp := slice[i]
|
||||
for j <= highIndex {
|
||||
if j < highIndex && comparator.Compare(slice[j], slice[j+1]) == -1 { //slice[j] < slice[j+1]
|
||||
j++
|
||||
}
|
||||
if comparator.Compare(temp, slice[j]) == -1 { //tmp < slice[j]
|
||||
slice[i] = slice[j]
|
||||
i = j
|
||||
j = 2*i + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
slice[i] = temp
|
||||
}
|
||||
|
||||
// MergeSort merge sorting for slice
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
|
||||
func mergeSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
if lowIndex < highIndex {
|
||||
mid := (lowIndex + highIndex) / 2
|
||||
mergeSort(slice, lowIndex, mid, comparator)
|
||||
mergeSort(slice, mid+1, highIndex, comparator)
|
||||
merge(slice, lowIndex, mid, highIndex, comparator)
|
||||
}
|
||||
}
|
||||
|
||||
func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lancetconstraints.Comparator) {
|
||||
i := lowIndex
|
||||
j := midIndex + 1
|
||||
temp := []T{}
|
||||
|
||||
for i <= midIndex && j <= highIndex {
|
||||
//slice[i] < slice[j]
|
||||
if comparator.Compare(slice[i], slice[j]) == -1 {
|
||||
temp = append(temp, slice[i])
|
||||
i++
|
||||
} else {
|
||||
temp = append(temp, slice[j])
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
if i <= midIndex {
|
||||
temp = append(temp, slice[i:midIndex+1]...)
|
||||
} else {
|
||||
temp = append(temp, slice[j:highIndex+1]...)
|
||||
}
|
||||
|
||||
for k := 0; k < len(temp); k++ {
|
||||
slice[lowIndex+k] = temp[k]
|
||||
}
|
||||
}
|
||||
|
||||
// CountSort use count sorting for slice
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
count := 0
|
||||
for j := 0; j < size; j++ {
|
||||
//slice[i] > slice[j]
|
||||
if comparator.Compare(slice[i], slice[j]) == 1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
out[count] = slice[i]
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// swap two slice value at index i and j
|
||||
func swap[T any](slice []T, i, j int) {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
218
algorithm/sorter_test.go
Normal file
218
algorithm/sorter_test.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package algorithm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
// People test mock data
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/v2/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// var peoples = []people{
|
||||
// {Name: "a", Age: 20},
|
||||
// {Name: "b", Age: 10},
|
||||
// {Name: "c", Age: 17},
|
||||
// {Name: "d", Age: 8},
|
||||
// {Name: "e", Age: 28},
|
||||
// }
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// var intSlice = []int{2, 1, 5, 3, 6, 4}
|
||||
|
||||
func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
BubbleSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
asssert.Equal([]int{1, 2, 3, 4, 5, 6}, numbers)
|
||||
}
|
||||
|
||||
func TestInsertionSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestInsertionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
InsertionSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestSelectionSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestSelectionSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
SelectionSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestShellSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestShellSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
ShellSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestQuickSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestQuickSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
QuickSort(peoples, 0, len(peoples)-1, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestHeapSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestHeapSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
HeapSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestMergeSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestMergeSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
MergeSort(peoples, comparator)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", peoples)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestCountSort(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestCountSort")
|
||||
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
sortedPeopleByAge := CountSort(peoples, comparator)
|
||||
t.Log(sortedPeopleByAge)
|
||||
|
||||
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
|
||||
actual := fmt.Sprintf("%v", sortedPeopleByAge)
|
||||
|
||||
asssert.Equal(expected, actual)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package compare provides a lightweight comparison function on interface{} type.
|
||||
// reference: https://github.com/stretchr/testify
|
||||
package compare
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
// operator type
|
||||
const (
|
||||
equal = "eq"
|
||||
lessThan = "lt"
|
||||
greaterThan = "gt"
|
||||
lessOrEqual = "le"
|
||||
greaterOrEqual = "ge"
|
||||
)
|
||||
|
||||
var (
|
||||
timeType = reflect.TypeOf(time.Time{})
|
||||
bytesType = reflect.TypeOf([]byte{})
|
||||
)
|
||||
|
||||
// Equal checks if two values are equal or not. (check both type and value)
|
||||
func Equal(left, right interface{}) bool {
|
||||
return compareValue(equal, left, right)
|
||||
}
|
||||
|
||||
// EqualValue checks if two values are equal or not. (check value only)
|
||||
func EqualValue(left, right interface{}) bool {
|
||||
ls, rs := convertor.ToString(left), convertor.ToString(right)
|
||||
return ls == rs
|
||||
}
|
||||
|
||||
// LessThan checks if value `left` less than value `right`.
|
||||
func LessThan(left, right interface{}) bool {
|
||||
return compareValue(lessThan, left, right)
|
||||
}
|
||||
|
||||
// GreaterThan checks if value `left` greater than value `right`.
|
||||
func GreaterThan(left, right interface{}) bool {
|
||||
return compareValue(greaterThan, left, right)
|
||||
}
|
||||
|
||||
// LessOrEqual checks if value `left` less than or equal to value `right`.
|
||||
func LessOrEqual(left, right interface{}) bool {
|
||||
return compareValue(lessOrEqual, left, right)
|
||||
}
|
||||
|
||||
// GreaterOrEqual checks if value `left` greater than or equal to value `right`.
|
||||
func GreaterOrEqual(left, right interface{}) bool {
|
||||
return compareValue(greaterOrEqual, left, right)
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleEqual() {
|
||||
result1 := Equal(1, 1)
|
||||
result2 := Equal("1", "1")
|
||||
result3 := Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := Equal(1, "1")
|
||||
result6 := Equal(1, int64(1))
|
||||
result7 := Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleEqualValue() {
|
||||
result1 := EqualValue(1, 1)
|
||||
result2 := EqualValue(int(1), int64(1))
|
||||
result3 := EqualValue(1, "1")
|
||||
result4 := EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLessThan() {
|
||||
result1 := LessThan(1, 2)
|
||||
result2 := LessThan(1.1, 2.2)
|
||||
result3 := LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := LessThan(time1, time2)
|
||||
|
||||
result5 := LessThan(2, 1)
|
||||
result6 := LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleGreaterThan() {
|
||||
result1 := GreaterThan(2, 1)
|
||||
result2 := GreaterThan(2.2, 1.1)
|
||||
result3 := GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := GreaterThan(time2, time1)
|
||||
|
||||
result5 := GreaterThan(1, 2)
|
||||
result6 := GreaterThan(int64(2), 1)
|
||||
result7 := GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLessOrEqual() {
|
||||
result1 := LessOrEqual(1, 1)
|
||||
result2 := LessOrEqual(1.1, 2.2)
|
||||
result3 := LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := LessOrEqual(time1, time2)
|
||||
|
||||
result5 := LessOrEqual(2, 1)
|
||||
result6 := LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleGreaterOrEqual() {
|
||||
result1 := GreaterOrEqual(1, 1)
|
||||
result2 := GreaterOrEqual(2.2, 1.1)
|
||||
result3 := GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := GreaterOrEqual(1, 2)
|
||||
result6 := GreaterOrEqual(int64(2), 1)
|
||||
result7 := GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func compareValue(operator string, left, right interface{}) bool {
|
||||
leftType, rightType := reflect.TypeOf(left), reflect.TypeOf(right)
|
||||
|
||||
if leftType.Kind() != rightType.Kind() {
|
||||
return false
|
||||
}
|
||||
|
||||
switch leftType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
|
||||
return compareBasicValue(operator, left, right)
|
||||
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
return compareRefValue(operator, left, right, leftType.Kind())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflect.Kind) bool {
|
||||
leftVal, rightVal := reflect.ValueOf(leftObj), reflect.ValueOf(rightObj)
|
||||
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
|
||||
// compare time
|
||||
if leftVal.CanConvert(timeType) {
|
||||
timeObj1, ok := leftObj.(time.Time)
|
||||
if !ok {
|
||||
timeObj1 = leftVal.Convert(timeType).Interface().(time.Time)
|
||||
}
|
||||
|
||||
timeObj2, ok := rightObj.(time.Time)
|
||||
if !ok {
|
||||
timeObj2 = rightVal.Convert(timeType).Interface().(time.Time)
|
||||
}
|
||||
|
||||
return compareBasicValue(operator, timeObj1.UnixNano(), timeObj2.UnixNano())
|
||||
}
|
||||
|
||||
// for other struct type, only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return objectsAreEqualValues(leftObj, rightObj)
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
// compare []byte
|
||||
if leftVal.CanConvert(bytesType) {
|
||||
bytesObj1, ok := leftObj.([]byte)
|
||||
if !ok {
|
||||
bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte)
|
||||
}
|
||||
bytesObj2, ok := rightObj.([]byte)
|
||||
if !ok {
|
||||
bytesObj2 = rightVal.Convert(bytesType).Interface().([]byte)
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 0 {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == -1 {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) == 1 {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) <= 0 {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if bytes.Compare(bytesObj1, bytesObj2) >= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// for other type slice, only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return reflect.DeepEqual(leftObj, rightObj)
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
// only process equal operator
|
||||
switch operator {
|
||||
case equal:
|
||||
return reflect.DeepEqual(leftObj, rightObj)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func objectsAreEqualValues(expected, actual interface{}) bool {
|
||||
if objectsAreEqual(expected, actual) {
|
||||
return true
|
||||
}
|
||||
|
||||
actualType := reflect.TypeOf(actual)
|
||||
if actualType == nil {
|
||||
return false
|
||||
}
|
||||
expectedValue := reflect.ValueOf(expected)
|
||||
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
|
||||
// Attempt comparison after type conversion
|
||||
return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func objectsAreEqual(expected, actual interface{}) bool {
|
||||
if expected == nil || actual == nil {
|
||||
return expected == actual
|
||||
}
|
||||
|
||||
exp, ok := expected.([]byte)
|
||||
if !ok {
|
||||
return reflect.DeepEqual(expected, actual)
|
||||
}
|
||||
|
||||
act, ok := actual.([]byte)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if exp == nil || act == nil {
|
||||
return exp == nil && act == nil
|
||||
}
|
||||
return bytes.Equal(exp, act)
|
||||
}
|
||||
|
||||
// compareBasic compare basic value: integer, float, string, bool
|
||||
func compareBasicValue(operator string, leftValue, rightValue interface{}) bool {
|
||||
if leftValue == nil && rightValue == nil && operator == equal {
|
||||
return true
|
||||
}
|
||||
|
||||
switch leftVal := leftValue.(type) {
|
||||
case json.Number:
|
||||
if left, err := leftVal.Float64(); err == nil {
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
left, err := convertor.ToFloat(leftValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch rightVal := rightValue.(type) {
|
||||
case json.Number:
|
||||
if right, err := rightVal.Float64(); err == nil {
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
|
||||
right, err := convertor.ToFloat(rightValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case string:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case string:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
case lessThan:
|
||||
if left < right {
|
||||
return true
|
||||
}
|
||||
case greaterThan:
|
||||
if left > right {
|
||||
return true
|
||||
}
|
||||
case lessOrEqual:
|
||||
if left <= right {
|
||||
return true
|
||||
}
|
||||
case greaterOrEqual:
|
||||
if left >= right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case bool:
|
||||
left := leftVal
|
||||
switch right := rightValue.(type) {
|
||||
case bool:
|
||||
switch operator {
|
||||
case equal:
|
||||
if left == right {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package compare
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
)
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqual")
|
||||
|
||||
assert.Equal(true, Equal(1, 1))
|
||||
assert.Equal(true, Equal(int64(1), int64(1)))
|
||||
assert.Equal(true, Equal("a", "a"))
|
||||
assert.Equal(true, Equal(true, true))
|
||||
assert.Equal(true, Equal([]int{1, 2, 3}, []int{1, 2, 3}))
|
||||
assert.Equal(true, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"}))
|
||||
|
||||
assert.Equal(false, Equal(1, 2))
|
||||
assert.Equal(false, Equal(1, int64(1)))
|
||||
assert.Equal(false, Equal("a", "b"))
|
||||
assert.Equal(false, Equal(true, false))
|
||||
assert.Equal(false, Equal([]int{1, 2}, []int{1, 2, 3}))
|
||||
assert.Equal(false, Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a"}))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
time3 := time1.Add(time.Second)
|
||||
|
||||
assert.Equal(false, Equal(time1, time2))
|
||||
assert.Equal(true, Equal(time2, time3))
|
||||
|
||||
st1 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
st2 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
st3 := struct {
|
||||
A string
|
||||
B string
|
||||
}{
|
||||
A: "a1",
|
||||
B: "b",
|
||||
}
|
||||
|
||||
assert.Equal(true, Equal(st1, st2))
|
||||
assert.Equal(false, Equal(st1, st3))
|
||||
}
|
||||
|
||||
func TestEqualValue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqualValue")
|
||||
|
||||
assert.Equal(true, EqualValue(1, 1))
|
||||
assert.Equal(true, EqualValue(int(1), int64(1)))
|
||||
assert.Equal(true, EqualValue(1, "1"))
|
||||
|
||||
assert.Equal(false, EqualValue(1, "2"))
|
||||
}
|
||||
|
||||
func TestLessThan(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLessThan")
|
||||
|
||||
assert.Equal(true, LessThan(1, 2))
|
||||
assert.Equal(true, LessThan(1.1, 2.2))
|
||||
assert.Equal(true, LessThan("a", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessThan(time1, time2))
|
||||
|
||||
assert.Equal(false, LessThan(1, 1))
|
||||
assert.Equal(false, LessThan(1, int64(1)))
|
||||
}
|
||||
|
||||
func TestGreaterThan(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterThan(2, 1))
|
||||
assert.Equal(true, GreaterThan(2.2, 1.1))
|
||||
assert.Equal(true, GreaterThan("b", "a"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterThan(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterThan(1, 2))
|
||||
assert.Equal(false, GreaterThan(int64(2), 1))
|
||||
assert.Equal(false, GreaterThan("b", "c"))
|
||||
}
|
||||
|
||||
func TestLessOrEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLessOrEqual")
|
||||
|
||||
assert.Equal(true, LessOrEqual(1, 2))
|
||||
assert.Equal(true, LessOrEqual(1, 1))
|
||||
assert.Equal(true, LessOrEqual(1.1, 2.2))
|
||||
assert.Equal(true, LessOrEqual("a", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, LessOrEqual(time1, time2))
|
||||
|
||||
assert.Equal(false, LessOrEqual(2, 1))
|
||||
assert.Equal(false, LessOrEqual(1, int64(2)))
|
||||
}
|
||||
|
||||
func TestGreaterOrEqual(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGreaterThan")
|
||||
|
||||
assert.Equal(true, GreaterOrEqual(2, 1))
|
||||
assert.Equal(true, GreaterOrEqual(1, 1))
|
||||
assert.Equal(true, GreaterOrEqual(2.2, 1.1))
|
||||
assert.Equal(true, GreaterOrEqual("b", "b"))
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
assert.Equal(true, GreaterOrEqual(time2, time1))
|
||||
|
||||
assert.Equal(false, GreaterOrEqual(1, 2))
|
||||
assert.Equal(false, GreaterOrEqual(int64(2), 1))
|
||||
assert.Equal(false, GreaterOrEqual("b", "c"))
|
||||
}
|
||||
@@ -7,19 +7,13 @@ package convertor
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// ToBool convert string to a boolean
|
||||
@@ -28,7 +22,7 @@ func ToBool(s string) (bool, error) {
|
||||
}
|
||||
|
||||
// ToBytes convert interface to bytes
|
||||
func ToBytes(value interface{}) ([]byte, error) {
|
||||
func ToBytes(value any) ([]byte, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
switch value.(type) {
|
||||
@@ -81,51 +75,39 @@ func ToChar(s string) []string {
|
||||
}
|
||||
|
||||
// ToString convert value to string
|
||||
func ToString(value interface{}) string {
|
||||
func ToString(value any) string {
|
||||
res := ""
|
||||
if value == nil {
|
||||
return ""
|
||||
return res
|
||||
}
|
||||
|
||||
switch val := value.(type) {
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||
case int:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int8:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int16:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int32:
|
||||
return strconv.FormatInt(int64(val), 10)
|
||||
case int64:
|
||||
return strconv.FormatInt(val, 10)
|
||||
case uint:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint8:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint16:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint32:
|
||||
return strconv.FormatUint(uint64(val), 10)
|
||||
case uint64:
|
||||
return strconv.FormatUint(val, 10)
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
switch value.(type) {
|
||||
case float32, float64:
|
||||
res = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
return res
|
||||
case int, int8, int16, int32, int64:
|
||||
res = strconv.FormatInt(v.Int(), 10)
|
||||
return res
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
res = strconv.FormatUint(v.Uint(), 10)
|
||||
return res
|
||||
case string:
|
||||
return val
|
||||
res = v.String()
|
||||
return res
|
||||
case []byte:
|
||||
return string(val)
|
||||
res = string(v.Bytes())
|
||||
return res
|
||||
default:
|
||||
b, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
newValue, _ := json.Marshal(value)
|
||||
res = string(newValue)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
// ToJson convert value to a valid json string
|
||||
func ToJson(value interface{}) (string, error) {
|
||||
func ToJson(value any) (string, error) {
|
||||
res, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -135,7 +117,7 @@ func ToJson(value interface{}) (string, error) {
|
||||
}
|
||||
|
||||
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
|
||||
func ToFloat(value interface{}) (float64, error) {
|
||||
func ToFloat(value any) (float64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
res := 0.0
|
||||
@@ -162,7 +144,7 @@ func ToFloat(value interface{}) (float64, error) {
|
||||
}
|
||||
|
||||
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
|
||||
func ToInt(value interface{}) (int64, error) {
|
||||
func ToInt(value any) (int64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
var res int64
|
||||
@@ -190,7 +172,7 @@ func ToInt(value interface{}) (int64, error) {
|
||||
|
||||
// StructToMap convert struct to map, only convert exported struct field
|
||||
// map key is specified same as struct field tag `json` value
|
||||
func StructToMap(value interface{}) (map[string]interface{}, error) {
|
||||
func StructToMap(value any) (map[string]any, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
|
||||
@@ -201,7 +183,7 @@ func StructToMap(value interface{}) (map[string]interface{}, error) {
|
||||
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
|
||||
}
|
||||
|
||||
res := make(map[string]interface{})
|
||||
res := make(map[string]any)
|
||||
|
||||
fieldNum := t.NumField()
|
||||
pattern := `^[A-Z]`
|
||||
@@ -247,160 +229,3 @@ func ColorRGBToHex(red, green, blue int) string {
|
||||
|
||||
return "#" + r + g + b
|
||||
}
|
||||
|
||||
// ToChannel convert a array of elements to a read-only channels
|
||||
func ToChannel(array []interface{}) <-chan interface{} {
|
||||
ch := make(chan interface{})
|
||||
|
||||
go func() {
|
||||
for _, item := range array {
|
||||
ch <- item
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// EncodeByte encode data to byte
|
||||
func EncodeByte(data interface{}) ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
encoder := gob.NewEncoder(buffer)
|
||||
err := encoder.Encode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecodeByte decode byte data to target object
|
||||
func DecodeByte(data []byte, target interface{}) error {
|
||||
buffer := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(buffer)
|
||||
return decoder.Decode(target)
|
||||
}
|
||||
|
||||
// DeepClone creates a deep copy of passed item.
|
||||
// can't clone unexported field of struct
|
||||
func DeepClone(src interface{}) interface{} {
|
||||
c := cloner{
|
||||
ptrs: map[reflect.Type]map[uintptr]reflect.Value{},
|
||||
}
|
||||
result := c.clone(reflect.ValueOf(src))
|
||||
if result.Kind() == reflect.Invalid {
|
||||
return nil
|
||||
}
|
||||
|
||||
return result.Interface()
|
||||
}
|
||||
|
||||
// // CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
// func CopyProperties(dst, src interface{}) (err error) {
|
||||
// defer func() {
|
||||
// if e := recover(); e != nil {
|
||||
// err = errors.New(fmt.Sprintf("%v", e))
|
||||
// }
|
||||
// }()
|
||||
|
||||
// dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
|
||||
// srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
|
||||
|
||||
// if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||
// return errors.New("CopyProperties: param dst should be struct pointer")
|
||||
// }
|
||||
|
||||
// if srcType.Kind() == reflect.Ptr {
|
||||
// srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
||||
// }
|
||||
// if srcType.Kind() != reflect.Struct {
|
||||
// return errors.New("CopyProperties: param src should be a struct or struct pointer")
|
||||
// }
|
||||
|
||||
// dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
||||
|
||||
// propertyNums := dstType.NumField()
|
||||
|
||||
// for i := 0; i < propertyNums; i++ {
|
||||
// property := dstType.Field(i)
|
||||
// propertyValue := srcValue.FieldByName(property.Name)
|
||||
|
||||
// if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// if dstValue.Field(i).CanSet() {
|
||||
// dstValue.Field(i).Set(propertyValue)
|
||||
// }
|
||||
// }
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// CopyProperties copies each field from the source into the destination. It recursively copies struct pointers and interfaces that contain struct pointers.
|
||||
// use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.
|
||||
func CopyProperties(dst, src interface{}) error {
|
||||
dstType, srcType := reflect.TypeOf(dst), reflect.TypeOf(src)
|
||||
|
||||
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
||||
return errors.New("CopyProperties: parameter dst should be struct pointer")
|
||||
}
|
||||
|
||||
if srcType.Kind() == reflect.Ptr {
|
||||
srcType = srcType.Elem()
|
||||
}
|
||||
if srcType.Kind() != reflect.Struct {
|
||||
return errors.New("CopyProperties: parameter src should be a struct or struct pointer")
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to marshal src: %s", err)
|
||||
}
|
||||
err = json.Unmarshal(bytes, dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CopyProperties: unable to unmarshal into dst: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToInterface converts reflect value to its interface type.
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
|
||||
if v.IsValid() && v.CanInterface() {
|
||||
return v.Interface(), true
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return v.Bool(), true
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int(), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint(), true
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float(), true
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return v.Complex(), true
|
||||
case reflect.String:
|
||||
return v.String(), true
|
||||
case reflect.Ptr:
|
||||
return ToInterface(v.Elem())
|
||||
case reflect.Interface:
|
||||
return ToInterface(v.Elem())
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error) {
|
||||
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
|
||||
b, err := io.ReadAll(r)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
|
||||
func GbkToUtf8(bs []byte) ([]byte, error) {
|
||||
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
|
||||
b, err := io.ReadAll(r)
|
||||
return b, err
|
||||
}
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package convertor implements some functions to convert data.
|
||||
package convertor
|
||||
|
||||
import "reflect"
|
||||
|
||||
type cloner struct {
|
||||
ptrs map[reflect.Type]map[uintptr]reflect.Value
|
||||
}
|
||||
|
||||
// clone return a duplicate of passed item.
|
||||
func (c *cloner) clone(v reflect.Value) reflect.Value {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
return reflect.ValueOf(nil)
|
||||
|
||||
// bool
|
||||
case reflect.Bool:
|
||||
return reflect.ValueOf(v.Bool())
|
||||
|
||||
//int
|
||||
case reflect.Int:
|
||||
return reflect.ValueOf(int(v.Int()))
|
||||
case reflect.Int8:
|
||||
return reflect.ValueOf(int8(v.Int()))
|
||||
case reflect.Int16:
|
||||
return reflect.ValueOf(int16(v.Int()))
|
||||
case reflect.Int32:
|
||||
return reflect.ValueOf(int32(v.Int()))
|
||||
case reflect.Int64:
|
||||
return reflect.ValueOf(v.Int())
|
||||
|
||||
// uint
|
||||
case reflect.Uint:
|
||||
return reflect.ValueOf(uint(v.Uint()))
|
||||
case reflect.Uint8:
|
||||
return reflect.ValueOf(uint8(v.Uint()))
|
||||
case reflect.Uint16:
|
||||
return reflect.ValueOf(uint16(v.Uint()))
|
||||
case reflect.Uint32:
|
||||
return reflect.ValueOf(uint32(v.Uint()))
|
||||
case reflect.Uint64:
|
||||
return reflect.ValueOf(v.Uint())
|
||||
|
||||
// float
|
||||
case reflect.Float32:
|
||||
return reflect.ValueOf(float32(v.Float()))
|
||||
case reflect.Float64:
|
||||
return reflect.ValueOf(v.Float())
|
||||
|
||||
// complex
|
||||
case reflect.Complex64:
|
||||
return reflect.ValueOf(complex64(v.Complex()))
|
||||
case reflect.Complex128:
|
||||
return reflect.ValueOf(v.Complex())
|
||||
|
||||
// string
|
||||
case reflect.String:
|
||||
return reflect.ValueOf(v.String())
|
||||
|
||||
// array
|
||||
case reflect.Array, reflect.Slice:
|
||||
return c.cloneArray(v)
|
||||
|
||||
// map
|
||||
case reflect.Map:
|
||||
return c.cloneMap(v)
|
||||
|
||||
// Ptr
|
||||
case reflect.Ptr:
|
||||
return c.clonePtr(v)
|
||||
|
||||
// struct
|
||||
case reflect.Struct:
|
||||
return c.cloneStruct(v)
|
||||
|
||||
// func
|
||||
case reflect.Func:
|
||||
return v
|
||||
|
||||
// interface
|
||||
case reflect.Interface:
|
||||
return c.clone(v.Elem())
|
||||
|
||||
}
|
||||
|
||||
return reflect.Zero(v.Type())
|
||||
}
|
||||
|
||||
func (c *cloner) cloneArray(v reflect.Value) reflect.Value {
|
||||
if v.IsNil() {
|
||||
return reflect.Zero(v.Type())
|
||||
}
|
||||
|
||||
arr := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
val := c.clone(v.Index(i))
|
||||
|
||||
if val.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
item := arr.Index(i)
|
||||
if !item.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
item.Set(val.Convert(item.Type()))
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
func (c *cloner) cloneMap(v reflect.Value) reflect.Value {
|
||||
if v.IsNil() {
|
||||
return reflect.Zero(v.Type())
|
||||
}
|
||||
|
||||
clonedMap := reflect.MakeMap(v.Type())
|
||||
|
||||
for _, key := range v.MapKeys() {
|
||||
value := v.MapIndex(key)
|
||||
clonedKey := c.clone(key)
|
||||
clonedValue := c.clone(value)
|
||||
|
||||
if !isNillable(clonedKey) || !clonedKey.IsNil() {
|
||||
clonedKey = clonedKey.Convert(key.Type())
|
||||
}
|
||||
|
||||
if (!isNillable(clonedValue) || !clonedValue.IsNil()) && clonedValue.IsValid() {
|
||||
clonedValue = clonedValue.Convert(value.Type())
|
||||
}
|
||||
|
||||
if !clonedValue.IsValid() {
|
||||
clonedValue = reflect.Zero(clonedMap.Type().Elem())
|
||||
}
|
||||
|
||||
clonedMap.SetMapIndex(clonedKey, clonedValue)
|
||||
}
|
||||
|
||||
return clonedMap
|
||||
}
|
||||
|
||||
func isNillable(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *cloner) clonePtr(v reflect.Value) reflect.Value {
|
||||
if v.IsNil() {
|
||||
return reflect.Zero(v.Type())
|
||||
}
|
||||
|
||||
var newVal reflect.Value
|
||||
|
||||
if v.Elem().CanAddr() {
|
||||
ptrs, exists := c.ptrs[v.Type()]
|
||||
if exists {
|
||||
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
|
||||
return newVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newVal = c.clone(v.Elem())
|
||||
|
||||
if v.Elem().CanAddr() {
|
||||
ptrs, exists := c.ptrs[v.Type()]
|
||||
if exists {
|
||||
if newVal, exists := ptrs[v.Elem().UnsafeAddr()]; exists {
|
||||
return newVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clonedPtr := reflect.New(newVal.Type())
|
||||
clonedPtr.Elem().Set(newVal)
|
||||
|
||||
return clonedPtr
|
||||
}
|
||||
|
||||
func (c *cloner) cloneStruct(v reflect.Value) reflect.Value {
|
||||
clonedStructPtr := reflect.New(v.Type())
|
||||
clonedStruct := clonedStructPtr.Elem()
|
||||
|
||||
if v.CanAddr() {
|
||||
ptrs := c.ptrs[clonedStructPtr.Type()]
|
||||
if ptrs == nil {
|
||||
ptrs = make(map[uintptr]reflect.Value)
|
||||
c.ptrs[clonedStructPtr.Type()] = ptrs
|
||||
}
|
||||
ptrs[v.UnsafeAddr()] = clonedStructPtr
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
newStructValue := clonedStruct.Field(i)
|
||||
if !newStructValue.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
clonedVal := c.clone(v.Field(i))
|
||||
if !clonedVal.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
newStructValue.Set(clonedVal.Convert(newStructValue.Type()))
|
||||
}
|
||||
|
||||
return clonedStruct
|
||||
}
|
||||
@@ -2,12 +2,9 @@ package convertor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/validator"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestToChar(t *testing.T) {
|
||||
@@ -39,7 +36,7 @@ func TestToBool(t *testing.T) {
|
||||
func TestToBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToBytes")
|
||||
|
||||
cases := []interface{}{
|
||||
cases := []any{
|
||||
0,
|
||||
false,
|
||||
"1",
|
||||
@@ -65,7 +62,7 @@ func TestToBytes(t *testing.T) {
|
||||
func TestToInt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToInt")
|
||||
|
||||
cases := []interface{}{"123", "-123", 123,
|
||||
cases := []any{"123", "-123", 123,
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
float32(12.3), float64(12.3),
|
||||
"abc", false, "111111111111111111111111111111111111111"}
|
||||
@@ -81,7 +78,7 @@ func TestToInt(t *testing.T) {
|
||||
func TestToFloat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToFloat")
|
||||
|
||||
cases := []interface{}{
|
||||
cases := []any{
|
||||
"", "-1", "-.11", "1.23e3", ".123e10", "abc",
|
||||
int(0), int8(1), int16(-1), int32(123), int64(123),
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
@@ -109,7 +106,7 @@ func TestToString(t *testing.T) {
|
||||
}
|
||||
aStruct := TestStruct{Name: "TestStruct"}
|
||||
|
||||
cases := []interface{}{
|
||||
cases := []any{
|
||||
"", nil,
|
||||
int(0), int8(1), int16(-1), int32(123), int64(123),
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
@@ -121,7 +118,7 @@ func TestToString(t *testing.T) {
|
||||
"", "",
|
||||
"0", "1", "-1",
|
||||
"123", "123", "123", "123", "123", "123", "123",
|
||||
"12.3", "12.3",
|
||||
"12.3", "12.300000190734863",
|
||||
"true", "false",
|
||||
"[1,2,3]", "{\"a\":1,\"b\":2,\"c\":3}", "{\"Name\":\"TestStruct\"}", "hello"}
|
||||
|
||||
@@ -157,7 +154,7 @@ func TestStructToMap(t *testing.T) {
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
var expected = map[string]interface{}{"name": "test"}
|
||||
var expected = map[string]any{"name": "test"}
|
||||
assert.Equal(expected, pm)
|
||||
}
|
||||
|
||||
@@ -181,185 +178,3 @@ func TestColorRGBToHex(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestColorRGBToHex")
|
||||
assert.Equal(expected, colorHex)
|
||||
}
|
||||
|
||||
func TestToChannel(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToChannel")
|
||||
|
||||
ch := ToChannel([]interface{}{1, 2, 3})
|
||||
val1, _ := <-ch
|
||||
assert.Equal(1, val1)
|
||||
|
||||
val2, _ := <-ch
|
||||
assert.Equal(2, val2)
|
||||
|
||||
val3, _ := <-ch
|
||||
assert.Equal(3, val3)
|
||||
|
||||
_, ok := <-ch
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestEncodeByte(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEncodeByte")
|
||||
|
||||
byteData, _ := EncodeByte("abc")
|
||||
expected := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
|
||||
assert.Equal(expected, byteData)
|
||||
}
|
||||
|
||||
func TestDecodeByte(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDecodeByte")
|
||||
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
DecodeByte(byteData, &obj)
|
||||
assert.Equal("abc", obj)
|
||||
}
|
||||
|
||||
func TestDeepClone(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestDeepClone")
|
||||
|
||||
type Struct struct {
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
unexported string
|
||||
}
|
||||
|
||||
cases := []interface{}{
|
||||
true,
|
||||
1,
|
||||
0.1,
|
||||
map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
&Struct{
|
||||
Str: "test",
|
||||
Int: 1,
|
||||
Float: 0.1,
|
||||
Bool: true,
|
||||
Nil: nil,
|
||||
// unexported: "can't be cloned",
|
||||
},
|
||||
}
|
||||
|
||||
for i, item := range cases {
|
||||
cloned := DeepClone(item)
|
||||
|
||||
t.Log(cloned)
|
||||
if &cloned == &item {
|
||||
t.Fatalf("[TestDeepClone case #%d failed]: equal pointer", i)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, cloned) {
|
||||
t.Fatalf("[TestDeepClone case #%d failed] unequal objects", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyProperties(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCopyProperties")
|
||||
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("001", indicatorVO.Id)
|
||||
assert.Equal("127.0.0.1", indicatorVO.Ip)
|
||||
assert.Equal(3, len(indicatorVO.Disk))
|
||||
}
|
||||
|
||||
func TestToInterface(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToInterface")
|
||||
|
||||
cases := []reflect.Value{
|
||||
reflect.ValueOf("abc"),
|
||||
reflect.ValueOf(int(0)), reflect.ValueOf(int8(1)), reflect.ValueOf(int16(-1)), reflect.ValueOf(int32(123)), reflect.ValueOf(int64(123)),
|
||||
reflect.ValueOf(uint(123)), reflect.ValueOf(uint8(123)), reflect.ValueOf(uint16(123)), reflect.ValueOf(uint32(123)), reflect.ValueOf(uint64(123)),
|
||||
reflect.ValueOf(float64(12.3)), reflect.ValueOf(float32(12.3)),
|
||||
reflect.ValueOf(true), reflect.ValueOf(false),
|
||||
}
|
||||
|
||||
expected := []interface{}{
|
||||
"abc",
|
||||
0, int8(1), int16(-1), int32(123), int64(123),
|
||||
uint(123), uint8(123), uint16(123), uint32(123), uint64(123),
|
||||
float64(12.3), float32(12.3),
|
||||
true, false,
|
||||
}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual, _ := ToInterface(cases[i])
|
||||
assert.Equal(expected[i], actual)
|
||||
}
|
||||
|
||||
nilVal, ok := ToInterface(reflect.ValueOf(nil))
|
||||
assert.EqualValues(nil, nilVal)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestUtf8ToGbk(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUtf8ToGbk")
|
||||
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, err := Utf8ToGbk(utf8Data)
|
||||
|
||||
assert.Equal(true, utf8.Valid(utf8Data))
|
||||
assert.Equal(true, validator.IsGBK(gbkData))
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
func TestGbkToUtf8(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGbkToUtf8")
|
||||
|
||||
gbkData, err := Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, err := GbkToUtf8(gbkData)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(true, utf8.Valid(utf8Data))
|
||||
assert.Equal("hello", string(utf8Data))
|
||||
}
|
||||
|
||||
168
cryptor/aes.go
Normal file
168
cryptor/aes.go
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
// Note:
|
||||
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
copy(plain, data)
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
encrypted := make([]byte, len(plain))
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
//
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcEncrypt(data, key []byte) []byte {
|
||||
// len(key) should be 16, 24 or 32
|
||||
block, _ := aes.NewCipher(key)
|
||||
blockSize := block.BlockSize()
|
||||
data = pkcs7Padding(data, blockSize)
|
||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
||||
|
||||
encrypted := make([]byte, len(data))
|
||||
blockMode.CryptBlocks(encrypted, data)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
blockSize := block.BlockSize()
|
||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
||||
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
blockMode.CryptBlocks(decrypted, encrypted)
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:aes.BlockSize]
|
||||
data = data[aes.BlockSize:]
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
return decrypted
|
||||
}
|
||||
62
cryptor/aes_test.go
Normal file
62
cryptor/aes_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestAesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
||||
assert.Equal(data, string(aesEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
||||
assert.Equal(data, string(aesCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
||||
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
||||
assert.Equal(data, string(aesCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestAesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
||||
assert.Equal(data, string(aesCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
||||
assert.Equal(data, string(aesOfbDecrypt))
|
||||
}
|
||||
@@ -37,27 +37,6 @@ func Md5String(s string) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5StringWithBase64 return the md5 value of string with base64.
|
||||
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.
|
||||
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.
|
||||
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 {
|
||||
@@ -97,13 +76,6 @@ func HmacMd5(data, key string) string {
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
|
||||
func HmacMd5WithBase64(data, key string) string {
|
||||
h := hmac.New(md5.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha1 return the hmac hash of string use sha1
|
||||
func HmacSha1(data, key string) string {
|
||||
h := hmac.New(sha1.New, []byte(key))
|
||||
@@ -111,13 +83,6 @@ func HmacSha1(data, key string) string {
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
|
||||
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
|
||||
func HmacSha256(data, key string) string {
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
@@ -125,13 +90,6 @@ func HmacSha256(data, key string) string {
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
|
||||
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
|
||||
func HmacSha512(data, key string) string {
|
||||
h := hmac.New(sha512.New, []byte(key))
|
||||
@@ -139,13 +97,6 @@ func HmacSha512(data, key string) string {
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
|
||||
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
|
||||
func Sha1(data string) string {
|
||||
sha1 := sha1.New()
|
||||
@@ -153,13 +104,6 @@ func Sha1(data string) string {
|
||||
return hex.EncodeToString(sha1.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
|
||||
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
|
||||
func Sha256(data string) string {
|
||||
sha256 := sha256.New()
|
||||
@@ -167,23 +111,9 @@ func Sha256(data string) string {
|
||||
return hex.EncodeToString(sha256.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
|
||||
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
|
||||
func Sha512(data string) string {
|
||||
sha512 := sha512.New()
|
||||
sha512.Write([]byte(data))
|
||||
return hex.EncodeToString(sha512.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
|
||||
func Sha512WithBase64(str string) string {
|
||||
sha512 := sha512.New()
|
||||
sha512.Write([]byte(str))
|
||||
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package cryptor
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestBase64StdEncode(t *testing.T) {
|
||||
@@ -21,22 +21,6 @@ func TestMd5String(t *testing.T) {
|
||||
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
|
||||
}
|
||||
|
||||
func TestMd5StringWithBase64(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
|
||||
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
|
||||
}
|
||||
|
||||
func TestMd5Byte(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMd5Byte")
|
||||
data := []byte{'a'}
|
||||
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
|
||||
}
|
||||
|
||||
func TestMd5ByteWithBase64(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
|
||||
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
|
||||
}
|
||||
|
||||
func TestMd5File(t *testing.T) {
|
||||
fileMd5, err := Md5File("./basic.go")
|
||||
assert := internal.NewAssert(t, "TestMd5File")
|
||||
@@ -49,11 +33,6 @@ func TestHmacMd5(t *testing.T) {
|
||||
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
|
||||
}
|
||||
|
||||
func TestHmacMd5WithBase64(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
|
||||
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
|
||||
}
|
||||
|
||||
func TestHmacSha1(t *testing.T) {
|
||||
s := "hello world"
|
||||
key := "12345"
|
||||
@@ -64,16 +43,6 @@ func TestHmacSha1(t *testing.T) {
|
||||
assert.Equal(expected, hmacSha1)
|
||||
}
|
||||
|
||||
func TestHmacSha1WithBase64(t *testing.T) {
|
||||
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) {
|
||||
s := "hello world"
|
||||
key := "12345"
|
||||
@@ -84,16 +53,6 @@ func TestHmacSha256(t *testing.T) {
|
||||
assert.Equal(expected, hmacSha256)
|
||||
}
|
||||
|
||||
func TestHmacSha256WithBase64(t *testing.T) {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
hms := HmacSha256WithBase64(str, key)
|
||||
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
|
||||
|
||||
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
|
||||
assert.Equal(expected, hms)
|
||||
}
|
||||
|
||||
func TestHmacSha512(t *testing.T) {
|
||||
s := "hello world"
|
||||
key := "12345"
|
||||
@@ -104,16 +63,6 @@ func TestHmacSha512(t *testing.T) {
|
||||
assert.Equal(expected, hmacSha512)
|
||||
}
|
||||
|
||||
func TestHmacSha512WithBase64(t *testing.T) {
|
||||
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) {
|
||||
s := "hello world"
|
||||
sha1 := Sha1(s)
|
||||
@@ -123,14 +72,6 @@ func TestSha1(t *testing.T) {
|
||||
assert.Equal(expected, sha1)
|
||||
}
|
||||
|
||||
func TestSha1WithBase64(t *testing.T) {
|
||||
str := Sha1WithBase64("hello")
|
||||
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha1WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
func TestSha256(t *testing.T) {
|
||||
s := "hello world"
|
||||
sha256 := Sha256(s)
|
||||
@@ -140,14 +81,6 @@ func TestSha256(t *testing.T) {
|
||||
assert.Equal(expected, sha256)
|
||||
}
|
||||
|
||||
func TestSha256WithBase64(t *testing.T) {
|
||||
str := Sha256WithBase64("hello")
|
||||
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha256WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
func TestSha512(t *testing.T) {
|
||||
s := "hello world"
|
||||
sha512 := Sha512(s)
|
||||
@@ -156,11 +89,3 @@ func TestSha512(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSha512")
|
||||
assert.Equal(expected, sha512)
|
||||
}
|
||||
|
||||
func TestSha512WithBase64(t *testing.T) {
|
||||
str := Sha512WithBase64("hello")
|
||||
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
|
||||
|
||||
assert := internal.NewAssert(t, "TestSha512WithBase64")
|
||||
assert.Equal(expected, str)
|
||||
}
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
// Note:
|
||||
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key, size))
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
size := len(key)
|
||||
if size != 16 && size != 24 && size != 32 {
|
||||
panic("key length shoud be 16 or 24 or 32")
|
||||
}
|
||||
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key, size))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:aes.BlockSize]
|
||||
data = data[aes.BlockSize:]
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
||||
// len(key) should be 8
|
||||
func DesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 8
|
||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
if len(encrypted) < des.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func DesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, des.BlockSize)
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:des.BlockSize]
|
||||
data = data[des.BlockSize:]
|
||||
if len(data)%des.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// GenerateRsaKey make a rsa private key, and return key file name
|
||||
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
|
||||
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
// private key
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
|
||||
block := pem.Block{
|
||||
Type: "rsa private key",
|
||||
Bytes: derText,
|
||||
}
|
||||
|
||||
//file,err := os.Create("rsa_private.pem")
|
||||
file, err := os.Create(priKeyFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
publicKey := privateKey.PublicKey
|
||||
|
||||
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block = pem.Block{
|
||||
Type: "rsa public key",
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
//file,err = os.Create("rsa_public.pem")
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RsaEncrypt encrypt data with ras algorithm
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
file, err := os.Open(pubKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
file.Read(buf)
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKey := pubInterface.(*rsa.PublicKey)
|
||||
|
||||
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cipherText
|
||||
}
|
||||
|
||||
// RsaDecrypt decrypt data with ras algorithm
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
file, err := os.Open(privateKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
file.Read(buf)
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return plainText
|
||||
}
|
||||
|
||||
// GenerateRsaKeyPair create rsa private and public key.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
}
|
||||
@@ -2,15 +2,15 @@ package cryptor
|
||||
|
||||
import "bytes"
|
||||
|
||||
func generateAesKey(key []byte, size int) []byte {
|
||||
aesKey := make([]byte, size)
|
||||
copy(aesKey, key)
|
||||
for i := size; i < len(key); {
|
||||
for j := 0; j < size && i < len(key); j, i = j+1, i+1 {
|
||||
aesKey[j] ^= key[i]
|
||||
func generateAesKey(key []byte) []byte {
|
||||
genKey := make([]byte, 16)
|
||||
copy(genKey, key)
|
||||
for i := 16; i < len(key); {
|
||||
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
|
||||
genKey[j] ^= key[i]
|
||||
}
|
||||
}
|
||||
return aesKey
|
||||
return genKey
|
||||
}
|
||||
|
||||
func generateDesKey(key []byte) []byte {
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
)
|
||||
|
||||
func TestAesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
||||
assert.Equal(data, string(aesEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
||||
assert.Equal(data, string(aesCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
||||
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
||||
assert.Equal(data, string(aesCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestAesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
||||
assert.Equal(data, string(aesCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
||||
assert.Equal(data, string(aesOfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
||||
assert.Equal(data, string(desEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
||||
assert.Equal(data, string(desCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
||||
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
||||
assert.Equal(data, string(desCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestDesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
||||
assert.Equal(data, string(desCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
||||
assert.Equal(data, string(desOfbDecrypt))
|
||||
}
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
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))
|
||||
}
|
||||
173
cryptor/des.go
Normal file
173
cryptor/des.go
Normal file
@@ -0,0 +1,173 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
blockSize := block.BlockSize()
|
||||
data = pkcs7Padding(data, blockSize)
|
||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
||||
|
||||
encrypted := make([]byte, len(data))
|
||||
blockMode.CryptBlocks(encrypted, data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
blockSize := block.BlockSize()
|
||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
||||
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
blockMode.CryptBlocks(decrypted, encrypted)
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
||||
// len(key) should be 8
|
||||
func DesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 8
|
||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
if len(encrypted) < des.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func DesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, des.BlockSize)
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:des.BlockSize]
|
||||
data = data[des.BlockSize:]
|
||||
if len(data)%des.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
62
cryptor/des_test.go
Normal file
62
cryptor/des_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestDesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
||||
assert.Equal(data, string(desEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
||||
assert.Equal(data, string(desCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
||||
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
||||
assert.Equal(data, string(desCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestDesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
||||
assert.Equal(data, string(desCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
||||
assert.Equal(data, string(desOfbDecrypt))
|
||||
}
|
||||
118
cryptor/rsa.go
Normal file
118
cryptor/rsa.go
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GenerateRsaKey make a rsa private key, and return key file name
|
||||
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
|
||||
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
// private key
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
|
||||
block := pem.Block{
|
||||
Type: "rsa private key",
|
||||
Bytes: derText,
|
||||
}
|
||||
|
||||
//file,err := os.Create("rsa_private.pem")
|
||||
file, err := os.Create(priKeyFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
publicKey := privateKey.PublicKey
|
||||
|
||||
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block = pem.Block{
|
||||
Type: "rsa public key",
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
//file,err = os.Create("rsa_public.pem")
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pem.Encode(file, &block)
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RsaEncrypt encrypt data with ras algorithm
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
file, err := os.Open(pubKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
file.Read(buf)
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKey := pubInterface.(*rsa.PublicKey)
|
||||
|
||||
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cipherText
|
||||
}
|
||||
|
||||
// RsaDecrypt decrypt data with ras algorithm
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
file, err := os.Open(privateKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
file.Read(buf)
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return plainText
|
||||
}
|
||||
20
cryptor/rsa_test.go
Normal file
20
cryptor/rsa_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
}
|
||||
241
datastructure/link/doublylink.go
Normal file
241
datastructure/link/doublylink.go
Normal file
@@ -0,0 +1,241 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
|
||||
type DoublyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
}
|
||||
|
||||
// NewDoublyLink return *DoublyLink instance
|
||||
func NewDoublyLink[T any]() *DoublyLink[T] {
|
||||
return &DoublyLink[T]{Head: nil}
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into doubly linklist at head index
|
||||
func (link *DoublyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
size := link.Size()
|
||||
|
||||
if size == 0 {
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
return
|
||||
}
|
||||
|
||||
newNode.Next = link.Head
|
||||
newNode.Pre = nil
|
||||
|
||||
link.Head.Pre = newNode
|
||||
link.Head = newNode
|
||||
|
||||
link.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
for current.Next != nil {
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = nil
|
||||
newNode.Pre = current
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into doubly linklist at index
|
||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of doubly link.")
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = current.Next
|
||||
newNode.Pre = current
|
||||
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
|
||||
return nil
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in doubly linklist at head index
|
||||
func (link *DoublyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.Head.Pre = nil
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in doubly linklist at tail index
|
||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAt delete value in doubly linklist at index
|
||||
func (link *DoublyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("doubly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *DoublyLink[T]) Reverse() {
|
||||
current := link.Head
|
||||
var temp *datastructure.LinkNode[T]
|
||||
|
||||
for current != nil {
|
||||
temp = current.Pre
|
||||
current.Pre = current.Next
|
||||
current.Next = temp
|
||||
current = current.Pre
|
||||
}
|
||||
|
||||
if temp != nil {
|
||||
link.Head = temp.Pre
|
||||
}
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
|
||||
if fast != nil {
|
||||
fast = fast.Next
|
||||
slow = slow.Next
|
||||
} else {
|
||||
return slow
|
||||
}
|
||||
}
|
||||
return slow
|
||||
}
|
||||
|
||||
// Size return the count of doubly linked list
|
||||
func (link *DoublyLink[T]) Size() int {
|
||||
return link.length
|
||||
}
|
||||
|
||||
// Values return slice of all doubly linklist node value
|
||||
func (link *DoublyLink[T]) Values() []T {
|
||||
res := []T{}
|
||||
current := link.Head
|
||||
for current != nil {
|
||||
res = append(res, current.Value)
|
||||
current = current.Next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *DoublyLink[T]) Print() {
|
||||
current := link.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
current = current.Next
|
||||
}
|
||||
info += " ]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *DoublyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
}
|
||||
|
||||
// Clear checks if link is empty or not
|
||||
func (link *DoublyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
}
|
||||
179
datastructure/link/doublylink_test.go
Normal file
179
datastructure/link/doublylink_test.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestDoublyLink_InsertAtFirst(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtFirst")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
link.InsertAtHead(1)
|
||||
link.InsertAtHead(2)
|
||||
link.InsertAtHead(3)
|
||||
link.Print()
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestDoublyLink_InsertAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtTail")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestDoublyLink_InsertAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_InsertAt")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAt(0, 1)
|
||||
link.InsertAt(1, 2)
|
||||
link.InsertAt(2, 4)
|
||||
link.InsertAt(2, 3)
|
||||
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
|
||||
}
|
||||
|
||||
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtHead()
|
||||
link.Print()
|
||||
|
||||
expected := []int{2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestDoublyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
assert.Equal([]int{2, 3, 4}, link.Values())
|
||||
|
||||
link.DeleteAt(1)
|
||||
assert.Equal(2, link.Size())
|
||||
assert.Equal([]int{2, 4}, link.Values())
|
||||
}
|
||||
|
||||
func TestDoublyLink_Reverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_Reverse")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.Reverse()
|
||||
link.Print()
|
||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||
}
|
||||
|
||||
func TestDoublyLink_GetMiddleNode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_GetMiddleNode")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
middle1 := link.GetMiddleNode()
|
||||
assert.Equal(3, middle1.Value)
|
||||
|
||||
link.InsertAtTail(5)
|
||||
link.InsertAtTail(6)
|
||||
link.InsertAtTail(7)
|
||||
middle2 := link.GetMiddleNode()
|
||||
assert.Equal(4, middle2.Value)
|
||||
}
|
||||
|
||||
func TestDoublyLink_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDoublyLink_Clear")
|
||||
|
||||
link := NewDoublyLink[int]()
|
||||
|
||||
assert.Equal(true, link.IsEmpty())
|
||||
assert.Equal(0, link.Size())
|
||||
|
||||
link.InsertAtTail(1)
|
||||
assert.Equal(false, link.IsEmpty())
|
||||
assert.Equal(1, link.Size())
|
||||
|
||||
link.Clear()
|
||||
assert.Equal(true, link.IsEmpty())
|
||||
assert.Equal(0, link.Size())
|
||||
}
|
||||
246
datastructure/link/singlylink.go
Normal file
246
datastructure/link/singlylink.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
|
||||
type SinglyLink[T any] struct {
|
||||
Head *datastructure.LinkNode[T]
|
||||
length int
|
||||
}
|
||||
|
||||
// NewSinglyLink return *SinglyLink instance
|
||||
func NewSinglyLink[T any]() *SinglyLink[T] {
|
||||
return &SinglyLink[T]{Head: nil}
|
||||
}
|
||||
|
||||
// InsertAtHead insert value into singly linklist at head index
|
||||
func (link *SinglyLink[T]) InsertAtHead(value T) {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = link.Head
|
||||
link.Head = newNode
|
||||
link.length++
|
||||
}
|
||||
|
||||
// InsertAtTail insert value into singly linklist at tail index
|
||||
func (link *SinglyLink[T]) InsertAtTail(value T) {
|
||||
current := link.Head
|
||||
if current == nil {
|
||||
link.InsertAtHead(value)
|
||||
return
|
||||
}
|
||||
|
||||
for current.Next != nil {
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = nil
|
||||
current.Next = newNode
|
||||
|
||||
link.length++
|
||||
}
|
||||
|
||||
// InsertAt insert value into singly linklist at index
|
||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
|
||||
size := link.length
|
||||
if index < 0 || index > size {
|
||||
return errors.New("param index should between 0 and the length of singly link.")
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
link.InsertAtHead(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
if index == size {
|
||||
link.InsertAtTail(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
i := 0
|
||||
current := link.Head
|
||||
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
newNode := datastructure.NewLinkNode(value)
|
||||
newNode.Next = current.Next
|
||||
current.Next = newNode
|
||||
link.length++
|
||||
|
||||
return nil
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
|
||||
// DeleteAtHead delete value in singly linklist at head index
|
||||
func (link *SinglyLink[T]) DeleteAtHead() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
link.Head = current.Next
|
||||
link.length--
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAtTail delete value in singly linklist at tail index
|
||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
if current.Next == nil {
|
||||
return link.DeleteAtHead()
|
||||
}
|
||||
|
||||
for current.Next.Next != nil {
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
current.Next = nil
|
||||
link.length--
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAt delete value in singly linklist at index
|
||||
func (link *SinglyLink[T]) DeleteAt(index int) error {
|
||||
if link.Head == nil {
|
||||
return errors.New("singly link list no exist")
|
||||
}
|
||||
current := link.Head
|
||||
if current.Next == nil || index == 0 {
|
||||
return link.DeleteAtHead()
|
||||
}
|
||||
|
||||
if index == link.length-1 {
|
||||
return link.DeleteAtTail()
|
||||
}
|
||||
|
||||
if index < 0 || index > link.length-1 {
|
||||
return errors.New("param index should between 0 and link size -1.")
|
||||
}
|
||||
|
||||
i := 0
|
||||
for current != nil {
|
||||
if i == index-1 {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
return nil
|
||||
}
|
||||
i++
|
||||
current = current.Next
|
||||
}
|
||||
|
||||
return errors.New("delete error")
|
||||
}
|
||||
|
||||
// DeleteValue delete value in singly linklist
|
||||
func (link *SinglyLink[T]) DeleteValue(value T) {
|
||||
if link.Head == nil {
|
||||
return
|
||||
}
|
||||
dummyHead := datastructure.NewLinkNode(value)
|
||||
dummyHead.Next = link.Head
|
||||
current := dummyHead
|
||||
|
||||
for current.Next != nil {
|
||||
if reflect.DeepEqual(current.Next.Value, value) {
|
||||
current.Next = current.Next.Next
|
||||
link.length--
|
||||
} else {
|
||||
current = current.Next
|
||||
}
|
||||
}
|
||||
|
||||
link.Head = dummyHead.Next
|
||||
}
|
||||
|
||||
// Reverse the linked list
|
||||
func (link *SinglyLink[T]) Reverse() {
|
||||
var pre, next *datastructure.LinkNode[T]
|
||||
|
||||
current := link.Head
|
||||
|
||||
for current != nil {
|
||||
next = current.Next
|
||||
current.Next = pre
|
||||
pre = current
|
||||
current = next
|
||||
}
|
||||
|
||||
link.Head = pre
|
||||
}
|
||||
|
||||
// GetMiddleNode return node at middle index of linked list
|
||||
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||
if link.Head == nil {
|
||||
return nil
|
||||
}
|
||||
if link.Head.Next == nil {
|
||||
return link.Head
|
||||
}
|
||||
fast := link.Head
|
||||
slow := link.Head
|
||||
|
||||
for fast != nil {
|
||||
fast = fast.Next
|
||||
|
||||
if fast != nil {
|
||||
fast = fast.Next
|
||||
slow = slow.Next
|
||||
} else {
|
||||
return slow
|
||||
}
|
||||
}
|
||||
return slow
|
||||
}
|
||||
|
||||
// Size return the count of singly linked list
|
||||
func (link *SinglyLink[T]) Size() int {
|
||||
return link.length
|
||||
}
|
||||
|
||||
// Values return slice of all singly linklist node value
|
||||
func (link *SinglyLink[T]) Values() []T {
|
||||
res := []T{}
|
||||
current := link.Head
|
||||
for current != nil {
|
||||
res = append(res, current.Value)
|
||||
current = current.Next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// IsEmpty checks if link is empty or not
|
||||
func (link *SinglyLink[T]) IsEmpty() bool {
|
||||
return link.length == 0
|
||||
}
|
||||
|
||||
// Clear checks if link is empty or not
|
||||
func (link *SinglyLink[T]) Clear() {
|
||||
link.Head = nil
|
||||
link.length = 0
|
||||
}
|
||||
|
||||
// Print all nodes info of a linked list
|
||||
func (link *SinglyLink[T]) Print() {
|
||||
current := link.Head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
current = current.Next
|
||||
}
|
||||
info += " ]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
208
datastructure/link/singlylink_test.go
Normal file
208
datastructure/link/singlylink_test.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestSinglyLink_InsertAtFirst(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtFirst")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
link.InsertAtHead(1)
|
||||
link.InsertAtHead(2)
|
||||
link.InsertAtHead(3)
|
||||
link.Print()
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestSinglyLink_InsertAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtTail")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestSinglyLink_InsertAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_InsertAt")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
|
||||
err := link.InsertAt(1, 1)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.InsertAt(0, 1)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(1, 2)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 4)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
err = link.InsertAt(2, 3)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestSinglyLink_DeleteAtHead(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtHead()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtHead()
|
||||
link.Print()
|
||||
|
||||
expected := []int{2, 3, 4}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAtTail()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteAtTail()
|
||||
link.Print()
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
values := link.Values()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
}
|
||||
|
||||
func TestSinglyLink_DeleteValue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteValue")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.DeleteValue(2)
|
||||
assert.Equal([]int{1, 3, 4}, link.Values())
|
||||
|
||||
link.DeleteValue(1)
|
||||
assert.Equal([]int{3, 4}, link.Values())
|
||||
}
|
||||
|
||||
func TestSinglyLink_DeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
err := link.DeleteAt(0)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
link.InsertAtTail(5)
|
||||
|
||||
err = link.DeleteAt(5)
|
||||
assert.IsNotNil(err)
|
||||
|
||||
err = link.DeleteAt(0)
|
||||
assert.IsNil(err)
|
||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||
|
||||
link.DeleteAt(3)
|
||||
assert.Equal([]int{2, 3, 4}, link.Values())
|
||||
|
||||
link.DeleteAt(1)
|
||||
assert.Equal(2, link.Size())
|
||||
assert.Equal([]int{2, 4}, link.Values())
|
||||
}
|
||||
|
||||
func TestSinglyLink_Reverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_Reverse")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
link.Reverse()
|
||||
link.Print()
|
||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||
}
|
||||
|
||||
func TestSinglyLink_GetMiddleNode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_GetMiddleNode")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
link.InsertAtTail(1)
|
||||
link.InsertAtTail(2)
|
||||
link.InsertAtTail(3)
|
||||
link.InsertAtTail(4)
|
||||
|
||||
middle1 := link.GetMiddleNode()
|
||||
assert.Equal(3, middle1.Value)
|
||||
|
||||
link.InsertAtTail(5)
|
||||
link.InsertAtTail(6)
|
||||
link.InsertAtTail(7)
|
||||
middle2 := link.GetMiddleNode()
|
||||
assert.Equal(4, middle2.Value)
|
||||
}
|
||||
|
||||
func TestSinglyLink_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSinglyLink_Clear")
|
||||
|
||||
link := NewSinglyLink[int]()
|
||||
|
||||
assert.Equal(true, link.IsEmpty())
|
||||
assert.Equal(0, link.Size())
|
||||
|
||||
link.InsertAtTail(1)
|
||||
assert.Equal(false, link.IsEmpty())
|
||||
assert.Equal(1, link.Size())
|
||||
|
||||
link.Clear()
|
||||
assert.Equal(true, link.IsEmpty())
|
||||
assert.Equal(0, link.Size())
|
||||
}
|
||||
245
datastructure/list/list.go
Normal file
245
datastructure/list/list.go
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// List is a linear table, implemented with slice
|
||||
type List[T any] struct {
|
||||
data []T
|
||||
}
|
||||
|
||||
// NewList return a pointer of List
|
||||
func NewList[T any](data []T) *List[T] {
|
||||
return &List[T]{data: data}
|
||||
}
|
||||
|
||||
// Data return list data
|
||||
func (l *List[T]) Data() []T {
|
||||
return l.data
|
||||
}
|
||||
|
||||
// ValueOf return the value pointer at index of list data.
|
||||
func (l *List[T]) ValueOf(index int) (*T, bool) {
|
||||
if index < 0 || index >= len(l.data) {
|
||||
return nil, false
|
||||
}
|
||||
return &l.data[index], true
|
||||
}
|
||||
|
||||
// IndexOf reture the index of value. if not found return -1
|
||||
func (l *List[T]) IndexOf(value T) int {
|
||||
index := -1
|
||||
data := l.data
|
||||
for i, v := range data {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// Contain checks if the value in the list or not
|
||||
func (l *List[T]) Contain(value T) bool {
|
||||
data := l.data
|
||||
for _, v := range data {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Push append value to the list data
|
||||
func (l *List[T]) Push(value T) {
|
||||
l.data = append(l.data, value)
|
||||
}
|
||||
|
||||
// InsertAtFirst insert value into list at first index
|
||||
func (l *List[T]) InsertAtFirst(value T) {
|
||||
l.InsertAt(0, value)
|
||||
}
|
||||
|
||||
// InsertAtLast insert value into list at last index
|
||||
func (l *List[T]) InsertAtLast(value T) {
|
||||
l.InsertAt(len(l.data), value)
|
||||
}
|
||||
|
||||
// InsertAt insert value into list at index
|
||||
func (l *List[T]) InsertAt(index int, value T) {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
|
||||
if index < 0 || index > size {
|
||||
return
|
||||
}
|
||||
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
|
||||
}
|
||||
|
||||
// PopFirst delete the first value of list and return it
|
||||
func (l *List[T]) PopFirst() (*T, bool) {
|
||||
if len(l.data) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
v := l.data[0]
|
||||
l.DeleteAt(0)
|
||||
|
||||
return &v, true
|
||||
}
|
||||
|
||||
// PopLast delete the last value of list and return it
|
||||
func (l *List[T]) PopLast() (*T, bool) {
|
||||
size := len(l.data)
|
||||
if size == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
v := l.data[size-1]
|
||||
l.DeleteAt(size - 1)
|
||||
|
||||
return &v, true
|
||||
}
|
||||
|
||||
// DeleteAt delete the value of list at index
|
||||
func (l *List[T]) DeleteAt(index int) {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
if index < 0 || index > size-1 {
|
||||
return
|
||||
}
|
||||
if index == size-1 {
|
||||
data = append(data[:index])
|
||||
} else {
|
||||
data = append(data[:index], data[index+1:]...)
|
||||
}
|
||||
l.data = data
|
||||
}
|
||||
|
||||
// UpdateAt update value of list at index, index shoud between 0 and list size -1
|
||||
func (l *List[T]) UpdateAt(index int, value T) {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
|
||||
if index < 0 || index >= size {
|
||||
return
|
||||
}
|
||||
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
|
||||
}
|
||||
|
||||
// Equtal compare list to other list, use reflect.DeepEqual
|
||||
func (l *List[T]) Equtal(other *List[T]) bool {
|
||||
if len(l.data) != len(other.data) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(l.data); i++ {
|
||||
if !reflect.DeepEqual(l.data[i], other.data[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsEmpty check if the list is empty or not
|
||||
func (l *List[T]) IsEmpty() bool {
|
||||
return len(l.data) == 0
|
||||
}
|
||||
|
||||
// Clear the data of list
|
||||
func (l *List[T]) Clear() {
|
||||
l.data = make([]T, 0, 0)
|
||||
}
|
||||
|
||||
// Clone return a copy of list
|
||||
func (l *List[T]) Clone() *List[T] {
|
||||
cl := NewList(make([]T, len(l.data)))
|
||||
copy(cl.data, l.data)
|
||||
|
||||
return cl
|
||||
}
|
||||
|
||||
// Merge two list, return new list, don't change original list
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||
l1, l2 := len(l.data), len(other.data)
|
||||
ml := NewList(make([]T, l1+l2, l1+l2))
|
||||
|
||||
data := append([]T{}, append(l.data, other.data...)...)
|
||||
ml.data = data
|
||||
|
||||
return ml
|
||||
}
|
||||
|
||||
// Size return number of list data items
|
||||
func (l *List[T]) Size() int {
|
||||
return len(l.data)
|
||||
}
|
||||
|
||||
// Swap the value of index i and j in list
|
||||
func (l *List[T]) Swap(i, j int) {
|
||||
size := len(l.data)
|
||||
if i < 0 || i >= size || j < 0 || j >= size {
|
||||
return
|
||||
}
|
||||
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||
}
|
||||
|
||||
// Reverse the item order of list
|
||||
func (l *List[T]) Reverse() {
|
||||
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
|
||||
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Unique remove duplicate items in list
|
||||
func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
|
||||
uniqueData := make([]T, 0, 0)
|
||||
for i := 0; i < size; i++ {
|
||||
value := data[i]
|
||||
skip := true
|
||||
for _, v := range uniqueData {
|
||||
if reflect.DeepEqual(value, v) {
|
||||
skip = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
uniqueData = append(uniqueData, value)
|
||||
}
|
||||
}
|
||||
|
||||
l.data = uniqueData
|
||||
}
|
||||
|
||||
// Union creates a new list contain all element in list l and other, remove duplicate element.
|
||||
func (l *List[T]) Union(other *List[T]) *List[T] {
|
||||
res := NewList([]T{})
|
||||
|
||||
res.data = append(res.data, l.data...)
|
||||
res.data = append(res.data, other.data...)
|
||||
res.Unique()
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Intersection creates a new list whose element both be contained in list l and other
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||
res := NewList(make([]T, 0, 0))
|
||||
|
||||
for _, v := range l.data {
|
||||
if other.Contain(v) {
|
||||
res.data = append(res.data, v)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
272
datastructure/list/list_test.go
Normal file
272
datastructure/list/list_test.go
Normal file
@@ -0,0 +1,272 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestListData(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListData")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||
}
|
||||
|
||||
func TestValueOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestValueOf")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
v, ok := list.ValueOf(0)
|
||||
assert.Equal(1, *v)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = list.ValueOf(3)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestIndexOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIndexOf")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
i := list.IndexOf(1)
|
||||
assert.Equal(0, i)
|
||||
|
||||
i = list.IndexOf(4)
|
||||
assert.Equal(-1, i)
|
||||
}
|
||||
|
||||
func TestContain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestContain")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
assert.Equal(true, list.Contain(1))
|
||||
assert.Equal(false, list.Contain(0))
|
||||
}
|
||||
|
||||
func TestPush(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPush")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
list.Push(4)
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
}
|
||||
|
||||
func TestInsertAtFirst(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestInsertAtFirst")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
list.InsertAtFirst(0)
|
||||
|
||||
assert.Equal([]int{0, 1, 2, 3}, list.Data())
|
||||
}
|
||||
|
||||
func TestInsertAtLast(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestInsertAtLast")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
list.InsertAtLast(4)
|
||||
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
}
|
||||
|
||||
func TestInsertAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestInsertAt")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
|
||||
list.InsertAt(-1, 0)
|
||||
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||
|
||||
list.InsertAt(4, 0)
|
||||
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||
|
||||
list.InsertAt(0, 0)
|
||||
assert.Equal([]int{0, 1, 2, 3}, list.Data())
|
||||
|
||||
list.InsertAt(4, 4)
|
||||
assert.Equal([]int{0, 1, 2, 3, 4}, list.Data())
|
||||
}
|
||||
|
||||
func TestPopFirst(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPopFirst")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
v, ok := list.PopFirst()
|
||||
assert.Equal(1, *v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal([]int{2, 3}, list.Data())
|
||||
|
||||
list2 := NewList([]int{})
|
||||
_, ok = list2.PopFirst()
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal([]int{}, list2.Data())
|
||||
}
|
||||
|
||||
func TestPopLast(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPopLast")
|
||||
|
||||
list := NewList([]int{1, 2, 3})
|
||||
v, ok := list.PopLast()
|
||||
assert.Equal(3, *v)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal([]int{1, 2}, list.Data())
|
||||
|
||||
list2 := NewList([]int{})
|
||||
_, ok = list2.PopLast()
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal([]int{}, list2.Data())
|
||||
}
|
||||
|
||||
func TestDeleteAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDeleteAt")
|
||||
|
||||
list := NewList([]int{1, 2, 3, 4})
|
||||
|
||||
list.DeleteAt(-1)
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
|
||||
list.DeleteAt(4)
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
|
||||
list.DeleteAt(0)
|
||||
assert.Equal([]int{2, 3, 4}, list.Data())
|
||||
|
||||
list.DeleteAt(2)
|
||||
assert.Equal([]int{2, 3}, list.Data())
|
||||
}
|
||||
|
||||
func TestUpdateAt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUpdateAt")
|
||||
|
||||
list := NewList([]int{1, 2, 3, 4})
|
||||
|
||||
list.UpdateAt(-1, 0)
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
|
||||
list.UpdateAt(4, 0)
|
||||
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||
|
||||
list.UpdateAt(0, 5)
|
||||
assert.Equal([]int{5, 2, 3, 4}, list.Data())
|
||||
|
||||
list.UpdateAt(3, 1)
|
||||
assert.Equal([]int{5, 2, 3, 1}, list.Data())
|
||||
}
|
||||
|
||||
func TestEqutal(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEqutal")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{1, 2, 3, 4})
|
||||
list3 := NewList([]int{1, 2, 3})
|
||||
|
||||
assert.Equal(true, list1.Equtal(list2))
|
||||
assert.Equal(false, list1.Equtal(list3))
|
||||
}
|
||||
|
||||
func TestIsEmpty(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsEmpty")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{})
|
||||
|
||||
assert.Equal(false, list1.IsEmpty())
|
||||
assert.Equal(true, list2.IsEmpty())
|
||||
}
|
||||
|
||||
func TestIsClear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsClear")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list1.Clear()
|
||||
empty := NewList([]int{})
|
||||
|
||||
assert.Equal(empty, list1)
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestClone")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := list1.Clone()
|
||||
|
||||
assert.Equal(true, list1.Equtal(list2))
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMerge")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{4, 5, 6})
|
||||
expected := NewList([]int{1, 2, 3, 4, 4, 5, 6})
|
||||
|
||||
list3 := list1.Merge(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSize")
|
||||
|
||||
list := NewList([]int{1, 2, 3, 4})
|
||||
empty := NewList([]int{})
|
||||
|
||||
assert.Equal(4, list.Size())
|
||||
assert.Equal(0, empty.Size())
|
||||
}
|
||||
|
||||
func TestSwap(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSwap")
|
||||
|
||||
list := NewList([]int{1, 2, 3, 4})
|
||||
expected := NewList([]int{4, 2, 3, 1})
|
||||
|
||||
list.Swap(0, 3)
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
}
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReverse")
|
||||
|
||||
list := NewList([]int{1, 2, 3, 4})
|
||||
expected := NewList([]int{4, 3, 2, 1})
|
||||
|
||||
list.Reverse()
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
}
|
||||
|
||||
func TestUnique(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUnique")
|
||||
|
||||
list := NewList([]int{1, 2, 2, 3, 4})
|
||||
expected := NewList([]int{1, 2, 3, 4})
|
||||
|
||||
list.Unique()
|
||||
|
||||
assert.Equal(true, expected.Equtal(list))
|
||||
}
|
||||
|
||||
func TestUnion(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUnion")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{4, 5, 6})
|
||||
expected := NewList([]int{1, 2, 3, 4, 5, 6})
|
||||
|
||||
list3 := list1.Union(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
}
|
||||
|
||||
func TestIntersection(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIntersection")
|
||||
|
||||
list1 := NewList([]int{1, 2, 3, 4})
|
||||
list2 := NewList([]int{4, 5, 6})
|
||||
expected := NewList([]int{4})
|
||||
|
||||
list3 := list1.Intersection(list2)
|
||||
assert.Equal(true, expected.Equtal(list3))
|
||||
}
|
||||
51
datastructure/node.go
Normal file
51
datastructure/node.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
package datastructure
|
||||
|
||||
// LinkNode is a linkedlist node, which have a Value and Pre points to previous node, Next points to a next node of the link.
|
||||
type LinkNode[T any] struct {
|
||||
Value T
|
||||
Pre *LinkNode[T]
|
||||
Next *LinkNode[T]
|
||||
}
|
||||
|
||||
// NewLinkNode return a LinkNode pointer
|
||||
func NewLinkNode[T any](value T) *LinkNode[T] {
|
||||
return &LinkNode[T]{value, nil, nil}
|
||||
}
|
||||
|
||||
// StackNode is a node in stack, which have a Value and Next pointer points to next node in the stack.
|
||||
type StackNode[T any] struct {
|
||||
Value T
|
||||
Next *StackNode[T]
|
||||
}
|
||||
|
||||
// NewStackNode return a StackNode pointer
|
||||
func NewStackNode[T any](value T) *StackNode[T] {
|
||||
return &StackNode[T]{value, nil}
|
||||
}
|
||||
|
||||
// QueueNode is a node in a queue, which have a Value and Next pointer points to next node in the queue.
|
||||
type QueueNode[T any] struct {
|
||||
Value T
|
||||
Next *QueueNode[T]
|
||||
}
|
||||
|
||||
// NewQueueNode return a QueueNode pointer
|
||||
func NewQueueNode[T any](value T) *QueueNode[T] {
|
||||
return &QueueNode[T]{value, nil}
|
||||
}
|
||||
|
||||
// TreeNode is node of tree
|
||||
type TreeNode[T any] struct {
|
||||
Data T
|
||||
Left *TreeNode[T]
|
||||
Right *TreeNode[T]
|
||||
}
|
||||
|
||||
// NewTreeNode return a TreeNode pointer
|
||||
func NewTreeNode[T any](data T) *TreeNode[T] {
|
||||
return &TreeNode[T]{data, nil, nil}
|
||||
}
|
||||
114
datastructure/queue/arrayqueue.go
Normal file
114
datastructure/queue/arrayqueue.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ArrayQueue implements queue with slice
|
||||
type ArrayQueue[T any] struct {
|
||||
items []T
|
||||
head int
|
||||
tail int
|
||||
capacity int
|
||||
size int
|
||||
}
|
||||
|
||||
func NewArrayQueue[T any](capacity int) *ArrayQueue[T] {
|
||||
return &ArrayQueue[T]{
|
||||
items: make([]T, 0, capacity),
|
||||
head: 0,
|
||||
tail: 0,
|
||||
capacity: capacity,
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
func (q *ArrayQueue[T]) Data() []T {
|
||||
items := []T{}
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
items = append(items, q.items[i])
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// Size return length of queue data
|
||||
func (q *ArrayQueue[T]) Size() int {
|
||||
return q.size
|
||||
}
|
||||
|
||||
// IsEmpty checks if queue is empty or not
|
||||
func (q *ArrayQueue[T]) IsEmpty() bool {
|
||||
return q.size == 0
|
||||
}
|
||||
|
||||
// Front return front value of queue
|
||||
func (q *ArrayQueue[T]) Front() T {
|
||||
return q.items[0]
|
||||
}
|
||||
|
||||
// Back return back value of queue
|
||||
func (q *ArrayQueue[T]) Back() T {
|
||||
return q.items[q.size-1]
|
||||
}
|
||||
|
||||
// EnQueue put element into queue
|
||||
func (q *ArrayQueue[T]) Enqueue(item T) bool {
|
||||
if q.head == 0 && q.tail == q.capacity {
|
||||
return false
|
||||
} else if q.head != 0 && q.tail == q.capacity {
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
q.items[i-q.head] = q.items[i]
|
||||
}
|
||||
q.tail = q.tail - q.head
|
||||
q.head = 0
|
||||
}
|
||||
|
||||
q.items = append(q.items, item)
|
||||
q.tail++
|
||||
q.size++
|
||||
return true
|
||||
}
|
||||
|
||||
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
|
||||
func (q *ArrayQueue[T]) Dequeue() (T, bool) {
|
||||
var item T
|
||||
if q.head == q.tail {
|
||||
return item, false
|
||||
}
|
||||
item = q.items[q.head]
|
||||
q.head++
|
||||
q.size--
|
||||
return item, true
|
||||
}
|
||||
|
||||
// Clear the queue data
|
||||
func (q *ArrayQueue[T]) Clear() {
|
||||
capacity := q.capacity
|
||||
q.items = make([]T, 0, capacity)
|
||||
q.head = 0
|
||||
q.tail = 0
|
||||
q.size = 0
|
||||
q.capacity = capacity
|
||||
}
|
||||
|
||||
// Contain checks if the value is in queue or not
|
||||
func (q *ArrayQueue[T]) Contain(value T) bool {
|
||||
for _, v := range q.items {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Print queue data
|
||||
func (q *ArrayQueue[T]) Print() {
|
||||
info := "["
|
||||
for i := q.head; i < q.tail; i++ {
|
||||
info += fmt.Sprintf("%+v, ", q.items[i])
|
||||
}
|
||||
info += "]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
102
datastructure/queue/arrayqueue_test.go
Normal file
102
datastructure/queue/arrayqueue_test.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestArrayQueue_Enqueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
|
||||
|
||||
queue := NewArrayQueue[int](5)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
expected := []int{1, 2, 3}
|
||||
data := queue.Data()
|
||||
size := queue.Size()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(expected, data)
|
||||
assert.Equal(3, size)
|
||||
}
|
||||
|
||||
func TestArrayQueue_Dequeue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Dequeue")
|
||||
|
||||
queue := NewArrayQueue[int](4)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val, ok := queue.Dequeue()
|
||||
assert.Equal(true, ok)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{2, 3}, queue.Data())
|
||||
}
|
||||
|
||||
func TestArrayQueue_Front(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Front")
|
||||
|
||||
queue := NewArrayQueue[int](4)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val := queue.Front()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(1, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
|
||||
func TestArrayQueue_Back(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Back")
|
||||
|
||||
queue := NewArrayQueue[int](4)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
val := queue.Back()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal(3, val)
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
}
|
||||
|
||||
func TestArrayQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Contain")
|
||||
|
||||
queue := NewArrayQueue[int](4)
|
||||
queue.Enqueue(1)
|
||||
queue.Enqueue(2)
|
||||
queue.Enqueue(3)
|
||||
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(4))
|
||||
}
|
||||
|
||||
func TestArrayQueue_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayQueue_Clear")
|
||||
|
||||
queue := NewArrayQueue[int](4)
|
||||
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Size())
|
||||
|
||||
queue.Enqueue(1)
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
assert.Equal(1, queue.Size())
|
||||
|
||||
queue.Clear()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Size())
|
||||
}
|
||||
118
datastructure/queue/circularqueue.go
Normal file
118
datastructure/queue/circularqueue.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// CircularQueue implements circular queue with slice,
|
||||
// last index of CircularQueue don't contain value, so acturl capacity is size - 1
|
||||
type CircularQueue[T any] struct {
|
||||
data []T
|
||||
front int
|
||||
rear int
|
||||
size int
|
||||
}
|
||||
|
||||
// NewCircularQueue return a empty CircularQueue pointer
|
||||
func NewCircularQueue[T any](size int) *CircularQueue[T] {
|
||||
data := make([]T, size)
|
||||
return &CircularQueue[T]{data: data, front: 0, rear: 0, size: size}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
func (q *CircularQueue[T]) Data() []T {
|
||||
data := []T{}
|
||||
|
||||
front := q.front
|
||||
rear := q.rear
|
||||
if front <= rear {
|
||||
return q.data[front:rear]
|
||||
}
|
||||
|
||||
data = append(data, q.data[front:]...)
|
||||
data = append(data, q.data[0:rear]...)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Length return current data length of queue
|
||||
func (q *CircularQueue[T]) Length() int {
|
||||
if q.size == 0 {
|
||||
return 0
|
||||
}
|
||||
return (q.rear - q.front + q.size) % q.size
|
||||
}
|
||||
|
||||
// IsEmpty checks if queue is empty or not
|
||||
func (q *CircularQueue[T]) IsEmpty() bool {
|
||||
return q.front == q.rear
|
||||
}
|
||||
|
||||
// IsFull checks if queue is full or not
|
||||
func (q *CircularQueue[T]) IsFull() bool {
|
||||
return (q.rear+1)%q.size == q.front
|
||||
}
|
||||
|
||||
// Front return front value of queue
|
||||
func (q *CircularQueue[T]) Front() T {
|
||||
return q.data[q.front]
|
||||
}
|
||||
|
||||
// Back return back value of queue
|
||||
func (q *CircularQueue[T]) Back() T {
|
||||
if q.rear-1 >= 0 {
|
||||
return q.data[q.rear-1]
|
||||
}
|
||||
return q.data[q.size-1]
|
||||
}
|
||||
|
||||
// EnQueue put element into queue
|
||||
func (q *CircularQueue[T]) EnQueue(value T) error {
|
||||
if q.IsFull() {
|
||||
return errors.New("queue is full!")
|
||||
}
|
||||
|
||||
q.data[q.rear] = value
|
||||
q.rear = (q.rear + 1) % q.size
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeQueue remove head element of queue and return it, if queue is empty, return nil and error
|
||||
func (q *CircularQueue[T]) DeQueue() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
|
||||
headItem := q.data[q.front]
|
||||
var t T
|
||||
q.data[q.front] = t
|
||||
q.front = (q.front + 1) % q.size
|
||||
|
||||
return &headItem, nil
|
||||
}
|
||||
|
||||
// Clear the queue data
|
||||
func (q *CircularQueue[T]) Clear() {
|
||||
q.data = []T{}
|
||||
q.front = 0
|
||||
q.rear = 0
|
||||
q.size = 0
|
||||
}
|
||||
|
||||
// Contain checks if the value is in queue or not
|
||||
func (q *CircularQueue[T]) Contain(value T) bool {
|
||||
for _, v := range q.data {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Print queue data
|
||||
func (q *CircularQueue[T]) Print() {
|
||||
fmt.Printf("%+v\n", q)
|
||||
}
|
||||
148
datastructure/queue/circularqueue_test.go
Normal file
148
datastructure/queue/circularqueue_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestCircularQueue_EnQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_EnQueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
|
||||
queue.Print()
|
||||
// assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
assert.Equal(5, queue.Length())
|
||||
|
||||
err := queue.EnQueue(6)
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
func TestCircularQueue_DeQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
|
||||
val, err := queue.DeQueue()
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(1, *val)
|
||||
assert.Equal(false, queue.IsFull())
|
||||
|
||||
val, _ = queue.DeQueue()
|
||||
queue.Print()
|
||||
assert.Equal(2, *val)
|
||||
|
||||
queue.EnQueue(6)
|
||||
queue.Print()
|
||||
assert.Equal(false, queue.IsFull())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Front(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
|
||||
queue.Print()
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
|
||||
queue.Print()
|
||||
|
||||
val := queue.Front()
|
||||
assert.Equal(3, val)
|
||||
assert.Equal(5, queue.Length())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Back(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(5, queue.Back())
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal(7, queue.Back())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||
|
||||
queue := NewCircularQueue[int](2)
|
||||
queue.EnQueue(1)
|
||||
assert.Equal(true, queue.Contain(1))
|
||||
assert.Equal(false, queue.Contain(2))
|
||||
}
|
||||
|
||||
func TestCircularQueue_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Clear")
|
||||
|
||||
queue := NewCircularQueue[int](3)
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Length())
|
||||
|
||||
queue.EnQueue(1)
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
assert.Equal(1, queue.Length())
|
||||
|
||||
queue.Clear()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
assert.Equal(0, queue.Length())
|
||||
}
|
||||
|
||||
func TestCircularQueue_Data(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
||||
|
||||
queue := NewCircularQueue[int](6)
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
queue.EnQueue(4)
|
||||
queue.EnQueue(5)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||
|
||||
queue.DeQueue()
|
||||
queue.DeQueue()
|
||||
queue.EnQueue(6)
|
||||
queue.EnQueue(7)
|
||||
|
||||
queue.Print()
|
||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
||||
|
||||
}
|
||||
104
datastructure/queue/linkedqueue.go
Normal file
104
datastructure/queue/linkedqueue.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// LinkedQueue implements queue with link list
|
||||
type LinkedQueue[T any] struct {
|
||||
head *datastructure.QueueNode[T]
|
||||
tail *datastructure.QueueNode[T]
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLinkedQueue return a empty LinkedQueue pointer
|
||||
func NewLinkedQueue[T any]() *LinkedQueue[T] {
|
||||
return &LinkedQueue[T]{head: nil, tail: nil, length: 0}
|
||||
}
|
||||
|
||||
// Data return queue data
|
||||
func (q *LinkedQueue[T]) Data() []T {
|
||||
res := []T{}
|
||||
current := q.head
|
||||
|
||||
for current != nil {
|
||||
res = append(res, current.Value)
|
||||
current = current.Next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Size return length of queue data
|
||||
func (q *LinkedQueue[T]) Size() int {
|
||||
return q.length
|
||||
}
|
||||
|
||||
// IsEmpty checks if queue is empty or not
|
||||
func (q *LinkedQueue[T]) IsEmpty() bool {
|
||||
return q.length == 0
|
||||
}
|
||||
|
||||
// EnQueue add element into queue
|
||||
func (q *LinkedQueue[T]) EnQueue(value T) {
|
||||
newNode := datastructure.NewQueueNode(value)
|
||||
|
||||
if q.IsEmpty() {
|
||||
q.head = newNode
|
||||
q.tail = newNode
|
||||
} else {
|
||||
q.tail.Next = newNode
|
||||
q.tail = newNode
|
||||
}
|
||||
q.length++
|
||||
}
|
||||
|
||||
// DeQueue delete head element of queue then return it, if queue is empty, return nil and error
|
||||
func (q *LinkedQueue[T]) DeQueue() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
|
||||
head := q.head
|
||||
q.head = q.head.Next
|
||||
q.length--
|
||||
|
||||
return &head.Value, nil
|
||||
}
|
||||
|
||||
// Front return front value of queue
|
||||
func (q *LinkedQueue[T]) Front() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
return &q.head.Value, nil
|
||||
}
|
||||
|
||||
// Back return back value of queue
|
||||
func (q *LinkedQueue[T]) Back() (*T, error) {
|
||||
if q.IsEmpty() {
|
||||
return nil, errors.New("queue is empty")
|
||||
}
|
||||
return &q.tail.Value, nil
|
||||
}
|
||||
|
||||
// Clear clear the queue data
|
||||
func (q *LinkedQueue[T]) Clear() {
|
||||
q.head = nil
|
||||
q.tail = nil
|
||||
q.length = 0
|
||||
}
|
||||
|
||||
// Print all nodes info of queue link
|
||||
func (q *LinkedQueue[T]) Print() {
|
||||
current := q.head
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
current = current.Next
|
||||
}
|
||||
info += " ]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
84
datastructure/queue/linkedqueue_test.go
Normal file
84
datastructure/queue/linkedqueue_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestLinkedQueue_EnQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_EnQueue")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||
assert.Equal(3, queue.Size())
|
||||
}
|
||||
|
||||
func TestLinkedQueue_DeQueue(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
|
||||
val, _ := queue.DeQueue()
|
||||
|
||||
queue.Print()
|
||||
|
||||
assert.Equal([]int{2, 3}, queue.Data())
|
||||
assert.Equal(1, *val)
|
||||
}
|
||||
|
||||
func TestLinkedQueue_Front(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_Front")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
_, err := queue.Front()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
|
||||
val, err := queue.Front()
|
||||
assert.Equal(1, *val)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
func TestLinkedQueue_Back(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
_, err := queue.Back()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
|
||||
val, err := queue.Back()
|
||||
assert.Equal(3, *val)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
func TestLinkedQueue_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
|
||||
|
||||
queue := NewLinkedQueue[int]()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
|
||||
queue.EnQueue(1)
|
||||
queue.EnQueue(2)
|
||||
queue.EnQueue(3)
|
||||
assert.Equal(false, queue.IsEmpty())
|
||||
|
||||
queue.Clear()
|
||||
assert.Equal(true, queue.IsEmpty())
|
||||
}
|
||||
136
datastructure/set/set.go
Normal file
136
datastructure/set/set.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package datastructure
|
||||
|
||||
// Set is a data container, like slice, but element of set is not duplicate
|
||||
type Set[T comparable] map[T]bool
|
||||
|
||||
// NewSet return a instance of set
|
||||
func NewSet[T comparable](values ...T) Set[T] {
|
||||
set := make(Set[T])
|
||||
set.Add(values...)
|
||||
return set
|
||||
}
|
||||
|
||||
// Add value to set
|
||||
func (s Set[T]) Add(values ...T) {
|
||||
for _, v := range values {
|
||||
s[v] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Contain checks if set contains value or not
|
||||
func (s Set[T]) Contain(value T) bool {
|
||||
_, ok := s[value]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Contain checks if set contains other set
|
||||
func (s Set[T]) ContainAll(other Set[T]) bool {
|
||||
for k := range other {
|
||||
_, ok := s[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Clone return a copy of set
|
||||
func (s Set[T]) Clone() Set[T] {
|
||||
set := NewSet[T]()
|
||||
set.Add(s.Values()...)
|
||||
return set
|
||||
}
|
||||
|
||||
// Delete value of set
|
||||
func (s Set[T]) Delete(values ...T) {
|
||||
for _, v := range values {
|
||||
delete(s, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Equal checks if two set has same elements or not
|
||||
func (s Set[T]) Equal(other Set[T]) bool {
|
||||
if s.Size() != other.Size() {
|
||||
return false
|
||||
}
|
||||
|
||||
return s.ContainAll(other) && other.ContainAll(s)
|
||||
}
|
||||
|
||||
// Iterate call function by every element of set
|
||||
func (s Set[T]) Iterate(fn func(value T)) {
|
||||
for v := range s {
|
||||
fn(v)
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty checks the set is empty or not
|
||||
func (s Set[T]) IsEmpty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
// Size get the number of elements in set
|
||||
func (s Set[T]) Size() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// Values return all values of set
|
||||
func (s Set[T]) Values() []T {
|
||||
values := make([]T, 0, 0)
|
||||
|
||||
s.Iterate(func(value T) {
|
||||
values = append(values, value)
|
||||
})
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Union creates a new set contain all element of set s and other
|
||||
func (s Set[T]) Union(other Set[T]) Set[T] {
|
||||
set := s.Clone()
|
||||
set.Add(other.Values()...)
|
||||
return set
|
||||
}
|
||||
|
||||
// Intersection creates a new set whose element both be contained in set s and other
|
||||
func (s Set[T]) Intersection(other Set[T]) Set[T] {
|
||||
set := NewSet[T]()
|
||||
s.Iterate(func(value T) {
|
||||
if other.Contain(value) {
|
||||
set.Add(value)
|
||||
}
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// SymmetricDifference creates a new set whose element is in set1 or set2, but not in both sets
|
||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T] {
|
||||
set := NewSet[T]()
|
||||
s.Iterate(func(value T) {
|
||||
if !other.Contain(value) {
|
||||
set.Add(value)
|
||||
}
|
||||
})
|
||||
|
||||
other.Iterate(func(value T) {
|
||||
if !s.Contain(value) {
|
||||
set.Add(value)
|
||||
}
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// Minus creates an set of whose element in origin set but not in compared set
|
||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
|
||||
set := NewSet[T]()
|
||||
|
||||
s.Iterate(func(value T) {
|
||||
if !comparedSet.Contain(value) {
|
||||
set.Add(value)
|
||||
}
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
149
datastructure/set/set_test.go
Normal file
149
datastructure/set/set_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestSet_Add(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Add")
|
||||
|
||||
set := NewSet[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
expected := NewSet(1, 2, 3)
|
||||
|
||||
assert.Equal(true, set.Equal(expected))
|
||||
}
|
||||
|
||||
func TestSet_Contain(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Contain")
|
||||
|
||||
set := NewSet[int]()
|
||||
set.Add(1, 2, 3)
|
||||
|
||||
assert.Equal(true, set.Contain(1))
|
||||
assert.Equal(false, set.Contain(4))
|
||||
}
|
||||
|
||||
func TestSet_ContainAll(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_ContainAll")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(1, 2)
|
||||
set3 := NewSet(1, 2, 3, 4)
|
||||
|
||||
assert.Equal(true, set1.ContainAll(set2))
|
||||
assert.Equal(false, set1.ContainAll(set3))
|
||||
}
|
||||
|
||||
func TestSet_Clone(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Clone")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := set1.Clone()
|
||||
|
||||
assert.Equal(true, set1.Size() == set2.Size())
|
||||
assert.Equal(true, set1.ContainAll(set2))
|
||||
}
|
||||
|
||||
func TestSet_Delete(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Delete")
|
||||
|
||||
set := NewSet[int]()
|
||||
set.Add(1, 2, 3)
|
||||
set.Delete(3)
|
||||
|
||||
expected := NewSet(1, 2)
|
||||
|
||||
assert.Equal(true, set.Equal(expected))
|
||||
}
|
||||
|
||||
func TestSet_Equal(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Equal")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(1, 2, 3)
|
||||
set3 := NewSet(1, 2, 3, 4)
|
||||
|
||||
assert.Equal(true, set1.Equal(set2))
|
||||
assert.Equal(false, set1.Equal(set3))
|
||||
}
|
||||
|
||||
func TestSet_Iterate(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Iterate")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
arr := []int{}
|
||||
set.Iterate(func(value int) {
|
||||
arr = append(arr, value)
|
||||
})
|
||||
|
||||
assert.Equal(3, len(arr))
|
||||
}
|
||||
|
||||
func TestSet_IsEmpty(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_IsEmpty")
|
||||
|
||||
set := NewSet[int]()
|
||||
assert.Equal(true, set.IsEmpty())
|
||||
}
|
||||
|
||||
func TestSet_Size(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Size")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
assert.Equal(3, set.Size())
|
||||
}
|
||||
|
||||
func TestSet_Values(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Values")
|
||||
|
||||
set := NewSet(1, 2, 3)
|
||||
values := set.Values()
|
||||
|
||||
assert.Equal(3, len(values))
|
||||
}
|
||||
|
||||
func TestSet_Union(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Union")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
expected := NewSet(1, 2, 3, 4, 5)
|
||||
unionSet := set1.Union(set2)
|
||||
|
||||
assert.Equal(expected, unionSet)
|
||||
}
|
||||
|
||||
func TestSet_Intersection(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Intersection")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
expected := NewSet(2, 3)
|
||||
intersectionSet := set1.Intersection(set2)
|
||||
|
||||
assert.Equal(expected, intersectionSet)
|
||||
}
|
||||
|
||||
func TestSet_SymmetricDifference(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
|
||||
assert.Equal(NewSet(1, 4, 5), set1.SymmetricDifference(set2))
|
||||
}
|
||||
|
||||
func TestSet_Minus(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSet_Minus")
|
||||
|
||||
set1 := NewSet(1, 2, 3)
|
||||
set2 := NewSet(2, 3, 4, 5)
|
||||
set3 := NewSet(2, 3)
|
||||
|
||||
assert.Equal(NewSet(1), set1.Minus(set2))
|
||||
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
||||
}
|
||||
62
datastructure/stack/arraystack.go
Normal file
62
datastructure/stack/arraystack.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package datastructure
|
||||
|
||||
import "errors"
|
||||
|
||||
// ArrayStack implements stack with slice
|
||||
type ArrayStack[T any] struct {
|
||||
data []T
|
||||
length int
|
||||
}
|
||||
|
||||
// NewArrayStack return a empty ArrayStack pointer
|
||||
func NewArrayStack[T any]() *ArrayStack[T] {
|
||||
return &ArrayStack[T]{data: []T{}, length: 0}
|
||||
}
|
||||
|
||||
// Data return stack data
|
||||
func (s *ArrayStack[T]) Data() []T {
|
||||
return s.data
|
||||
}
|
||||
|
||||
// Size return length of stack data
|
||||
func (s *ArrayStack[T]) Size() int {
|
||||
return s.length
|
||||
}
|
||||
|
||||
// IsEmpty checks if stack is empty or not
|
||||
func (s *ArrayStack[T]) IsEmpty() bool {
|
||||
return s.length == 0
|
||||
}
|
||||
|
||||
// Push element into stack
|
||||
func (s *ArrayStack[T]) Push(value T) {
|
||||
s.data = append([]T{value}, s.data...)
|
||||
s.length++
|
||||
}
|
||||
|
||||
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
|
||||
func (s *ArrayStack[T]) Pop() (*T, error) {
|
||||
if s.IsEmpty() {
|
||||
return nil, errors.New("stack is empty")
|
||||
}
|
||||
|
||||
topItem := s.data[0]
|
||||
s.data = s.data[1:]
|
||||
s.length--
|
||||
|
||||
return &topItem, nil
|
||||
}
|
||||
|
||||
// Peak return the top element of stack then return it
|
||||
func (s *ArrayStack[T]) Peak() (*T, error) {
|
||||
if s.IsEmpty() {
|
||||
return nil, errors.New("stack is empty")
|
||||
}
|
||||
return &s.data[0], nil
|
||||
}
|
||||
|
||||
// Clear the stack data
|
||||
func (s *ArrayStack[T]) Clear() {
|
||||
s.data = []T{}
|
||||
s.length = 0
|
||||
}
|
||||
77
datastructure/stack/arraystack_test.go
Normal file
77
datastructure/stack/arraystack_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestArrayStack_Push(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayStack_Push")
|
||||
|
||||
stack := NewArrayStack[int]()
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := stack.Data()
|
||||
length := stack.Size()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
assert.Equal(3, length)
|
||||
}
|
||||
|
||||
func TestArrayStack_Pop(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayStack_Pop")
|
||||
|
||||
stack := NewArrayStack[int]()
|
||||
_, err := stack.Pop()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
topItem, err := stack.Pop()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(3, *topItem)
|
||||
|
||||
expected := []int{2, 1}
|
||||
assert.Equal(expected, stack.Data())
|
||||
}
|
||||
|
||||
func TestArrayStack_Peak(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayStack_Peak")
|
||||
|
||||
stack := NewArrayStack[int]()
|
||||
_, err := stack.Peak()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
topItem, err := stack.Peak()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(3, *topItem)
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
assert.Equal(expected, stack.Data())
|
||||
}
|
||||
|
||||
func TestArrayStack_Clear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestArrayStack_Clear")
|
||||
|
||||
stack := NewArrayStack[int]()
|
||||
assert.Equal(true, stack.IsEmpty())
|
||||
assert.Equal(0, stack.Size())
|
||||
|
||||
stack.Push(1)
|
||||
assert.Equal(false, stack.IsEmpty())
|
||||
assert.Equal(1, stack.Size())
|
||||
|
||||
stack.Clear()
|
||||
assert.Equal(true, stack.IsEmpty())
|
||||
assert.Equal(0, stack.Size())
|
||||
}
|
||||
94
datastructure/stack/linkedstack.go
Normal file
94
datastructure/stack/linkedstack.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
)
|
||||
|
||||
// LinkedStack implements stack with link list
|
||||
type LinkedStack[T any] struct {
|
||||
top *datastructure.StackNode[T]
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLinkedStack return a empty LinkedStack pointer
|
||||
func NewLinkedStack[T any]() *LinkedStack[T] {
|
||||
return &LinkedStack[T]{top: nil, length: 0}
|
||||
}
|
||||
|
||||
// Data return stack data
|
||||
func (s *LinkedStack[T]) Data() []T {
|
||||
res := []T{}
|
||||
current := s.top
|
||||
|
||||
for current != nil {
|
||||
res = append(res, current.Value)
|
||||
current = current.Next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Size return length of stack data
|
||||
func (s *LinkedStack[T]) Size() int {
|
||||
return s.length
|
||||
}
|
||||
|
||||
// IsEmpty checks if stack is empty or not
|
||||
func (s *LinkedStack[T]) IsEmpty() bool {
|
||||
return s.length == 0
|
||||
}
|
||||
|
||||
// Push element into stack
|
||||
func (s *LinkedStack[T]) Push(value T) {
|
||||
newNode := datastructure.NewStackNode(value)
|
||||
top := s.top
|
||||
if top == nil {
|
||||
s.top = newNode
|
||||
} else {
|
||||
newNode.Next = top
|
||||
s.top = newNode
|
||||
}
|
||||
|
||||
s.length++
|
||||
}
|
||||
|
||||
// Pop delete the top element of stack then return it, if stack is empty, return nil and error
|
||||
func (s *LinkedStack[T]) Pop() (*T, error) {
|
||||
if s.IsEmpty() {
|
||||
return nil, errors.New("stack is empty")
|
||||
}
|
||||
|
||||
top := s.top
|
||||
s.top = s.top.Next
|
||||
s.length--
|
||||
|
||||
return &top.Value, nil
|
||||
}
|
||||
|
||||
// Peak return the top element of stack then return it
|
||||
func (s *LinkedStack[T]) Peak() (*T, error) {
|
||||
if s.IsEmpty() {
|
||||
return nil, errors.New("stack is empty")
|
||||
}
|
||||
return &s.top.Value, nil
|
||||
}
|
||||
|
||||
// Clear clear the stack data
|
||||
func (s *LinkedStack[T]) Clear() {
|
||||
s.top = nil
|
||||
s.length = 0
|
||||
}
|
||||
|
||||
// Print all nodes info of stack link
|
||||
func (s *LinkedStack[T]) Print() {
|
||||
current := s.top
|
||||
info := "[ "
|
||||
for current != nil {
|
||||
info += fmt.Sprintf("%+v, ", current)
|
||||
current = current.Next
|
||||
}
|
||||
info += " ]"
|
||||
fmt.Println(info)
|
||||
}
|
||||
80
datastructure/stack/linkedstack_test.go
Normal file
80
datastructure/stack/linkedstack_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestLinkedStack_Push(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedStack_Push")
|
||||
|
||||
stack := NewLinkedStack[int]()
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
stack.Print()
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
values := stack.Data()
|
||||
size := stack.Size()
|
||||
|
||||
assert.Equal(expected, values)
|
||||
assert.Equal(3, size)
|
||||
}
|
||||
|
||||
func TestLinkedStack_Pop(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedStack_Pop")
|
||||
|
||||
stack := NewLinkedStack[int]()
|
||||
_, err := stack.Pop()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
topItem, err := stack.Pop()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(3, *topItem)
|
||||
|
||||
expected := []int{2, 1}
|
||||
stack.Print()
|
||||
assert.Equal(expected, stack.Data())
|
||||
}
|
||||
|
||||
func TestLinkedStack_Peak(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedStack_Peak")
|
||||
|
||||
stack := NewLinkedStack[int]()
|
||||
_, err := stack.Peak()
|
||||
assert.IsNotNil(err)
|
||||
|
||||
stack.Push(1)
|
||||
stack.Push(2)
|
||||
stack.Push(3)
|
||||
|
||||
topItem, err := stack.Peak()
|
||||
assert.IsNil(err)
|
||||
assert.Equal(3, *topItem)
|
||||
|
||||
expected := []int{3, 2, 1}
|
||||
assert.Equal(expected, stack.Data())
|
||||
}
|
||||
|
||||
func TestLinkedStack_Empty(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLinkedStack_Empty")
|
||||
|
||||
stack := NewLinkedStack[int]()
|
||||
assert.Equal(true, stack.IsEmpty())
|
||||
assert.Equal(0, stack.Size())
|
||||
|
||||
stack.Push(1)
|
||||
assert.Equal(false, stack.IsEmpty())
|
||||
assert.Equal(1, stack.Size())
|
||||
|
||||
stack.Clear()
|
||||
assert.Equal(true, stack.IsEmpty())
|
||||
assert.Equal(0, stack.Size())
|
||||
}
|
||||
83
datastructure/tree/bstree.go
Normal file
83
datastructure/tree/bstree.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
// BSTree is a binary search tree data structure in which each node has at most two children,
|
||||
// which are referred to as the left child and the right child.
|
||||
// In BSTree: leftNode < rootNode < rightNode
|
||||
// type T should implements Compare function in lancetconstraints.Comparator interface.
|
||||
type BSTree[T any] struct {
|
||||
root *datastructure.TreeNode[T]
|
||||
}
|
||||
|
||||
// NewBSTree create a BSTree pointer
|
||||
func NewBSTree[T any](rootData T) *BSTree[T] {
|
||||
root := datastructure.NewTreeNode(rootData)
|
||||
return &BSTree[T]{root}
|
||||
}
|
||||
|
||||
// InsertNode insert data into BSTree
|
||||
func (t *BSTree[T]) InsertNode(data T, comparator lancetconstraints.Comparator) {
|
||||
root := t.root
|
||||
newNode := datastructure.NewTreeNode(data)
|
||||
if root == nil {
|
||||
t.root = newNode
|
||||
} else {
|
||||
insertTreeNode(root, newNode, comparator)
|
||||
}
|
||||
}
|
||||
|
||||
// DeletetNode delete data into BSTree
|
||||
func (t *BSTree[T]) DeletetNode(data T, comparator lancetconstraints.Comparator) {
|
||||
deleteTreeNode(t.root, data, comparator)
|
||||
}
|
||||
|
||||
// NodeLevel get node level in BSTree
|
||||
func (t *BSTree[T]) NodeLevel(node *datastructure.TreeNode[T]) int {
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
left := float64(t.NodeLevel(node.Left))
|
||||
right := float64(t.NodeLevel(node.Right))
|
||||
|
||||
return int(math.Max(left, right)) + 1
|
||||
}
|
||||
|
||||
// PreOrderTraverse traverse tree node in pre order
|
||||
func (t *BSTree[T]) PreOrderTraverse() []T {
|
||||
return preOrderTraverse(t.root)
|
||||
}
|
||||
|
||||
// PostOrderTraverse traverse tree node in post order
|
||||
func (t *BSTree[T]) PostOrderTraverse() []T {
|
||||
return postOrderTraverse(t.root)
|
||||
}
|
||||
|
||||
// InOrderTraverse traverse tree node in mid order
|
||||
func (t *BSTree[T]) InOrderTraverse() []T {
|
||||
return inOrderTraverse(t.root)
|
||||
}
|
||||
|
||||
// LevelOrderTraverse traverse tree node in level order
|
||||
func (t *BSTree[T]) LevelOrderTraverse() []T {
|
||||
traversal := make([]T, 0)
|
||||
levelOrderTraverse(t.root, &traversal)
|
||||
return traversal
|
||||
}
|
||||
|
||||
// Depth returns the calculated depth of a binary saerch tree
|
||||
func (t *BSTree[T]) Depth() int {
|
||||
return calculateDepth(t.root, 0)
|
||||
}
|
||||
|
||||
// Print the bstree structure
|
||||
func (t *BSTree[T]) Print() {
|
||||
maxLevel := t.NodeLevel(t.root)
|
||||
nodes := []*datastructure.TreeNode[T]{t.root}
|
||||
printTreeNodes(nodes, 1, maxLevel)
|
||||
}
|
||||
142
datastructure/tree/bstree_test.go
Normal file
142
datastructure/tree/bstree_test.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func TestBSTree_InsertNode(t *testing.T) {
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
bstree.Print()
|
||||
}
|
||||
|
||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
acturl := bstree.PreOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 2, 4, 7}, acturl)
|
||||
}
|
||||
|
||||
func TestBSTree_PostOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
acturl := bstree.PostOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{5, 2, 4, 7, 6}, acturl)
|
||||
}
|
||||
|
||||
func TestBSTree_InOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
acturl := bstree.InOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{2, 4, 5, 6, 7}, acturl)
|
||||
}
|
||||
|
||||
func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
acturl := bstree.LevelOrderTraverse()
|
||||
t.Log(acturl)
|
||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||
}
|
||||
|
||||
func TestBSTree_DeletetNode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_DeletetNode")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
bstree.DeletetNode(4, comparator)
|
||||
bstree.Print()
|
||||
acturl1 := bstree.InOrderTraverse()
|
||||
t.Log(acturl1)
|
||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||
|
||||
//todo
|
||||
// bstree.DeletetNode(6, comparator)
|
||||
// bstree.Print()
|
||||
// acturl2 := bstree.InOrderTraverse()
|
||||
// t.Log(acturl2)
|
||||
// assert.Equal([]int{2, 5, 7}, acturl2)
|
||||
}
|
||||
|
||||
func TestBSTree_Depth(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBSTree_Depth")
|
||||
|
||||
bstree := NewBSTree(6)
|
||||
|
||||
comparator := &intComparator{}
|
||||
bstree.InsertNode(7, comparator)
|
||||
bstree.InsertNode(5, comparator)
|
||||
bstree.InsertNode(2, comparator)
|
||||
bstree.InsertNode(4, comparator)
|
||||
|
||||
bstree.Print()
|
||||
|
||||
assert.Equal(bstree.Depth(), 4)
|
||||
}
|
||||
224
datastructure/tree/tree_internal.go
Normal file
224
datastructure/tree/tree_internal.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datastructure"
|
||||
"github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
)
|
||||
|
||||
func preOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
data := []T{}
|
||||
if node != nil {
|
||||
data = append(data, node.Data)
|
||||
data = append(data, preOrderTraverse(node.Left)...)
|
||||
data = append(data, preOrderTraverse(node.Right)...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func postOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
data := []T{}
|
||||
if node != nil {
|
||||
data = append(data, preOrderTraverse(node.Left)...)
|
||||
data = append(data, preOrderTraverse(node.Right)...)
|
||||
data = append(data, node.Data)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
||||
data := []T{}
|
||||
if node != nil {
|
||||
data = append(data, inOrderTraverse(node.Left)...)
|
||||
data = append(data, node.Data)
|
||||
data = append(data, inOrderTraverse(node.Right)...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
}
|
||||
|
||||
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
|
||||
preOrderPrint(node.Left)
|
||||
preOrderPrint(node.Right)
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
}
|
||||
|
||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
|
||||
inOrderPrint(node.Left)
|
||||
fmt.Printf("%v, ", node.Data)
|
||||
inOrderPrint(node.Right)
|
||||
}
|
||||
|
||||
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
||||
var q []*datastructure.TreeNode[T] // queue
|
||||
var n *datastructure.TreeNode[T] // temp node
|
||||
|
||||
q = append(q, root)
|
||||
|
||||
for len(q) != 0 {
|
||||
n, q = q[0], q[1:]
|
||||
*traversal = append(*traversal, n.Data)
|
||||
if n.Left != nil {
|
||||
q = append(q, n.Left)
|
||||
}
|
||||
if n.Right != nil {
|
||||
q = append(q, n.Right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func insertTreeNode[T any](rootNode, newNode *datastructure.TreeNode[T], comparator lancetconstraints.Comparator) {
|
||||
if comparator.Compare(newNode.Data, rootNode.Data) == -1 {
|
||||
if rootNode.Left == nil {
|
||||
rootNode.Left = newNode
|
||||
} else {
|
||||
insertTreeNode(rootNode.Left, newNode, comparator)
|
||||
}
|
||||
} else {
|
||||
if rootNode.Right == nil {
|
||||
rootNode.Right = newNode
|
||||
} else {
|
||||
insertTreeNode(rootNode.Right, newNode, comparator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo, delete root node failed
|
||||
func deleteTreeNode[T any](node *datastructure.TreeNode[T], data T, comparator lancetconstraints.Comparator) *datastructure.TreeNode[T] {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
if comparator.Compare(data, node.Data) == -1 {
|
||||
node.Left = deleteTreeNode(node.Left, data, comparator)
|
||||
} else if comparator.Compare(data, node.Data) == 1 {
|
||||
node.Right = deleteTreeNode(node.Right, data, comparator)
|
||||
} else {
|
||||
if node.Left == nil {
|
||||
node = node.Right
|
||||
} else if node.Right == nil {
|
||||
node = node.Left
|
||||
} else {
|
||||
l := node.Right
|
||||
d := inOrderSuccessor(l)
|
||||
d.Left = node.Left
|
||||
return node.Right
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func inOrderSuccessor[T any](root *datastructure.TreeNode[T]) *datastructure.TreeNode[T] {
|
||||
cur := root
|
||||
for cur.Left != nil {
|
||||
cur = cur.Left
|
||||
}
|
||||
return cur
|
||||
}
|
||||
|
||||
func printTreeNodes[T any](nodes []*datastructure.TreeNode[T], level, maxLevel int) {
|
||||
if len(nodes) == 0 || isAllNil(nodes) {
|
||||
return
|
||||
}
|
||||
|
||||
floor := maxLevel - level
|
||||
endgeLines := int(math.Pow(float64(2), (math.Max(float64(floor)-1, 0))))
|
||||
firstSpaces := int(math.Pow(float64(2), float64(floor))) - 1
|
||||
betweenSpaces := int(math.Pow(float64(2), float64(floor)+1)) - 1
|
||||
|
||||
printSpaces(firstSpaces)
|
||||
|
||||
newNodes := []*datastructure.TreeNode[T]{}
|
||||
for _, node := range nodes {
|
||||
if node != nil {
|
||||
fmt.Printf("%v", node.Data)
|
||||
newNodes = append(newNodes, node.Left)
|
||||
newNodes = append(newNodes, node.Right)
|
||||
} else {
|
||||
newNodes = append(newNodes, nil)
|
||||
newNodes = append(newNodes, nil)
|
||||
printSpaces(1)
|
||||
}
|
||||
|
||||
printSpaces(betweenSpaces)
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
|
||||
for i := 1; i <= endgeLines; i++ {
|
||||
for j := 0; j < len(nodes); j++ {
|
||||
printSpaces(firstSpaces - i)
|
||||
if nodes[j] == nil {
|
||||
printSpaces(endgeLines + endgeLines + i + 1)
|
||||
continue
|
||||
}
|
||||
|
||||
if nodes[j].Left != nil {
|
||||
fmt.Print("/")
|
||||
} else {
|
||||
printSpaces(1)
|
||||
}
|
||||
|
||||
printSpaces(i + i - 1)
|
||||
|
||||
if nodes[j].Right != nil {
|
||||
fmt.Print("\\")
|
||||
} else {
|
||||
printSpaces(1)
|
||||
}
|
||||
printSpaces(endgeLines + endgeLines - 1)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
printTreeNodes(newNodes, level+1, maxLevel)
|
||||
}
|
||||
|
||||
// printSpaces
|
||||
func printSpaces(n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
}
|
||||
|
||||
func isAllNil[T any](nodes []*datastructure.TreeNode[T]) bool {
|
||||
for _, v := range nodes {
|
||||
if v != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func calculateDepth[T any](node *datastructure.TreeNode[T], depth int) int {
|
||||
if node == nil {
|
||||
return depth
|
||||
}
|
||||
return max(calculateDepth(node.Left, depth+1), calculateDepth(node.Right, depth+1))
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package datetime
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestToUnix(t *testing.T) {
|
||||
@@ -19,10 +19,10 @@ func TestToUnix(t *testing.T) {
|
||||
func TestToFormat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToFormat")
|
||||
|
||||
tm, err := NewFormat("2022/03/18 17:04:05")
|
||||
_, err := NewFormat("2022/03/18 17:04:05")
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err = NewFormat("2022-03-18 17:04:05")
|
||||
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToFormat -> ", tm.ToFormat())
|
||||
@@ -31,23 +31,22 @@ func TestToFormat(t *testing.T) {
|
||||
func TestToFormatForTpl(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToFormatForTpl")
|
||||
|
||||
tm, err := NewFormat("2022/03/18 17:04:05")
|
||||
_, err := NewFormat("2022/03/18 17:04:05")
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err = NewFormat("2022-03-18 17:04:05")
|
||||
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToFormatForTpl -> ", tm.ToFormatForTpl("2006/01/02 15:04:05"))
|
||||
|
||||
}
|
||||
|
||||
func TestToIso8601(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToIso8601")
|
||||
|
||||
tm, err := NewISO8601("2022-03-18 17:04:05")
|
||||
_, err := NewISO8601("2022-03-18 17:04:05")
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err = NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("ToIso8601 -> ", tm.ToIso8601())
|
||||
|
||||
@@ -3,35 +3,29 @@
|
||||
|
||||
// Package datetime implements some functions to format date and time.
|
||||
// Note:
|
||||
// 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"
|
||||
// "yyyy-mm-dd"
|
||||
// "yyyy-mm"
|
||||
// "mm-dd"
|
||||
// "dd-mm-yy hh:mm:ss"
|
||||
// "yyyy/mm/dd hh:mm:ss"
|
||||
// "yyyy/mm/dd hh:mm"
|
||||
// "yyyy/mm/dd hh"
|
||||
// "yyyy/mm/dd"
|
||||
// "yyyy/mm"
|
||||
// "mm/dd"
|
||||
// "dd/mm/yy hh:mm:ss"
|
||||
// "yyyymmdd"
|
||||
// "mmddyy"
|
||||
// "yyyy"
|
||||
// "yy"
|
||||
// "mm"
|
||||
// "hh:mm:ss"
|
||||
// "hh:mm"
|
||||
// "mm:ss"
|
||||
|
||||
// 1. `format` param in FormatTimeToStr function should be as flow:
|
||||
//"yyyy-mm-dd hh:mm:ss"
|
||||
//"yyyy-mm-dd hh:mm"
|
||||
//"yyyy-mm-dd hh"
|
||||
//"yyyy-mm-dd"
|
||||
//"yyyy-mm"
|
||||
//"mm-dd"
|
||||
//"dd-mm-yy hh:mm:ss"
|
||||
//"yyyy/mm/dd hh:mm:ss"
|
||||
//"yyyy/mm/dd hh:mm"
|
||||
//"yyyy/mm/dd hh"
|
||||
//"yyyy/mm/dd"
|
||||
//"yyyy/mm"
|
||||
//"mm/dd"
|
||||
//"dd/mm/yy hh:mm:ss"
|
||||
//"yyyy"
|
||||
//"mm"
|
||||
//"hh:mm:ss"
|
||||
//"mm:ss"
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -41,7 +35,7 @@ func init() {
|
||||
timeFormat = map[string]string{
|
||||
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
|
||||
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd hh": "2006-01-02 15",
|
||||
"yyyy-mm-dd hh": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd": "2006-01-02",
|
||||
"yyyy-mm": "2006-01",
|
||||
"mm-dd": "01-02",
|
||||
@@ -53,13 +47,9 @@ 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",
|
||||
}
|
||||
}
|
||||
@@ -79,11 +69,6 @@ func AddDay(t time.Time, day int64) time.Time {
|
||||
return t.Add(24 * time.Hour * time.Duration(day))
|
||||
}
|
||||
|
||||
// AddYear add or sub year to the time.
|
||||
func AddYear(t time.Time, year int64) time.Time {
|
||||
return t.Add(365 * 24 * time.Hour * time.Duration(year))
|
||||
}
|
||||
|
||||
// GetNowDate return format yyyy-mm-dd of current date
|
||||
func GetNowDate() string {
|
||||
return time.Now().Format("2006-01-02")
|
||||
@@ -112,39 +97,18 @@ func GetNightTimestamp() int64 {
|
||||
}
|
||||
|
||||
// FormatTimeToStr convert time to string
|
||||
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)
|
||||
func FormatTimeToStr(t time.Time, format string) string {
|
||||
return t.Format(timeFormat[format])
|
||||
}
|
||||
|
||||
// FormatStrToTime convert string to time
|
||||
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
|
||||
tf, ok := timeFormat[strings.ToLower(format)]
|
||||
func FormatStrToTime(str, format string) (time.Time, error) {
|
||||
v, ok := timeFormat[format]
|
||||
if !ok {
|
||||
return time.Time{}, fmt.Errorf("format %s not support", format)
|
||||
return time.Time{}, fmt.Errorf("format %s not found", format)
|
||||
}
|
||||
|
||||
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)
|
||||
return time.Parse(v, str)
|
||||
}
|
||||
|
||||
// BeginOfMinute return beginning minute time of day
|
||||
@@ -216,108 +180,3 @@ func BeginOfYear(t time.Time) time.Time {
|
||||
func EndOfYear(t time.Time) time.Time {
|
||||
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
|
||||
}
|
||||
|
||||
// IsLeapYear check if param year is leap year or not.
|
||||
func IsLeapYear(year int) bool {
|
||||
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
|
||||
}
|
||||
|
||||
// BetweenSeconds returns the number of seconds between two times.
|
||||
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
|
||||
index := t2.Unix() - t1.Unix()
|
||||
return index
|
||||
}
|
||||
|
||||
// DayOfYear returns which day of the year the parameter date `t` is.
|
||||
func DayOfYear(t time.Time) int {
|
||||
y, m, d := t.Date()
|
||||
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
|
||||
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
|
||||
|
||||
return int(nowDate.Sub(firstDay).Hours() / 24)
|
||||
}
|
||||
|
||||
// IsWeekend checks if passed time is weekend or not.
|
||||
func IsWeekend(t time.Time) bool {
|
||||
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
|
||||
}
|
||||
|
||||
// NowDateOrTime return current datetime with specific format and timezone.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestAddDay(t *testing.T) {
|
||||
@@ -46,19 +46,6 @@ func TestAddMinute(t *testing.T) {
|
||||
assert.Equal(float64(-2), diff2.Minutes())
|
||||
}
|
||||
|
||||
func TestAddYear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAddDay")
|
||||
|
||||
now := time.Now()
|
||||
after2Years := AddYear(now, 1)
|
||||
diff1 := after2Years.Sub(now)
|
||||
assert.Equal(float64(8760), diff1.Hours())
|
||||
|
||||
before2Years := AddYear(now, -1)
|
||||
diff2 := before2Years.Sub(now)
|
||||
assert.Equal(float64(-8760), diff2.Hours())
|
||||
}
|
||||
|
||||
func TestGetNowDate(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetNowDate")
|
||||
expected := time.Now().Format("2006-01-02")
|
||||
@@ -244,92 +231,3 @@ func TestEndOfYear(t *testing.T) {
|
||||
|
||||
assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func TestIsLeapYear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEndOfYear")
|
||||
|
||||
result1 := IsLeapYear(2000)
|
||||
result2 := IsLeapYear(2001)
|
||||
|
||||
assert.Equal(true, result1)
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
func TestBetweenSeconds(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||
|
||||
today := time.Now()
|
||||
tomorrow := AddDay(today, 1)
|
||||
yesterday := AddDay(today, -1)
|
||||
|
||||
result1 := BetweenSeconds(today, tomorrow)
|
||||
result2 := BetweenSeconds(today, yesterday)
|
||||
|
||||
assert.Equal(int64(86400), result1)
|
||||
assert.Equal(int64(-86400), result2)
|
||||
}
|
||||
|
||||
func TestDayOfYear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDayOfYear")
|
||||
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||
result1 := DayOfYear(date1)
|
||||
assert.Equal(31, result1)
|
||||
|
||||
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||
result2 := DayOfYear(date2)
|
||||
assert.Equal(1, result2)
|
||||
|
||||
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||
result3 := DayOfYear(date3)
|
||||
assert.Equal(0, result3)
|
||||
}
|
||||
|
||||
func TestIsWeekend(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsWeekend")
|
||||
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||
result := IsWeekend(date)
|
||||
assert.Equal(true, result)
|
||||
|
||||
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||
result1 := IsWeekend(date1)
|
||||
assert.Equal(true, result1)
|
||||
|
||||
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||
result2 := IsWeekend(date2)
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
598
docs/algorithm.md
Normal file
598
docs/algorithm.md
Normal file
@@ -0,0 +1,598 @@
|
||||
# Algorithm
|
||||
Package algorithm implements some basic algorithm. eg. sort, search.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Algorithm](#algorithm)
|
||||
- [Source](#source)
|
||||
- [Usage](#usage)
|
||||
- [Index](#index)
|
||||
- [Documentation](#documentation)
|
||||
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
|
||||
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
|
||||
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
|
||||
- [<span id="ShellSort">ShellSort</span>](#shellsort)
|
||||
- [<span id="QuickSort">QuickSort</span>](#quicksort)
|
||||
- [<span id="HeapSort">HeapSort</span>](#heapsort)
|
||||
- [<span id="MergeSort">MergeSort</span>](#mergesort)
|
||||
- [<span id="CountSort">CountSort</span>](#countsort)
|
||||
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
|
||||
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
|
||||
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
|
||||
- [<span id="LRUCache">LRUCache</span>](#lrucache)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.BubbleSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
//decending order
|
||||
// if p1.Age > p2.Age {
|
||||
// return -1
|
||||
// } else if p1.Age < p2.Age {
|
||||
// return 1
|
||||
// }
|
||||
}
|
||||
|
||||
var peoples = []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
algorithm.InsertionSort(peoples, comparator)
|
||||
|
||||
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.SelectionSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.ShellSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.HeapSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.MergeSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
sortedSlice := algorithm.CountSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinearSearch">LinearSearch</span>
|
||||
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
|
||||
fmt.Println(foundIndex) //2
|
||||
|
||||
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LRUCache">LRUCache</span>
|
||||
<p>LRUCache implements mem cache with lru.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cache := algorithm.NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
|
||||
}
|
||||
```
|
||||
598
docs/algorithm_zh-CN.md
Normal file
598
docs/algorithm_zh-CN.md
Normal file
@@ -0,0 +1,598 @@
|
||||
# Algorithm
|
||||
algorithm算法包实现一些基本算法,sort,search,lrucache。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Algorithm](#algorithm)
|
||||
- [源码](#源码)
|
||||
- [用法](#用法)
|
||||
- [目录](#目录)
|
||||
- [文档](#文档)
|
||||
- [<span id="BubbleSort">BubbleSort</span>](#bubblesort)
|
||||
- [<span id="InsertionSort">InsertionSort</span>](#insertionsort)
|
||||
- [<span id="SelectionSort">SelectionSort</span>](#selectionsort)
|
||||
- [<span id="ShellSort">ShellSort</span>](#shellsort)
|
||||
- [<span id="QuickSort">QuickSort</span>](#quicksort)
|
||||
- [<span id="HeapSort">HeapSort</span>](#heapsort)
|
||||
- [<span id="MergeSort">MergeSort</span>](#mergesort)
|
||||
- [<span id="CountSort">CountSort</span>](#countsort)
|
||||
- [<span id="BinarySearch">BinarySearch</span>](#binarysearch)
|
||||
- [<span id="BinaryIterativeSearch">BinaryIterativeSearch</span>](#binaryiterativesearch)
|
||||
- [<span id="LinearSearch">LinearSearch</span>](#linearsearch)
|
||||
- [<span id="LRUCache">LRUCache</span>](#lrucache)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.BubbleSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
//decending order
|
||||
// if p1.Age > p2.Age {
|
||||
// return -1
|
||||
// } else if p1.Age < p2.Age {
|
||||
// return 1
|
||||
// }
|
||||
}
|
||||
|
||||
var peoples = []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
comparator := &peopleAgeComparator{}
|
||||
algorithm.InsertionSort(peoples, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.SelectionSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.ShellSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.HeapSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.MergeSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
sortedSlice := algorithm.CountSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinearSearch">LinearSearch</span>
|
||||
<p>线性查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
|
||||
fmt.Println(foundIndex) //2
|
||||
|
||||
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LRUCache">LRUCache</span>
|
||||
<p>lru实现缓存</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cache := algorithm.NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
|
||||
}
|
||||
```
|
||||
326
docs/compare.md
326
docs/compare.md
@@ -1,326 +0,0 @@
|
||||
# Compare
|
||||
|
||||
Package compare provides a lightweight comparison function on any type.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/condition"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [Equal](#Equal)
|
||||
- [EqualValue](#EqualValue)
|
||||
- [LessThan](#LessThan)
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
|
||||
<p>Checks if two values are equal or not. (check both type and value)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Equal(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.Equal(1, 1)
|
||||
result2 := compare.Equal("1", "1")
|
||||
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := compare.Equal(1, "1")
|
||||
result6 := compare.Equal(1, int64(1))
|
||||
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualValue">EqualValue</span>
|
||||
|
||||
<p>Checks if two values are equal or not. (check value only)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func EqualValue(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.EqualValue(1, 1)
|
||||
result2 := compare.EqualValue(int(1), int64(1))
|
||||
result3 := compare.EqualValue(1, "1")
|
||||
result4 := compare.EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessThan">LessThan</span>
|
||||
|
||||
<p>Checks if value `left` less than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LessThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessThan(1, 2)
|
||||
result2 := compare.LessThan(1.1, 2.2)
|
||||
result3 := compare.LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessThan(time1, time2)
|
||||
|
||||
result5 := compare.LessThan(2, 1)
|
||||
result6 := compare.LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterThan">GreaterThan</span>
|
||||
|
||||
<p>Checks if value `left` greater than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterThan(2, 1)
|
||||
result2 := compare.GreaterThan(2.2, 1.1)
|
||||
result3 := compare.GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterThan(time2, time1)
|
||||
|
||||
result5 := compare.GreaterThan(1, 2)
|
||||
result6 := compare.GreaterThan(int64(2), 1)
|
||||
result7 := compare.GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessOrEqual">LessOrEqual</span>
|
||||
|
||||
<p>Checks if value `left` less than or equal than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessOrEqual(1, 1)
|
||||
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||
result3 := compare.LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessOrEqual(time1, time2)
|
||||
|
||||
result5 := compare.LessOrEqual(2, 1)
|
||||
result6 := compare.LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||
|
||||
<p>Checks if value `left` less greater or equal than value `right`.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterOrEqual(1, 1)
|
||||
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||
result3 := compare.GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := compare.GreaterOrEqual(1, 2)
|
||||
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||
result7 := compare.GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
@@ -1,326 +0,0 @@
|
||||
# Compare
|
||||
|
||||
compare包提供几个轻量级的类型比较函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/v1/compare/compare.go](https://github.com/duke-git/lancet/blob/v1/compare/compare.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go](https://github.com/duke-git/lancet/blob/v1/compare/compare_internal.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/condition"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Equal](#Equal)
|
||||
- [EqualValue](#EqualValue)
|
||||
- [LessThan](#LessThan)
|
||||
- [GreaterThan](#GreaterThan)
|
||||
- [LessOrEqual](#LessOrEqual)
|
||||
- [GreaterOrEqual](#GreaterOrEqual)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Equal">Equal</span>
|
||||
|
||||
<p>检查两个值是否相等(检查类型和值)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Equal(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.Equal(1, 1)
|
||||
result2 := compare.Equal("1", "1")
|
||||
result3 := compare.Equal([]int{1, 2, 3}, []int{1, 2, 3})
|
||||
result4 := compare.Equal(map[int]string{1: "a", 2: "b"}, map[int]string{1: "a", 2: "b"})
|
||||
|
||||
result5 := compare.Equal(1, "1")
|
||||
result6 := compare.Equal(1, int64(1))
|
||||
result7 := compare.Equal([]int{1, 2}, []int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EqualValue">EqualValue</span>
|
||||
|
||||
<p>检查两个值是否相等(只检查值)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func EqualValue(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.EqualValue(1, 1)
|
||||
result2 := compare.EqualValue(int(1), int64(1))
|
||||
result3 := compare.EqualValue(1, "1")
|
||||
result4 := compare.EqualValue(1, "2")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessThan">LessThan</span>
|
||||
|
||||
<p>验证参数`left`的值是否小于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LessThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessThan(1, 2)
|
||||
result2 := compare.LessThan(1.1, 2.2)
|
||||
result3 := compare.LessThan("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessThan(time1, time2)
|
||||
|
||||
result5 := compare.LessThan(2, 1)
|
||||
result6 := compare.LessThan(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterThan">GreaterThan</span>
|
||||
|
||||
<p>验证参数`left`的值是否大于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GreaterThan(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterThan(2, 1)
|
||||
result2 := compare.GreaterThan(2.2, 1.1)
|
||||
result3 := compare.GreaterThan("b", "a")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterThan(time2, time1)
|
||||
|
||||
result5 := compare.GreaterThan(1, 2)
|
||||
result6 := compare.GreaterThan(int64(2), 1)
|
||||
result7 := compare.GreaterThan("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LessOrEqual">LessOrEqual</span>
|
||||
|
||||
<p>验证参数`left`的值是否小于或等于参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LessOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.LessOrEqual(1, 1)
|
||||
result2 := compare.LessOrEqual(1.1, 2.2)
|
||||
result3 := compare.LessOrEqual("a", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.LessOrEqual(time1, time2)
|
||||
|
||||
result5 := compare.LessOrEqual(2, 1)
|
||||
result6 := compare.LessOrEqual(1, int64(2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GreaterOrEqual">GreaterOrEqual</span>
|
||||
|
||||
<p>验证参数`left`的值是否大于或参数`right`的值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GreaterOrEqual(left, right any) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/compare"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := compare.GreaterOrEqual(1, 1)
|
||||
result2 := compare.GreaterOrEqual(2.2, 1.1)
|
||||
result3 := compare.GreaterOrEqual("b", "b")
|
||||
|
||||
time1 := time.Now()
|
||||
time2 := time1.Add(time.Second)
|
||||
result4 := compare.GreaterOrEqual(time2, time1)
|
||||
|
||||
result5 := compare.GreaterOrEqual(1, 2)
|
||||
result6 := compare.GreaterOrEqual(int64(2), 1)
|
||||
result7 := compare.GreaterOrEqual("b", "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
@@ -1,53 +1,41 @@
|
||||
# Convertor
|
||||
|
||||
Package convertor contains some functions for data type convertion.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [ColorHexToRGB](#ColorHexToRGB)
|
||||
- [ColorRGBToHex](#ColorRGBToHex)
|
||||
- [ToBool](#ToBool)
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToChannel](#ToChannel)
|
||||
- [ToFloat](#ToFloat)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
- [ToString](#ToString)
|
||||
- [StructToMap](#StructToMap)
|
||||
- [EncodeByte](#EncodeByte)
|
||||
- [DecodeByte](#DecodeByte)
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
- [Utf8ToGbk](#Utf8ToGbk)
|
||||
- [GbkToUtf8](#GbkToUtf8)
|
||||
|
||||
- [ColorHexToRGB](#ColorHexToRGB)
|
||||
- [ColorRGBToHex](#ColorRGBToHex)
|
||||
- [ToBool](#ToBool)
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
- [ToString](#ToString)
|
||||
- [StructToMap](#StructToMap)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
<p>Convert color hex to color rgb.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -55,7 +43,6 @@ import (
|
||||
```go
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -63,16 +50,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := ColorHexToRGB(colorHex)
|
||||
r, g, b := convertor.ColorHexToRGB(colorHex)
|
||||
fmt.Println(r, g, b) //0,51,102
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||
|
||||
<p>Convert color rgb to color hex.</p>
|
||||
@@ -82,7 +71,6 @@ func main() {
|
||||
```go
|
||||
func ColorRGBToHex(red, green, blue int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -90,19 +78,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
colorHex := convertor.ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex) //#003366
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
||||
@@ -112,7 +102,6 @@ func main() {
|
||||
```go
|
||||
func ToBool(s string) (bool, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -120,7 +109,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -138,6 +127,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>Convert interface to byte slice.</p>
|
||||
@@ -145,9 +136,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToBytes(data interface{}) ([]byte, error)
|
||||
func ToBytes(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -155,7 +145,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -167,6 +157,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToChar">ToChar</span>
|
||||
|
||||
<p>Convert string to char slice.</p>
|
||||
@@ -176,7 +168,6 @@ func main() {
|
||||
```go
|
||||
func ToChar(s string) []string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -184,7 +175,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -199,42 +190,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>Convert a collection of elements to a read-only channels.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToChannel(array []interface{}) <-chan interface{}
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||
|
||||
val1, _ := <-ch
|
||||
fmt.Println(val1) //1
|
||||
|
||||
val2, _ := <-ch
|
||||
fmt.Println(val2) //2
|
||||
|
||||
val3, _ := <-ch
|
||||
fmt.Println(val3) //3
|
||||
|
||||
_, ok := <-ch
|
||||
fmt.Println(ok) //false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
@@ -243,9 +199,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToFloat(value interface{}) (float64, error)
|
||||
func ToFloat(value any) (float64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -253,7 +208,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -268,6 +223,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
@@ -275,9 +232,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToInt(value interface{}) (int64, error)
|
||||
func ToInt(value any) (int64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -285,7 +241,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -300,6 +256,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToJson">ToJson</span>
|
||||
|
||||
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
|
||||
@@ -307,9 +265,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToJson(value interface{}) (string, error)
|
||||
func ToJson(value any) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -317,7 +274,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -327,6 +284,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>Convert interface to string. </p>
|
||||
@@ -334,9 +293,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToString(value interface{}) string
|
||||
func ToString(value any) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -344,7 +302,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -354,6 +312,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="StructToMap">StructToMap</span>
|
||||
|
||||
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
|
||||
@@ -361,9 +321,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func StructToMap(value interface{}) (map[string]interface{}, error)
|
||||
func StructToMap(value any) (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -371,7 +330,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -387,303 +346,4 @@ func main() {
|
||||
|
||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EncodeByte">EncodeByte</span>
|
||||
|
||||
<p>Encode data to byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func EncodeByte(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
byteData, _ := convertor.EncodeByte("abc")
|
||||
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>Decode byte data to target object. target should be a pointer instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DecodeByte(data []byte, target any) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var result string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
convertor.DecodeByte(byteData, &result)
|
||||
fmt.Println(result) //"abc"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DeepClone">DeepClone</span>
|
||||
|
||||
<p>Creates a deep copy of passed item, can't clone unexported field of struct.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DeepClone[T any](src T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Struct struct {
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
unexported string
|
||||
}
|
||||
|
||||
cases := []interface{}{
|
||||
true,
|
||||
1,
|
||||
0.1,
|
||||
map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
&Struct{
|
||||
Str: "test",
|
||||
Int: 1,
|
||||
Float: 0.1,
|
||||
Bool: true,
|
||||
Nil: nil,
|
||||
// unexported: "can't be cloned",
|
||||
},
|
||||
}
|
||||
|
||||
for _, item := range cases {
|
||||
cloned := convertor.DeepClone(item)
|
||||
|
||||
isPointerEqual := &cloned == &item
|
||||
fmt.Println(cloned, isPointerEqual)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true false
|
||||
// 1 false
|
||||
// 0.1 false
|
||||
// map[a:1 b:2] false
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func CopyProperties(dst, src interface{}) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToInterface">ToInterface</span>
|
||||
|
||||
<p>Converts reflect value to its interface type.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||
|
||||
<p>Converts utf8 encoding data to GBK encoding data.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(validator.IsGBK(gbkData))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||
|
||||
<p>Converts GBK encoding data to utf8 encoding data.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(string(utf8Data))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
```
|
||||
@@ -1,12 +1,11 @@
|
||||
# Convertor
|
||||
|
||||
convertor 转换器包支持一些常见的数据类型转换
|
||||
convertor转换器包支持一些常见的数据类型转换
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go](https://github.com/duke-git/lancet/blob/v1/convertor/convertor.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/convertor/convertor.go](https://github.com/duke-git/lancet/blob/main/convertor/convertor.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -14,7 +13,7 @@ convertor 转换器包支持一些常见的数据类型转换
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
```
|
||||
|
||||
@@ -22,31 +21,23 @@ import (
|
||||
|
||||
## 目录
|
||||
|
||||
- [ColorHexToRGB](#ColorHexToRGB)
|
||||
- [ColorRGBToHex](#ColorRGBToHex)
|
||||
- [ToBool](#ToBool)
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToChannel](#ToChannel)
|
||||
- [ToFloat](#ToFloat)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
- [ToString](#ToString)
|
||||
- [StructToMap](#StructToMap)
|
||||
- [EncodeByte](#EncodeByte)
|
||||
- [DecodeByte](#DecodeByte)
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
- [Utf8ToGbk](#Utf8ToGbk)
|
||||
- [GbkToUtf8](#GbkToUtf8)
|
||||
- [ColorHexToRGB](#ColorHexToRGB)
|
||||
- [ColorRGBToHex](#ColorRGBToHex)
|
||||
- [ToBool](#ToBool)
|
||||
- [ToBytes](#ToBytes)
|
||||
- [ToChar](#ToChar)
|
||||
- [ToInt](#ToInt)
|
||||
- [ToJson](#ToJson)
|
||||
- [ToString](#ToString)
|
||||
- [StructToMap](#StructToMap)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
<p>颜色值十六进制转rgb</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -54,7 +45,6 @@ import (
|
||||
```go
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -62,16 +52,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := ColorHexToRGB(colorHex)
|
||||
r, g, b := convertor.ColorHexToRGB(colorHex)
|
||||
fmt.Println(r, g, b) //0,51,102
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||
|
||||
<p>颜色值rgb转十六进制</p>
|
||||
@@ -81,7 +73,6 @@ func main() {
|
||||
```go
|
||||
func ColorRGBToHex(red, green, blue int) string
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -89,19 +80,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
colorHex := convertor.ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex) //#003366
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>字符串转布尔类型,使用strconv.ParseBool</p>
|
||||
@@ -111,7 +104,6 @@ func main() {
|
||||
```go
|
||||
func ToBool(s string) (bool, error)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -119,7 +111,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -137,6 +129,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>interface转字节切片.</p>
|
||||
@@ -144,9 +138,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToBytes(data interface{}) ([]byte, error)
|
||||
func ToBytes(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -154,7 +147,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -166,6 +159,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToChar">ToChar</span>
|
||||
|
||||
<p>字符串转字符切片</p>
|
||||
@@ -175,7 +170,6 @@ func main() {
|
||||
```go
|
||||
func ToChar(s string) []string
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -183,7 +177,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -198,42 +192,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>将切片转为只读channel</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToChannel(array []interface{}) <-chan interface{}
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||
|
||||
val1, _ := <-ch
|
||||
fmt.Println(val1) //1
|
||||
|
||||
val2, _ := <-ch
|
||||
fmt.Println(val2) //2
|
||||
|
||||
val3, _ := <-ch
|
||||
fmt.Println(val3) //3
|
||||
|
||||
_, ok := <-ch
|
||||
fmt.Println(ok) //false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
@@ -242,9 +201,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToFloat(value interface{}) (float64, error)
|
||||
func ToFloat(value any) (float64, error)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -252,7 +210,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -267,6 +225,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>将interface转成intt64类型,如果参数无法转换,会返回0和error</p>
|
||||
@@ -274,9 +234,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToInt(value interface{}) (int64, error)
|
||||
func ToInt(value any) (int64, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -284,7 +243,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -299,6 +258,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToJson">ToJson</span>
|
||||
|
||||
<p>将interface转成json字符串,如果参数无法转换,会返回""和error</p>
|
||||
@@ -306,9 +267,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToJson(value interface{}) (string, error)
|
||||
func ToJson(value any) (string, error)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -316,7 +276,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -326,6 +286,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>将interface转成字符串</p>
|
||||
@@ -333,9 +295,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToString(value interface{}) string
|
||||
func ToString(value any) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -343,7 +304,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -353,6 +314,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="StructToMap">StructToMap</span>
|
||||
|
||||
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
|
||||
@@ -360,9 +323,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StructToMap(value interface{}) (map[string]interface{}, error)
|
||||
func StructToMap(value any) (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>列子:</b>
|
||||
|
||||
```go
|
||||
@@ -370,7 +332,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -386,304 +348,4 @@ func main() {
|
||||
|
||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EncodeByte">EncodeByte</span>
|
||||
|
||||
<p>将data编码成字节切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func EncodeByte(data any) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
byteData, _ := convertor.EncodeByte("abc")
|
||||
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DecodeByte(data []byte, target any) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var result string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
convertor.DecodeByte(byteData, &result)
|
||||
fmt.Println(result) //"abc"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DeepClone">DeepClone</span>
|
||||
|
||||
<p>创建一个传入值的深拷贝, 无法克隆结构体的非导出字段。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DeepClone[T any](src T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Struct struct {
|
||||
Str string
|
||||
Int int
|
||||
Float float64
|
||||
Bool bool
|
||||
Nil interface{}
|
||||
unexported string
|
||||
}
|
||||
|
||||
cases := []interface{}{
|
||||
true,
|
||||
1,
|
||||
0.1,
|
||||
map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
&Struct{
|
||||
Str: "test",
|
||||
Int: 1,
|
||||
Float: 0.1,
|
||||
Bool: true,
|
||||
Nil: nil,
|
||||
// unexported: "can't be cloned",
|
||||
},
|
||||
}
|
||||
|
||||
for _, item := range cases {
|
||||
cloned := convertor.DeepClone(item)
|
||||
|
||||
isPointerEqual := &cloned == &item
|
||||
fmt.Println(cloned, isPointerEqual)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true false
|
||||
// 1 false
|
||||
// 0.1 false
|
||||
// map[a:1 b:2] false
|
||||
// &{test 1 0.1 true <nil> } false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="CopyProperties">CopyProperties</span>
|
||||
|
||||
<p>拷贝不同结构体之间的同名字段。使用json.Marshal序列化,需要设置dst和src struct字段的json tag。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CopyProperties(dst, src interface{}) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Disk struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type DiskVO struct {
|
||||
Name string `json:"name"`
|
||||
Total string `json:"total"`
|
||||
Used string `json:"used"`
|
||||
Percent float64 `json:"percent"`
|
||||
}
|
||||
|
||||
type Indicator struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk []Disk `json:"disk"`
|
||||
Stop chan bool `json:"-"`
|
||||
}
|
||||
|
||||
type IndicatorVO struct {
|
||||
Id string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
UpTime string `json:"upTime"`
|
||||
LoadAvg string `json:"loadAvg"`
|
||||
Cpu int64 `json:"cpu"`
|
||||
Disk []DiskVO `json:"disk"`
|
||||
}
|
||||
|
||||
indicator := &Indicator{Id: "001", Ip: "127.0.0.1", Cpu: 1, Disk: []Disk{
|
||||
{Name: "disk-001", Total: "100", Used: "1", Percent: 10},
|
||||
{Name: "disk-002", Total: "200", Used: "1", Percent: 20},
|
||||
{Name: "disk-003", Total: "300", Used: "1", Percent: 30},
|
||||
}}
|
||||
|
||||
indicatorVO := IndicatorVO{}
|
||||
|
||||
err := convertor.CopyProperties(&indicatorVO, indicator)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(indicatorVO.Id)
|
||||
fmt.Println(indicatorVO.Ip)
|
||||
fmt.Println(len(indicatorVO.Disk))
|
||||
|
||||
// Output:
|
||||
// 001
|
||||
// 127.0.0.1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToInterface">ToInterface</span>
|
||||
|
||||
<p>将反射值转换成对应的interface类型。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||
|
||||
<p>utf8编码转GBK编码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(validator.IsGBK(gbkData))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||
|
||||
<p>GBK编码转utf8编码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(string(utf8Data))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
```
|
||||
714
docs/cryptor.md
714
docs/cryptor.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
711
docs/datetime.md
711
docs/datetime.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
838
docs/fileutil.md
838
docs/fileutil.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,41 @@
|
||||
# Formatter
|
||||
|
||||
formatter contains some functions for data formatting.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [Comma](#Comma)
|
||||
- [Pretty](#Pretty)
|
||||
- [PrettyToWriter](#PrettyToWriter)
|
||||
- [DecimalBytes](#DecimalBytes)
|
||||
- [BinaryBytes](#BinaryBytes)
|
||||
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||
- [Comma](#Comma)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
|
||||
Param should be number or numberic string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Comma(value interface{}, symbol string) string
|
||||
func Comma(v any, symbol string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -52,7 +43,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -60,241 +51,3 @@ func main() {
|
||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pretty">Pretty</span>
|
||||
|
||||
<p>Pretty data to JSON string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Pretty(v interface{}) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [
|
||||
// "a",
|
||||
// "b",
|
||||
// "c"
|
||||
// ]
|
||||
// {
|
||||
// "a": 1
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||
|
||||
<p>Pretty encode data to writer.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func PrettyToWriter(v interface{}, out io.Writer) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := formatter.PrettyToWriter(user, buf)
|
||||
|
||||
fmt.Println(buf)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// "name": "King",
|
||||
// "age": 10000
|
||||
// }
|
||||
//
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecimalBytes">DecimalBytes</span>
|
||||
|
||||
<p>Returns a human readable byte size under decimal standard (base 1000). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DecimalBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.DecimalBytes(1000)
|
||||
result2 := formatter.DecimalBytes(1024)
|
||||
result3 := formatter.DecimalBytes(1234567)
|
||||
result4 := formatter.DecimalBytes(1234567, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KB
|
||||
// 1.024KB
|
||||
// 1.2346MB
|
||||
// 1.235MB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BinaryBytes">BinaryBytes</span>
|
||||
|
||||
<p>Returns a human readable byte size under binary standard (base 1024). The precision parameter specifies the number of digits after the decimal point, which is 4 for default.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BinaryBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.BinaryBytes(1024)
|
||||
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||
result3 := formatter.BinaryBytes(1234567)
|
||||
result4 := formatter.BinaryBytes(1234567, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KiB
|
||||
// 1MiB
|
||||
// 1.1774MiB
|
||||
// 1.18MiB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||
|
||||
<p>Returns the human readable bytes size string into the amount it represents(base 1000).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ParseDecimalBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseDecimalBytes("12")
|
||||
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12000
|
||||
// 12000
|
||||
// 12200
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||
|
||||
<p>Returns the human readable bytes size string into the amount it represents(base 1024).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ParseBinaryBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseBinaryBytes("12")
|
||||
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12288
|
||||
// 12288
|
||||
// 12492
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,49 +1,40 @@
|
||||
# Formatter
|
||||
|
||||
formatter 格式化器包含一些数据格式化处理方法。
|
||||
formatter格式化器包含一些数据格式化处理方法。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go](https://github.com/duke-git/lancet/blob/v1/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Comma](#Comma)
|
||||
- [Pretty](#Pretty)
|
||||
- [PrettyToWriter](#PrettyToWriter)
|
||||
- [DecimalBytes](#DecimalBytes)
|
||||
- [BinaryBytes](#BinaryBytes)
|
||||
- [ParseDecimalBytes](#ParseDecimalBytes)
|
||||
- [ParseBinaryBytes](#ParseBinaryBytes)
|
||||
- [Comma](#Comma)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Comma(v interface{}, symbol string) string
|
||||
func Comma(v any, symbol string) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -51,7 +42,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -59,241 +50,3 @@ func main() {
|
||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pretty">Pretty</span>
|
||||
|
||||
<p>返回pretty JSON字符串.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Pretty(v interface{}) (string, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.Pretty([]string{"a", "b", "c"})
|
||||
result2, _ := formatter.Pretty(map[string]int{"a": 1})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [
|
||||
// "a",
|
||||
// "b",
|
||||
// "c"
|
||||
// ]
|
||||
// {
|
||||
// "a": 1
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PrettyToWriter">PrettyToWriter</span>
|
||||
|
||||
<p>Pretty encode数据到writer。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func PrettyToWriter(v interface{}, out io.Writer) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := formatter.PrettyToWriter(user, buf)
|
||||
|
||||
fmt.Println(buf)
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// "name": "King",
|
||||
// "age": 10000
|
||||
// }
|
||||
//
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DecimalBytes">DecimalBytes</span>
|
||||
|
||||
<p>返回十进制标准(以1000为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DecimalBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.DecimalBytes(1000)
|
||||
result2 := formatter.DecimalBytes(1024)
|
||||
result3 := formatter.DecimalBytes(1234567)
|
||||
result4 := formatter.DecimalBytes(1234567, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KB
|
||||
// 1.024KB
|
||||
// 1.2346MB
|
||||
// 1.235MB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BinaryBytes">BinaryBytes</span>
|
||||
|
||||
<p>返回binary标准(以1024为基数)下的可读字节单位字符串。precision参数指定小数点后的位数,默认为4。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryBytes(size float64, precision ...int) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := formatter.BinaryBytes(1024)
|
||||
result2 := formatter.BinaryBytes(1024 * 1024)
|
||||
result3 := formatter.BinaryBytes(1234567)
|
||||
result4 := formatter.BinaryBytes(1234567, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 1KiB
|
||||
// 1MiB
|
||||
// 1.1774MiB
|
||||
// 1.18MiB
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseDecimalBytes">ParseDecimalBytes</span>
|
||||
|
||||
<p>将字节单位字符串转换成其所表示的字节数(以1000为基数)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ParseDecimalBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseDecimalBytes("12")
|
||||
result2, _ := formatter.ParseDecimalBytes("12k")
|
||||
result3, _ := formatter.ParseDecimalBytes("12 Kb")
|
||||
result4, _ := formatter.ParseDecimalBytes("12.2 kb")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12000
|
||||
// 12000
|
||||
// 12200
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ParseBinaryBytes">ParseBinaryBytes</span>
|
||||
|
||||
<p>将字节单位字符串转换成其所表示的字节数(以1024为基数)。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ParseBinaryBytes(size string) (uint64, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/formatter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1, _ := formatter.ParseBinaryBytes("12")
|
||||
result2, _ := formatter.ParseBinaryBytes("12ki")
|
||||
result3, _ := formatter.ParseBinaryBytes("12 KiB")
|
||||
result4, _ := formatter.ParseBinaryBytes("12.2 kib")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 12288
|
||||
// 12288
|
||||
// 12492
|
||||
}
|
||||
```
|
||||
|
||||
296
docs/function.md
296
docs/function.md
@@ -1,52 +1,47 @@
|
||||
# Function
|
||||
|
||||
Package function can control the flow of function execution and support part of functional programming.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
|
||||
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Schedule](#Schedule)
|
||||
- [Watcher](#Watcher)
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>Creates a function that invokes given func once it's called n or more times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -54,35 +49,37 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
|
||||
type cb func(args ...interface{}) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
type cb func(args ...any) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
|
||||
//output:
|
||||
// arr is [a b]
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// last print
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
|
||||
<p>creates a function that invokes func once it's called less than n times.</p>
|
||||
@@ -90,9 +87,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -100,34 +96,36 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
assert := internal.NewAssert(t, "TestBefore")
|
||||
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
|
||||
var res []int64
|
||||
type cb func(args ...interface{}) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
var res []int64
|
||||
type cb func(args ...any) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
|
||||
expected := []int64{0, 1, 2, 2, 2}
|
||||
assert.Equal(expected, res)
|
||||
expected := []int64{0, 1, 2, 2, 2}
|
||||
assert.Equal(expected, res)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
|
||||
<p>Make a curry function.</p>
|
||||
@@ -135,10 +133,9 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...interface{}) interface{}
|
||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -146,22 +143,24 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>Compose the function list from right to left, then return the composed function.</p>
|
||||
@@ -169,9 +168,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -179,24 +177,26 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...interface{}) interface{} {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...interface{}) interface{} {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := add3(1)
|
||||
|
||||
fmt.Println(result) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
|
||||
@@ -206,7 +206,6 @@ func main() {
|
||||
```go
|
||||
func Debounced(fn func(), duration time.Duration) func()
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -214,30 +213,32 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delay">Delay</span>
|
||||
|
||||
<p>Invoke function after delayed time.</p>
|
||||
@@ -245,9 +246,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
||||
func Delay(delay time.Duration, fn any, args ...any)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -255,17 +255,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Schedule">Schedule</span>
|
||||
|
||||
<p>Invoke function every duration time, until close the returned bool chan.</p>
|
||||
@@ -273,9 +275,8 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -283,65 +284,24 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var res []string
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(res) //[* * * * *]
|
||||
fmt.Println(res) //[* * * * *]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pipeline">Pipeline</span>
|
||||
|
||||
<p>Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
the functions one by one.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addOne := func(x interface{}) interface{} {
|
||||
return x.(int) + 1
|
||||
}
|
||||
double := func(x interface{}) interface{} {
|
||||
return 2 * x.(int)
|
||||
}
|
||||
square := func(x interface{}) interface{} {
|
||||
return x.(int) * x.(int)
|
||||
}
|
||||
|
||||
f := function.Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
@@ -351,16 +311,15 @@ func main() {
|
||||
|
||||
```go
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -368,35 +327,38 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w.Start()
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
longRunningTask()
|
||||
|
||||
fmt.Println(w.excuting) //true
|
||||
fmt.Println(w.excuting) //true
|
||||
|
||||
w.Stop()
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,52 +1,47 @@
|
||||
# Function
|
||||
|
||||
function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
function函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/function/function.go](https://github.com/duke-git/lancet/blob/v1/function/function.go)
|
||||
[https://github.com/duke-git/lancet/blob/v1/function/watcher.go](https://github.com/duke-git/lancet/blob/v1/function/watcher.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Schedule](#Schedule)
|
||||
- [Watcher](#Watcher)
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -54,35 +49,37 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
|
||||
type cb func(args ...interface{}) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
type cb func(args ...any) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
|
||||
//output:
|
||||
// arr is [a b]
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// last print
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
|
||||
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
|
||||
@@ -90,9 +87,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -100,34 +96,36 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
assert := internal.NewAssert(t, "TestBefore")
|
||||
assert := internal.NewAssert(t, "TestBefore")
|
||||
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
|
||||
var res []int64
|
||||
type cb func(args ...interface{}) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
var res []int64
|
||||
type cb func(args ...any) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
|
||||
expected := []int64{0, 1, 2, 2, 2}
|
||||
assert.Equal(expected, res)
|
||||
expected := []int64{0, 1, 2, 2, 2}
|
||||
assert.Equal(expected, res)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
|
||||
<p>创建一个柯里化的函数</p>
|
||||
@@ -135,10 +133,9 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...interface{}) interface{}
|
||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{}
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -146,22 +143,24 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...interface{}) interface{} {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
||||
@@ -169,9 +168,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{}
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -179,24 +177,26 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...interface{}) interface{} {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...interface{}) interface{} {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||
@@ -206,7 +206,6 @@ func main() {
|
||||
```go
|
||||
func Debounced(fn func(), duration time.Duration) func()
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -214,30 +213,32 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delay">Delay</span>
|
||||
|
||||
<p>延迟delay时间后调用函数</p>
|
||||
@@ -245,9 +246,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Delay(delay time.Duration, fn interface{}, args ...interface{})
|
||||
func Delay(delay time.Duration, fn any, args ...any)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -255,17 +255,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Schedule">Schedule</span>
|
||||
|
||||
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
|
||||
@@ -273,9 +275,8 @@ func main() {
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -283,64 +284,24 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var res []string
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(res) //[* * * * *]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Pipeline">Pipeline</span>
|
||||
|
||||
<p>管道执行多个函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{}
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addOne := func(x interface{}) interface{} {
|
||||
return x.(int) + 1
|
||||
}
|
||||
double := func(x interface{}) interface{} {
|
||||
return 2 * x.(int)
|
||||
}
|
||||
square := func(x interface{}) interface{} {
|
||||
return x.(int) * x.(int)
|
||||
}
|
||||
|
||||
f := function.Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
@@ -350,16 +311,15 @@ func main() {
|
||||
|
||||
```go
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -367,35 +327,38 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/function"
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w.Start()
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
longRunningTask()
|
||||
|
||||
fmt.Println(w.excuting) //true
|
||||
fmt.Println(w.excuting) //true
|
||||
|
||||
w.Stop()
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
304
docs/maputil.md
Normal file
304
docs/maputil.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# Maputil
|
||||
Package maputil includes some functions to manipulate map.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Example:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
<p>Executes iteratee funcation for every key and value pair in map.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
fmt.Println(sum) // 10
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
<p>Iterates over map, return a new map contains all key and value pairs pass the predicate function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
res := maputil.Filter(m, isEven)
|
||||
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersect">Intersect</span>
|
||||
<p>Iterates over maps, return a new map of key and value pairs in all given maps.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Keys">Keys</span>
|
||||
<p>Returns a slice of the map's keys.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Keys[K comparable, V any](m map[K]V) []K
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
<p>Merge maps, next key will overwrite previous key.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
<p>Creates an map of whose key in mapA but not in mapB.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
<p>Returns a slice of the map's values.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Values[K comparable, V any](m map[K]V) []V
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
|
||||
}
|
||||
```
|
||||
304
docs/maputil_zh-CN.md
Normal file
304
docs/maputil_zh-CN.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# Maputil
|
||||
maputil包包括一些操作map的函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/maputil.go](https://github.com/duke-git/lancet/blob/main/maputil/maputil.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录:
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## API文档:
|
||||
|
||||
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
<p>对map中的每对key和value执行iteratee函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
fmt.Println(sum) // 10
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
<p>迭代map中的每对key和value, 返回符合predicate函数的key, value</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
res := maputil.Filter(m, isEven)
|
||||
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersect">Intersect</span>
|
||||
<p>多个map的交集操作</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Keys">Keys</span>
|
||||
<p>返回map中所有key的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Keys[K comparable, V any](m map[K]V) []K
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
<p>合并多个maps, 相同的key会被后来的key覆盖</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
<p>返回一个map,其中的key存在于mapA,不存在于mapB.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
<p>返回map中所有value的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Values[K comparable, V any](m map[K]V) []V
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
|
||||
}
|
||||
```
|
||||
552
docs/mathutil.md
552
docs/mathutil.md
@@ -1,50 +1,72 @@
|
||||
# Mathutil
|
||||
|
||||
Package mathutil implements some functions for math calculation.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [Min](#Min)
|
||||
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [AngleToRadian](#AngleToRadian)
|
||||
- [RadianToAngle](#RadianToAngle)
|
||||
- [PointDistance](#PointDistance)
|
||||
- [IsPrime](#IsPrime)
|
||||
- [GCD](#GCD)
|
||||
- [LCM](#LCM)
|
||||
- [Cos](#Cos)
|
||||
- [Sin](#Sin)
|
||||
- [Log](#Log)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
|
||||
|
||||
### <span id="Average">Average</span>
|
||||
<p>Return average value of numbers. Maybe call RoundToFloat to round result.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Average(0, 0)) //0
|
||||
fmt.Println(mathutil.Average(1, 1)) //1
|
||||
avg := mathutil.Average(1.2, 1.4) //1.2999999998
|
||||
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
<p>Calculate x to the nth power.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -52,7 +74,6 @@ import (
|
||||
```go
|
||||
func Exponent(x, n int64) int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -60,18 +81,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
<p>Calculate the nth number of fibonacci sequence.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -79,7 +101,6 @@ func main() {
|
||||
```go
|
||||
func Fibonacci(first, second, n int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -87,20 +108,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
<p>Calculate the factorial of x.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -108,7 +130,6 @@ func main() {
|
||||
```go
|
||||
func Factorial(x uint) uint
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -116,19 +137,74 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
<p>Return max value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Max(0, 0)) //0
|
||||
fmt.Println(mathutil.Max(1, 2, 3)) //3
|
||||
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Min(0, 0)) //0
|
||||
fmt.Println(mathutil.Min(1, 2, 3)) //1
|
||||
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
<p>calculate the percentage of val to total, retain n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -136,7 +212,6 @@ func main() {
|
||||
```go
|
||||
func Percent(val, total float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -144,17 +219,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
<p>Round float up to n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -162,7 +238,6 @@ func main() {
|
||||
```go
|
||||
func RoundToFloat(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -170,20 +245,22 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
<p>Round float up to n decimal places. will return string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -191,7 +268,6 @@ func main() {
|
||||
```go
|
||||
func RoundToString(x float64, n int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -199,20 +275,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
<p>Round float off n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -220,7 +297,6 @@ func main() {
|
||||
```go
|
||||
func TruncRound(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -228,353 +304,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AngleToRadian">AngleToRadian</span>
|
||||
|
||||
<p>Converts angle value to radian value.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func AngleToRadian(angle float64) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.AngleToRadian(45)
|
||||
result2 := mathutil.AngleToRadian(90)
|
||||
result3 := mathutil.AngleToRadian(180)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.7853981633974483
|
||||
// 1.5707963267948966
|
||||
// 3.141592653589793
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RadianToAngle">RadianToAngle</span>
|
||||
|
||||
<p>Converts radian value to angle value.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RadianToAngle(radian float64) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.RadianToAngle(math.Pi)
|
||||
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 180
|
||||
// 90
|
||||
// 45
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PointDistance">PointDistance</span>
|
||||
|
||||
<p>Caculates two points distance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsPrime">IsPrime</span>
|
||||
|
||||
<p>Checks if number is prime number.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsPrime(n int) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.IsPrime(-1)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GCD">GCD</span>
|
||||
|
||||
<p>Return greatest common divisor (GCD) of integers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GCD(integers ...int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.GCD(1, 1)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LCM">LCM</span>
|
||||
|
||||
<p>Return Least Common Multiple (LCM) of integers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LCM(integers ...int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.LCM(1, 1)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Cos">Cos</span>
|
||||
|
||||
<p>Returns the cosine of the radian argument.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Cos(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Cos(0)
|
||||
result2 := mathutil.Cos(90)
|
||||
result3 := mathutil.Cos(180)
|
||||
result4 := mathutil.Cos(math.Pi)
|
||||
result5 := mathutil.Cos(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -0.447
|
||||
// -0.598
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sin">Sin</span>
|
||||
|
||||
<p>Returns the sine of the radian argument.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sin(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sin(0)
|
||||
result2 := mathutil.Sin(90)
|
||||
result3 := mathutil.Sin(180)
|
||||
result4 := mathutil.Sin(math.Pi)
|
||||
result5 := mathutil.Sin(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0.894
|
||||
// -0.801
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Log">Log</span>
|
||||
|
||||
<p>Returns the logarithm of base n.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Log(n, base float64) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 2.32
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,50 +1,70 @@
|
||||
# Mathutil
|
||||
|
||||
mathutil 包实现了一些数学计算的函数.
|
||||
mathutil包实现了一些数学计算的函数.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/v1/mathutil/mathutil.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
- [AngleToRadian](#AngleToRadian)
|
||||
- [RadianToAngle](#RadianToAngle)
|
||||
- [PointDistance](#PointDistance)
|
||||
- [IsPrime](#IsPrime)
|
||||
- [GCD](#GCD)
|
||||
- [LCM](#LCM)
|
||||
- [Cos](#Cos)
|
||||
- [Sin](#Sin)
|
||||
- [Log](#Log)
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [Min](#Min)
|
||||
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
|
||||
### <span id="Average">Average</span>
|
||||
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Average(0, 0)) //0
|
||||
fmt.Println(mathutil.Average(1, 1)) //1
|
||||
avg := mathutil.Average(1.2, 1.4) //1.2999999998
|
||||
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
<p>指数计算(x的n次方)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -52,7 +72,6 @@ import (
|
||||
```go
|
||||
func Exponent(x, n int64) int64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -60,18 +79,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
<p>计算斐波那契数列的第n个数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -79,7 +99,6 @@ func main() {
|
||||
```go
|
||||
func Fibonacci(first, second, n int) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -87,20 +106,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
<p>计算阶乘</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -108,7 +128,6 @@ func main() {
|
||||
```go
|
||||
func Factorial(x uint) uint
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -116,19 +135,73 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
<p>返回参数中的最大数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Max(0, 0)) //0
|
||||
fmt.Println(mathutil.Max(1, 2, 3)) //3
|
||||
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>返回参数中的最小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Min(0, 0)) //0
|
||||
fmt.Println(mathutil.Min(1, 2, 3)) //1
|
||||
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
<p>计算百分比,保留n位小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -136,7 +209,6 @@ func main() {
|
||||
```go
|
||||
func Percent(val, total float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -144,17 +216,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
<p>四舍五入,保留n位小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -162,7 +235,6 @@ func main() {
|
||||
```go
|
||||
func RoundToFloat(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -170,20 +242,22 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
<p>四舍五入,保留n位小数,返回字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -191,7 +265,6 @@ func main() {
|
||||
```go
|
||||
func RoundToString(x float64, n int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -199,20 +272,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
<p>截短n位小数(不进行四舍五入)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -220,7 +294,6 @@ func main() {
|
||||
```go
|
||||
func TruncRound(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -228,356 +301,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AngleToRadian">AngleToRadian</span>
|
||||
|
||||
<p>将角度值转为弧度值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AngleToRadian(angle float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.AngleToRadian(45)
|
||||
result2 := mathutil.AngleToRadian(90)
|
||||
result3 := mathutil.AngleToRadian(180)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.7853981633974483
|
||||
// 1.5707963267948966
|
||||
// 3.141592653589793
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RadianToAngle">RadianToAngle</span>
|
||||
|
||||
<p>将弧度值转为角度值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RadianToAngle(radian float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.RadianToAngle(math.Pi)
|
||||
result2 := mathutil.RadianToAngle(math.Pi / 2)
|
||||
result3 := mathutil.RadianToAngle(math.Pi / 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 180
|
||||
// 90
|
||||
// 45
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="PointDistance">PointDistance</span>
|
||||
|
||||
<p>计算两个坐标点的距离</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func PointDistance(x1, y1, x2, y2 float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.PointDistance(1, 1, 4, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsPrime">IsPrime</span>
|
||||
|
||||
<p>判断质数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsPrime(n int) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.IsPrime(-1)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GCD">GCD</span>
|
||||
|
||||
<p>计算整数最大公约数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GCD(integers ...int) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.GCD(1, 1)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="LCM">LCM</span>
|
||||
|
||||
<p>计算整数最小公倍数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LCM(integers ...int) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.LCM(1, 1)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Cos">Cos</span>
|
||||
|
||||
<p>计算弧度的余弦值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Cos(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Cos(0)
|
||||
result2 := mathutil.Cos(90)
|
||||
result3 := mathutil.Cos(180)
|
||||
result4 := mathutil.Cos(math.Pi)
|
||||
result5 := mathutil.Cos(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -0.447
|
||||
// -0.598
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Sin">Sin</span>
|
||||
|
||||
<p>计算弧度的正弦值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sin(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sin(0)
|
||||
result2 := mathutil.Sin(90)
|
||||
result3 := mathutil.Sin(180)
|
||||
result4 := mathutil.Sin(math.Pi)
|
||||
result5 := mathutil.Sin(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0.894
|
||||
// -0.801
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Log">Log</span>
|
||||
|
||||
<p>计算以base为底n的对数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Log(n, base float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 2.32
|
||||
// 3
|
||||
}
|
||||
```
|
||||
888
docs/netutil.md
888
docs/netutil.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
184
docs/random.md
184
docs/random.md
@@ -1,43 +1,36 @@
|
||||
# Random
|
||||
|
||||
Package random implements some basic functions to generate random int and string.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [RandBytes](#RandBytes)
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [RandUpper](#RandUpper)
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
- [RandBytes](#RandBytes)
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="RandBytes">RandBytes</span>
|
||||
|
||||
### <span id="RandBytes">RandBytes</span>
|
||||
<p>Generate random byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -45,7 +38,6 @@ import (
|
||||
```go
|
||||
func RandBytes(length int) []byte
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -53,17 +45,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randBytes := random.RandBytes(4)
|
||||
fmt.Println(randBytes)
|
||||
randBytes := random.RandBytes(4)
|
||||
fmt.Println(randBytes)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandInt">RandInt</span>
|
||||
|
||||
### <span id="RandInt">RandInt</span>
|
||||
<p>Generate random int between min and max, may contain min, not max.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -71,7 +63,6 @@ func main() {
|
||||
```go
|
||||
func RandInt(min, max int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -79,25 +70,25 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rInt := random.RandInt(1, 10)
|
||||
fmt.Println(rInt)
|
||||
rInt := random.RandInt(1, 10)
|
||||
fmt.Println(rInt)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandString">RandString</span>
|
||||
|
||||
<p>Generate random given length string. only contains letter (a-zA-Z)</p>
|
||||
|
||||
### <span id="RandString">RandInt</span>
|
||||
<p>Generate random given length string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandString(length int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -105,121 +96,19 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr) //pGWsze
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUpper">RandUpper</span>
|
||||
|
||||
<p>Generate a random upper case string</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandUpper(length int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr) //PACWGF
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandLower">RandLower</span>
|
||||
|
||||
<p>Generate a random lower case string</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandLower(length int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandLower(6)
|
||||
fmt.Println(randStr) //siqbew
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumeral">RandNumeral</span>
|
||||
|
||||
<p>Generate a random numeral string</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandNumeral(length int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandNumeral(6)
|
||||
fmt.Println(randStr) //035172
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
|
||||
|
||||
<p>generate a random numeral or letter string</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandNumeralOrLetter(length int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandNumeralOrLetter(6)
|
||||
fmt.Println(randStr) //0aW7cQ
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UUIdV4">UUIdV4</span>
|
||||
|
||||
<p>Generate a random UUID of version 4 according to RFC 4122.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -227,7 +116,6 @@ func main() {
|
||||
```go
|
||||
func UUIdV4() (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -235,40 +123,16 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uuid, err := random.UUIdV4()
|
||||
uuid, err := random.UUIdV4()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(uuid)
|
||||
fmt.Println(uuid)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||
|
||||
<p>Generate a slice of random int of length n that do not repeat.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandUniqueIntSlice(n, min, max int) []int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := RandUniqueIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,43 +1,37 @@
|
||||
# Random
|
||||
|
||||
random 随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/random/random.go](https://github.com/duke-git/lancet/blob/v1/random/random.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/random/random.go](https://github.com/duke-git/lancet/blob/main/random/random.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [RandBytes](#RandBytes)
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
|
||||
- [RandBytes](#RandBytes)
|
||||
- [RandInt](#RandInt)
|
||||
- [RandString](#RandString)
|
||||
- [RandUpper](#RandUpper)
|
||||
- [RandLower](#RandLower)
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
### <span id="RandBytes">RandBytes</span>
|
||||
|
||||
### <span id="RandBytes">RandBytes</span>
|
||||
<p>生成随机字节切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -45,7 +39,6 @@ import (
|
||||
```go
|
||||
func RandBytes(length int) []byte
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -53,17 +46,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randBytes := random.RandBytes(4)
|
||||
fmt.Println(randBytes)
|
||||
randBytes := random.RandBytes(4)
|
||||
fmt.Println(randBytes)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandInt">RandInt</span>
|
||||
|
||||
### <span id="RandInt">RandInt</span>
|
||||
<p>生成随机int, 范围[min, max)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -71,7 +64,6 @@ func main() {
|
||||
```go
|
||||
func RandInt(min, max int) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -79,25 +71,25 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rInt := random.RandInt(1, 10)
|
||||
fmt.Println(rInt)
|
||||
rInt := random.RandInt(1, 10)
|
||||
fmt.Println(rInt)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandString">RandString</span>
|
||||
|
||||
<p>生成给定长度的随机字符串,只包含字母(a-zA-Z)</p>
|
||||
|
||||
### <span id="RandString">RandInt</span>
|
||||
<p>生成随机给定长度的随机字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandString(length int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -105,121 +97,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr) //pGWsze
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUpper">RandUpper</span>
|
||||
|
||||
<p>生成给定长度的随机大写字母字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandUpper(length int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandString(6)
|
||||
fmt.Println(randStr) //PACWGF
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandLower">RandLower</span>
|
||||
|
||||
<p>生成给定长度的随机小写字母字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandLower(length int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandLower(6)
|
||||
fmt.Println(randStr) //siqbew
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumeral">RandNumeral</span>
|
||||
|
||||
<p>生成给定长度的随机数字字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumeral(length int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandNumeral(6)
|
||||
fmt.Println(randStr) //035172
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandNumeralOrLetter">RandNumeralOrLetter</span>
|
||||
|
||||
<p>生成给定长度的随机字符串(数字+字母)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandNumeralOrLetter(length int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
randStr := random.RandNumeralOrLetter(6)
|
||||
fmt.Println(randStr) //0aW7cQ
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UUIdV4">UUIdV4</span>
|
||||
|
||||
<p>生成UUID v4字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -227,7 +116,6 @@ func main() {
|
||||
```go
|
||||
func UUIdV4() (string, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -235,40 +123,16 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uuid, err := random.UUIdV4()
|
||||
uuid, err := random.UUIdV4()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(uuid)
|
||||
fmt.Println(uuid)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||
|
||||
<p>生成一个不重复的长度为n的随机int切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandUniqueIntSlice(n, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := RandUniqueIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
167
docs/retry.md
167
docs/retry.md
@@ -1,39 +1,37 @@
|
||||
# Retry
|
||||
|
||||
Package retry is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [Context](#Context)
|
||||
- [Retry](#Retry)
|
||||
- [RetryFunc](#RetryFunc)
|
||||
- [RetryDuration](#RetryDuration)
|
||||
- [RetryTimes](#RetryTimes)
|
||||
- [Context](#Context)
|
||||
- [Retry](#Retry)
|
||||
- [RetryFunc](#RetryFunc)
|
||||
- [RetryDuration](#RetryDuration)
|
||||
- [RetryTimes](#RetryTimes)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="Context">Context</span>
|
||||
|
||||
### <span id="Context">Context</span>
|
||||
<p>Set retry context config, can cancel the retry with context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -41,42 +39,43 @@ import (
|
||||
```go
|
||||
func Context(ctx context.Context)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"time"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber,
|
||||
retry.RetryDuration(time.Microsecond*50),
|
||||
retry.Context(ctx),
|
||||
)
|
||||
err := retry.Retry(increaseNumber,
|
||||
retry.RetryDuration(time.Microsecond*50),
|
||||
retry.Context(ctx),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err) //retry is cancelled
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err) //retry is cancelled
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryFunc">RetryFunc</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RetryFunc">RetryFunc</span>
|
||||
<p>Function that retry executes.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -84,7 +83,6 @@ func main() {
|
||||
```go
|
||||
type RetryFunc func() error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -94,31 +92,32 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
var increaseNumber retry.RetryFunc
|
||||
increaseNumber = func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber = func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryTimes">RetryTimes</span>
|
||||
|
||||
|
||||
### <span id="RetryTimes">RetryTimes</span>
|
||||
<p>Set times of retry. Default times is 5.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -126,7 +125,6 @@ func main() {
|
||||
```go
|
||||
func RetryTimes(n uint)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -136,28 +134,29 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||
if err != nil {
|
||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||
}
|
||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryDuration">RetryDuration</span>
|
||||
|
||||
|
||||
### <span id="RetryDuration">RetryDuration</span>
|
||||
<p>Set duration of retries. Default duration is 3 second.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -165,7 +164,6 @@ func main() {
|
||||
```go
|
||||
func RetryDuration(d time.Duration)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -175,30 +173,30 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Retry">Retry</span>
|
||||
|
||||
### <span id="Retry">Retry</span>
|
||||
<p>Executes the retryFunc repeatedly until it was successful or canceled by the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -206,7 +204,6 @@ func main() {
|
||||
```go
|
||||
func Retry(retryFunc RetryFunc, opts ...Option) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -216,23 +213,23 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
# Retry
|
||||
|
||||
retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
retry重试执行函数直到函数运行成功或被context cancel。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/retry/retry.go](https://github.com/duke-git/lancet/blob/v1/retry/retry.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/retry/retry.go](https://github.com/duke-git/lancet/blob/main/retry/retry.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Context](#Context)
|
||||
- [Retry](#Retry)
|
||||
- [RetryFunc](#RetryFunc)
|
||||
- [RetryDuration](#RetryDuration)
|
||||
- [RetryTimes](#RetryTimes)
|
||||
|
||||
- [Context](#Context)
|
||||
- [Retry](#Retry)
|
||||
- [RetryFunc](#RetryFunc)
|
||||
- [RetryDuration](#RetryDuration)
|
||||
- [RetryTimes](#RetryTimes)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Document 文档
|
||||
|
||||
## Document文档
|
||||
|
||||
|
||||
### <span id="Context">Context</span>
|
||||
|
||||
<p>设置重试context参数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -41,42 +41,43 @@ import (
|
||||
```go
|
||||
func Context(ctx context.Context)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"lancet-demo/retry"
|
||||
"time"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"lancet-demo/retry"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber,
|
||||
retry.RetryDuration(time.Microsecond*50),
|
||||
retry.Context(ctx),
|
||||
)
|
||||
err := retry.Retry(increaseNumber,
|
||||
retry.RetryDuration(time.Microsecond*50),
|
||||
retry.Context(ctx),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err) //retry is cancelled
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err) //retry is cancelled
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryFunc">RetryFunc</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RetryFunc">RetryFunc</span>
|
||||
<p>被重试执行的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -84,7 +85,6 @@ func main() {
|
||||
```go
|
||||
type RetryFunc func() error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -94,31 +94,32 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
var increaseNumber retry.RetryFunc
|
||||
increaseNumber = func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber = func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryTimes">RetryTimes</span>
|
||||
|
||||
|
||||
### <span id="RetryTimes">RetryTimes</span>
|
||||
<p>设置重试次数,默认5</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -126,7 +127,6 @@ func main() {
|
||||
```go
|
||||
func RetryTimes(n uint)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -136,28 +136,29 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||
err := retry.Retry(increaseNumber, retry.RetryTimes(2))
|
||||
if err != nil {
|
||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||
}
|
||||
log.Fatal(err) //2022/02/01 18:42:25 function main.main.func1 run failed after 2 times retry exit status 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RetryDuration">RetryDuration</span>
|
||||
|
||||
|
||||
### <span id="RetryDuration">RetryDuration</span>
|
||||
<p>设置重试间隔时间,默认3秒</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -165,7 +166,6 @@ func main() {
|
||||
```go
|
||||
func RetryDuration(d time.Duration)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -175,30 +175,30 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Retry">Retry</span>
|
||||
|
||||
### <span id="Retry">Retry</span>
|
||||
<p>重试执行函数retryFunc,直到函数运行成功,或被context停止</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -206,7 +206,6 @@ func main() {
|
||||
```go
|
||||
func Retry(retryFunc RetryFunc, opts ...Option) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -216,23 +215,23 @@ import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"github.com/duke-git/lancet/retry"
|
||||
"github.com/duke-git/lancet/v2/retry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var number int
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
err := retry.Retry(increaseNumber, retry.RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(number) //3
|
||||
}
|
||||
|
||||
1043
docs/slice.md
1043
docs/slice.md
File diff suppressed because it is too large
Load Diff
1043
docs/slice_zh-CN.md
1043
docs/slice_zh-CN.md
File diff suppressed because it is too large
Load Diff
1122
docs/strutil.md
1122
docs/strutil.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
157
docs/system.md
157
docs/system.md
@@ -1,43 +1,41 @@
|
||||
# System
|
||||
|
||||
Package system contains some functions about os, runtime, shell command.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/system"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
|
||||
- [IsWindows](#IsWindows)
|
||||
- [IsLinux](#IsLinux)
|
||||
- [IsMac](#IsMac)
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
- [IsWindows](#IsWindows)
|
||||
- [IsLinux](#IsLinux)
|
||||
- [IsMac](#IsMac)
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
### <span id="IsWindows">IsWindows</span>
|
||||
|
||||
### <span id="IsWindows">IsWindows</span>
|
||||
<p>Check if current os is windows.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -45,23 +43,24 @@ import (
|
||||
```go
|
||||
func IsWindows() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsWindows := system.IsWindows()
|
||||
fmt.Println(isOsWindows)
|
||||
isOsWindows := system.IsWindows()
|
||||
fmt.Println(isOsWindows)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsLinux">IsLinux</span>
|
||||
|
||||
|
||||
|
||||
### <span id="IsLinux">IsLinux</span>
|
||||
<p>Check if current os is linux.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -69,23 +68,23 @@ func main() {
|
||||
```go
|
||||
func IsLinux() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsLinux := system.IsLinux()
|
||||
fmt.Println(isOsLinux)
|
||||
isOsLinux := system.IsLinux()
|
||||
fmt.Println(isOsLinux)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsMac">IsMac</span>
|
||||
|
||||
|
||||
### <span id="IsMac">IsMac</span>
|
||||
<p>Check if current os is macos.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -93,23 +92,23 @@ func main() {
|
||||
```go
|
||||
func IsMac() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
fmt.Println(isOsMac)
|
||||
isOsMac := system.IsMac
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetOsEnv">GetOsEnv</span>
|
||||
|
||||
|
||||
### <span id="GetOsEnv">GetOsEnv</span>
|
||||
<p>Gets the value of the environment variable named by the key.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -117,23 +116,23 @@ func main() {
|
||||
```go
|
||||
func GetOsEnv(key string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fooEnv := system.GetOsEnv("foo")
|
||||
fmt.Println(fooEnv)
|
||||
fooEnv := system.GetOsEnv("foo")
|
||||
fmt.Println(fooEnv)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SetOsEnv">SetOsEnv</span>
|
||||
|
||||
|
||||
### <span id="SetOsEnv">SetOsEnv</span>
|
||||
<p>Sets the value of the environment variable named by the key.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -141,23 +140,24 @@ func main() {
|
||||
```go
|
||||
func SetOsEnv(key, value string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := system.SetOsEnv("foo", "foo_value")
|
||||
fmt.Println(err)
|
||||
err := system.SetOsEnv("foo", "foo_value")
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||
<p>Remove a single environment variable.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -165,25 +165,25 @@ func main() {
|
||||
```go
|
||||
func RemoveOsEnv(key string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := system.RemoveOsEnv("foo")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
err := system.RemoveOsEnv("foo")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||
|
||||
|
||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||
<p>Get env named by the key and compare it with comparedEnv.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -191,71 +191,52 @@ func main() {
|
||||
```go
|
||||
func CompareOsEnv(key, comparedEnv string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
system.SetOsEnv("foo", "foo_value")
|
||||
res := system.CompareOsEnv("foo", "foo_value")
|
||||
fmt.Println(res) //true
|
||||
system.SetOsEnv("foo", "foo_value")
|
||||
res := system.CompareOsEnv("foo", "foo_value")
|
||||
fmt.Println(res) //true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
|
||||
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
<p>use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls", system.WithForeground())
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetOsBits">GetOsBits</span>
|
||||
|
||||
<p>获取当前操作系统位数,返回32或64</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetOsBits() int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
osBit := system.GetOsBits()
|
||||
fmt.Println(osBit)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,43 +1,41 @@
|
||||
# System
|
||||
|
||||
system 包含 os, runtime, shell command 相关函数。
|
||||
system包含os, runtime, shell command相关函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
[https://github.com/duke-git/lancet/blob/v1/system/os.go](https://github.com/duke-git/lancet/blob/v1/system/os.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/system/os.go](https://github.com/duke-git/lancet/blob/main/system/os.go)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/system"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
|
||||
- [IsWindows](#IsWindows)
|
||||
- [IsLinux](#IsLinux)
|
||||
- [IsMac](#IsMac)
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
- [IsWindows](#IsWindows)
|
||||
- [IsLinux](#IsLinux)
|
||||
- [IsMac](#IsMac)
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation 文档
|
||||
## Documentation文档
|
||||
|
||||
|
||||
### <span id="IsWindows">IsWindows</span>
|
||||
|
||||
<p>检查当前操作系统是否是windows</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -45,23 +43,24 @@ import (
|
||||
```go
|
||||
func IsWindows() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsWindows := system.IsWindows()
|
||||
fmt.Println(isOsWindows)
|
||||
isOsWindows := system.IsWindows()
|
||||
fmt.Println(isOsWindows)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsLinux">IsLinux</span>
|
||||
|
||||
|
||||
|
||||
### <span id="IsLinux">IsLinux</span>
|
||||
<p>检查当前操作系统是否是linux</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -69,23 +68,23 @@ func main() {
|
||||
```go
|
||||
func IsLinux() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsLinux := system.IsLinux()
|
||||
fmt.Println(isOsLinux)
|
||||
isOsLinux := system.IsLinux()
|
||||
fmt.Println(isOsLinux)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsMac">IsMac</span>
|
||||
|
||||
|
||||
### <span id="IsMac">IsMac</span>
|
||||
<p>检查当前操作系统是否是macos</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -93,23 +92,23 @@ func main() {
|
||||
```go
|
||||
func IsMac() bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
fmt.Println(isOsMac)
|
||||
isOsMac := system.IsMac
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetOsEnv">GetOsEnv</span>
|
||||
|
||||
|
||||
### <span id="GetOsEnv">GetOsEnv</span>
|
||||
<p>获取key命名的环境变量的值</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -117,23 +116,23 @@ func main() {
|
||||
```go
|
||||
func GetOsEnv(key string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fooEnv := system.GetOsEnv("foo")
|
||||
fmt.Println(fooEnv)
|
||||
fooEnv := system.GetOsEnv("foo")
|
||||
fmt.Println(fooEnv)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="SetOsEnv">SetOsEnv</span>
|
||||
|
||||
|
||||
### <span id="SetOsEnv">SetOsEnv</span>
|
||||
<p>设置由key命名的环境变量的值</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -141,23 +140,24 @@ func main() {
|
||||
```go
|
||||
func SetOsEnv(key, value string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := system.SetOsEnv("foo", "foo_value")
|
||||
fmt.Println(err)
|
||||
err := system.SetOsEnv("foo", "foo_value")
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||
|
||||
|
||||
|
||||
### <span id="RemoveOsEnv">RemoveOsEnv</span>
|
||||
<p>删除单个环境变量</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -165,25 +165,25 @@ func main() {
|
||||
```go
|
||||
func RemoveOsEnv(key string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := system.RemoveOsEnv("foo")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
err := system.RemoveOsEnv("foo")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||
|
||||
|
||||
### <span id="CompareOsEnv">CompareOsEnv</span>
|
||||
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -191,71 +191,52 @@ func main() {
|
||||
```go
|
||||
func CompareOsEnv(key, comparedEnv string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
system.SetOsEnv("foo", "foo_value")
|
||||
res := system.CompareOsEnv("foo", "foo_value")
|
||||
fmt.Println(res) //true
|
||||
system.SetOsEnv("foo", "foo_value")
|
||||
res := system.CompareOsEnv("foo", "foo_value")
|
||||
fmt.Println(res) //true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ExecCommand">ExecCommand</span>
|
||||
|
||||
|
||||
|
||||
### <span id="ExecCommand">CompareOsEnv</span>
|
||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type (
|
||||
Option func(*exec.Cmd)
|
||||
)
|
||||
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
|
||||
func ExecCommand(command string) (stdout, stderr string, err error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
out, errout, err := system.ExecCommand("ls", system.WithForeground())
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
out, errout, err := system.ExecCommand("ls")
|
||||
fmt.Println(out)
|
||||
fmt.Println(errout)
|
||||
fmt.Println(err)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetOsBits">GetOsBits</span>
|
||||
|
||||
<p>Get current os bits, 32bit or 64bit. return 32 or 64</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetOsBits() int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
osBit := system.GetOsBits()
|
||||
fmt.Println(osBit)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
1122
docs/validator.md
1122
docs/validator.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
57
docs/xerror.md
Normal file
57
docs/xerror.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Xerror
|
||||
Package xerror implements helpers for errors.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/xerror/xerror.go](https://github.com/duke-git/lancet/blob/main/xerror/xerror.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
<p>Unwrap if err is nil then it returns a valid value. If err is not nil, Unwrap panics with err.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Unwrap[T any](val T, err error) T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, err := strconv.Atoi("4o2")
|
||||
defer func() {
|
||||
v := recover()
|
||||
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
|
||||
}()
|
||||
|
||||
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||
}
|
||||
```
|
||||
57
docs/xerror_zh-CN.md
Normal file
57
docs/xerror_zh-CN.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Xerror
|
||||
xerror错误处理逻辑封装
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/xerror/xerror.go](https://github.com/duke-git/lancet/blob/main/xerror/xerror.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
```
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
<p>如果err为nil则展开,则它返回一个有效值。 如果err不是nil则Unwrap使用err发生恐慌。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Unwrap[T any](val T, err error) T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/xerror"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, err := strconv.Atoi("4o2")
|
||||
defer func() {
|
||||
v := recover()
|
||||
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
|
||||
}()
|
||||
|
||||
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||
}
|
||||
```
|
||||
346
fileutil/file.go
346
fileutil/file.go
@@ -7,23 +7,14 @@ package fileutil
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/validator"
|
||||
)
|
||||
|
||||
// IsExist checks if a file or directory exists
|
||||
@@ -49,11 +40,6 @@ func CreateFile(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||
func CreateDir(absPath string) error {
|
||||
return os.MkdirAll(absPath, os.ModePerm)
|
||||
}
|
||||
|
||||
// IsDir checks if the path is directory or not
|
||||
func IsDir(path string) bool {
|
||||
file, err := os.Stat(path)
|
||||
@@ -95,7 +81,7 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// ClearFile write empty string to path file
|
||||
//ClearFile write empty string to path file
|
||||
func ClearFile(path string) error {
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
@@ -107,7 +93,7 @@ func ClearFile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadFileToString return string of file content
|
||||
//ReadFileToString return string of file content
|
||||
func ReadFileToString(path string) (string, error) {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -169,15 +155,7 @@ func ListFileNames(path string) ([]string, error) {
|
||||
}
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory
|
||||
func Zip(path string, destPath string) error {
|
||||
if IsDir(path) {
|
||||
return zipFolder(path, destPath)
|
||||
}
|
||||
|
||||
return zipFile(path, destPath)
|
||||
}
|
||||
|
||||
func zipFile(filePath string, destPath string) error {
|
||||
func Zip(fpath string, destPath string) error {
|
||||
zipFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -187,33 +165,7 @@ func zipFile(filePath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
return addFileToArchive1(filePath, archive)
|
||||
}
|
||||
|
||||
func zipFolder(folderPath string, destPath string) error {
|
||||
outFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
w := zip.NewWriter(outFile)
|
||||
|
||||
err = addFileToArchive2(w, folderPath, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFileToArchive1(fpath string, archive *zip.Writer) error {
|
||||
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -229,53 +181,26 @@ func addFileToArchive1(fpath string, archive *zip.Writer) error {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := io.Copy(writer, file); err != nil {
|
||||
_, err = io.Copy(writer, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func addFileToArchive2(w *zip.Writer, basePath, baseInZip string) error {
|
||||
files, err := os.ReadDir(basePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasSuffix(basePath, "/") {
|
||||
basePath = basePath + "/"
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
dat, err := os.ReadFile(basePath + file.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := w.Create(baseInZip + file.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(dat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if file.IsDir() {
|
||||
newBase := basePath + file.Name() + "/"
|
||||
addFileToArchive2(w, newBase, baseInZip+file.Name()+"/")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -289,11 +214,7 @@ func UnZip(zipFile string, destPath string) error {
|
||||
defer zipReader.Close()
|
||||
|
||||
for _, f := range zipReader.File {
|
||||
//issue#62: fix ZipSlip bug
|
||||
path, err := safeFilepathJoin(destPath, f.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(destPath, f.Name)
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(path, os.ModePerm)
|
||||
} else {
|
||||
@@ -322,75 +243,6 @@ func UnZip(zipFile string, destPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
|
||||
// Play: https://go.dev/play/p/cxvaT8TRNQp
|
||||
func ZipAppendEntry(fpath string, destPath string) error {
|
||||
tempFile, err := os.CreateTemp("", "temp.zip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
zipReader, err := zip.OpenReader(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archive := zip.NewWriter(tempFile)
|
||||
|
||||
for _, zipItem := range zipReader.File {
|
||||
zipItemReader, err := zipItem.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header, err := zip.FileInfoHeader(zipItem.FileInfo())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = zipItem.Name
|
||||
targetItem, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(targetItem, zipItemReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = addFileToArchive1(fpath, archive)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = zipReader.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = archive.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tempFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CopyFile(tempFile.Name(), destPath)
|
||||
}
|
||||
|
||||
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
relPath, err := filepath.Rel(".", path2)
|
||||
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||
return "", fmt.Errorf("(zipslip) filepath is unsafe %q: %v", path2, err)
|
||||
}
|
||||
if path1 == "" {
|
||||
path1 = "."
|
||||
}
|
||||
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
||||
}
|
||||
|
||||
// IsLink checks if a file is symbol link or not
|
||||
func IsLink(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
@@ -411,7 +263,7 @@ func FileMode(path string) (fs.FileMode, error) {
|
||||
|
||||
// MiMeType return file mime type
|
||||
// param `file` should be string(file path) or *os.File
|
||||
func MiMeType(file interface{}) string {
|
||||
func MiMeType(file any) string {
|
||||
var mediatype string
|
||||
|
||||
readBuffer := func(f *os.File) ([]byte, error) {
|
||||
@@ -444,169 +296,3 @@ func MiMeType(file interface{}) string {
|
||||
}
|
||||
return mediatype
|
||||
}
|
||||
|
||||
// CurrentPath return current absolute path.
|
||||
func CurrentPath() string {
|
||||
var absPath string
|
||||
_, filename, _, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
absPath = filepath.Dir(filename)
|
||||
}
|
||||
|
||||
return absPath
|
||||
}
|
||||
|
||||
// IsZipFile checks if file is zip or not.
|
||||
func IsZipFile(filepath string) bool {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := make([]byte, 4)
|
||||
if n, err := f.Read(buf); err != nil || n < 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.Equal(buf, []byte("PK\x03\x04"))
|
||||
}
|
||||
|
||||
// FileSize returns file size in bytes.
|
||||
func FileSize(path string) (int64, error) {
|
||||
f, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.Size(), nil
|
||||
}
|
||||
|
||||
// MTime returns file modified time.
|
||||
func MTime(filepath string) (int64, error) {
|
||||
f, err := os.Stat(filepath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.ModTime().Unix(), nil
|
||||
}
|
||||
|
||||
// Sha returns file sha value, param `shaType` should be 1, 256 or 512.
|
||||
func Sha(filepath string, shaType ...int) (string, error) {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
h := sha1.New()
|
||||
if len(shaType) > 0 {
|
||||
if shaType[0] == 1 {
|
||||
h = sha1.New()
|
||||
} else if shaType[0] == 256 {
|
||||
h = sha256.New()
|
||||
} else if shaType[0] == 512 {
|
||||
h = sha512.New()
|
||||
} else {
|
||||
return "", errors.New("param `shaType` should be 1, 256 or 512.")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = io.Copy(h, file)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sha := fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
return sha, nil
|
||||
|
||||
}
|
||||
|
||||
// ReadCsvFile read file content into slice.
|
||||
func ReadCsvFile(filepath string) ([][]string, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
csvReader := csv.NewReader(f)
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// WriteCsvFile write content to target csv file.
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
||||
flag := os.O_RDWR | os.O_CREATE
|
||||
|
||||
if append {
|
||||
flag = flag | os.O_APPEND
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(filepath, flag, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
writer := csv.NewWriter(f)
|
||||
writer.Comma = ','
|
||||
|
||||
return writer.WriteAll(records)
|
||||
}
|
||||
|
||||
// WriteStringToFile write string to target file.
|
||||
func WriteStringToFile(filepath string, content string, append bool) error {
|
||||
flag := os.O_RDWR | os.O_CREATE
|
||||
if append {
|
||||
flag = flag | os.O_APPEND
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(filepath, flag, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(content)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteBytesToFile write bytes to target file.
|
||||
func WriteBytesToFile(filepath string, content []byte) error {
|
||||
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write(content)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadFile get file reader by a url or a local file.
|
||||
func ReadFile(path string) (reader io.ReadCloser, closeFn func(), err error) {
|
||||
switch {
|
||||
case validator.IsUrl(path):
|
||||
resp, err := http.Get(path)
|
||||
if err != nil {
|
||||
return nil, func() {}, err
|
||||
}
|
||||
return resp.Body, func() { resp.Body.Close() }, nil
|
||||
case IsExist(path):
|
||||
reader, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, func() {}, err
|
||||
}
|
||||
return reader, func() { reader.Close() }, nil
|
||||
default:
|
||||
return nil, func() {}, errors.New("unknown file type")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestIsExist(t *testing.T) {
|
||||
@@ -34,27 +33,6 @@ func TestCreateFile(t *testing.T) {
|
||||
os.Remove(f)
|
||||
}
|
||||
|
||||
func TestCreateDir(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCreateDir")
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
dirPath := pwd + "/a/"
|
||||
err = CreateDir(dirPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.Equal(true, IsExist(dirPath))
|
||||
os.Remove(dirPath)
|
||||
assert.Equal(false, IsExist(dirPath))
|
||||
}
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsDir")
|
||||
|
||||
@@ -98,10 +76,10 @@ func TestCopyFile(t *testing.T) {
|
||||
func TestListFileNames(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListFileNames")
|
||||
|
||||
filesInPath, err := ListFileNames("../datetime/")
|
||||
filesInPath, err := ListFileNames("./")
|
||||
assert.IsNil(err)
|
||||
|
||||
expected := []string{"conversion.go", "conversion_test.go", "datetime.go", "datetime_test.go"}
|
||||
expected := []string{"file.go", "file_test.go"}
|
||||
assert.Equal(expected, filesInPath)
|
||||
}
|
||||
|
||||
@@ -183,44 +161,6 @@ func TestZipAndUnZip(t *testing.T) {
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestZipAppendEntry(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestZipAppendEntry")
|
||||
|
||||
zipFile := "./text.zip"
|
||||
err := CopyFile("./testdata/file.go.zip", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
|
||||
_, err = file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
file.Close()
|
||||
|
||||
err = ZipAppendEntry(srcFile, zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = ZipAppendEntry("./testdata", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
err = UnZip(zipFile, unZipPath)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, IsExist("./unzip/text.txt"))
|
||||
assert.Equal(true, IsExist("./unzip/file.go"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestFileMode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileMode")
|
||||
|
||||
@@ -260,167 +200,3 @@ func TestMiMeType(t *testing.T) {
|
||||
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
|
||||
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
|
||||
}
|
||||
|
||||
func TestCurrentPath(t *testing.T) {
|
||||
absPath := CurrentPath()
|
||||
t.Log(absPath)
|
||||
}
|
||||
|
||||
func TestIsZipFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsZipFile")
|
||||
|
||||
assert.Equal(false, IsZipFile("./file.go"))
|
||||
assert.Equal(true, IsZipFile("./testdata/file.go.zip"))
|
||||
}
|
||||
|
||||
func TestFileSize(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileSize")
|
||||
|
||||
size, err := FileSize("./testdata/test.txt")
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(int64(20), size)
|
||||
}
|
||||
|
||||
func TestMTime(t *testing.T) {
|
||||
// assert := internal.NewAssert(t, "TestMTime")
|
||||
|
||||
// mtime, err := MTime("./testdata/test.txt")
|
||||
|
||||
// assert.IsNil(err)
|
||||
// assert.Equal(int64(1682478195), mtime)
|
||||
}
|
||||
|
||||
func TestSha(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSha")
|
||||
|
||||
sha1, err := Sha("./testdata/test.txt", 1)
|
||||
assert.IsNil(err)
|
||||
|
||||
sha256, err := Sha("./testdata/test.txt", 256)
|
||||
assert.IsNil(err)
|
||||
|
||||
sha512, err := Sha("./testdata/test.txt", 512)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal("dda3cf10c5a6ff6c6659a497bf7261b287af2bc7", sha1)
|
||||
assert.Equal("aa6d0a3fbc3442c228d606da09e0c1dc98c69a1cac3da1909199e0266171df35", sha256)
|
||||
assert.Equal("d22aba2a1b7a2e2f512756255cc1c3708905646920cb1eb95e45b531ba74774dbbb89baebf1f716220eb9cf4908f1cfc5b2a01267704d9a59f59d77cab609870", sha512)
|
||||
}
|
||||
|
||||
func TestReadCsvFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReadCsvFile")
|
||||
|
||||
content, err := ReadCsvFile("./testdata/demo.csv")
|
||||
t.Log(content)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(3, len(content))
|
||||
assert.Equal(3, len(content[0]))
|
||||
assert.Equal("Bob", content[0][0])
|
||||
}
|
||||
|
||||
func TestWriteCsvFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteCsvFile")
|
||||
|
||||
csvFilePath := "./testdata/test1.csv"
|
||||
content := [][]string{
|
||||
{"Lili", "22", "female"},
|
||||
{"Jim", "21", "male"},
|
||||
}
|
||||
|
||||
err := WriteCsvFile(csvFilePath, content, false)
|
||||
assert.IsNil(err)
|
||||
|
||||
readContent, err := ReadCsvFile(csvFilePath)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(2, len(readContent))
|
||||
assert.Equal(3, len(readContent[0]))
|
||||
assert.Equal("Lili", content[0][0])
|
||||
}
|
||||
|
||||
func TestWriteStringToFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
||||
|
||||
filepath := "./test.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteStringToFile(filepath, "hello", false)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content1, err := ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
err = WriteStringToFile(filepath, " world", true)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content2, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
assert.Equal("hello", content1)
|
||||
assert.Equal("hello world", string(content2))
|
||||
|
||||
os.Remove(filepath)
|
||||
}
|
||||
|
||||
func TestWriteBytesToFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteBytesToFile")
|
||||
|
||||
filepath := "./bytes.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteBytesToFile(filepath, []byte("hello"))
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
assert.Equal("hello", string(content))
|
||||
|
||||
os.Remove(filepath)
|
||||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
reader, close, err := ReadFile("https://httpbin.org/robots.txt")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
defer close()
|
||||
|
||||
dat, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
want := `User-agent: *
|
||||
Disallow: /deny
|
||||
`
|
||||
internal.NewAssert(t, "TestReadFile").Equal(want, string(dat))
|
||||
}
|
||||
|
||||
3
fileutil/testdata/demo.csv
vendored
3
fileutil/testdata/demo.csv
vendored
@@ -1,3 +0,0 @@
|
||||
Bob, 12, male
|
||||
Duke, 14, male
|
||||
Lucy, 16, female
|
||||
|
BIN
fileutil/testdata/file.go.zip
vendored
BIN
fileutil/testdata/file.go.zip
vendored
Binary file not shown.
1
fileutil/testdata/test.txt
vendored
1
fileutil/testdata/test.txt
vendored
@@ -1 +0,0 @@
|
||||
this is a test file.
|
||||
3
fileutil/testdata/test1.csv
vendored
3
fileutil/testdata/test1.csv
vendored
@@ -1,3 +0,0 @@
|
||||
Lili,22,female
|
||||
Jim,21,male
|
||||
|
||||
|
@@ -4,176 +4,14 @@
|
||||
// Package formatter implements some functions to format string, struct.
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
import "strings"
|
||||
|
||||
"github.com/duke-git/lancet/convertor"
|
||||
"github.com/duke-git/lancet/strutil"
|
||||
"github.com/duke-git/lancet/validator"
|
||||
)
|
||||
|
||||
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
||||
// if value is invalid number string eg "aa", return empty string
|
||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||
func Comma(value interface{}, symbol string) string {
|
||||
if validator.IsInt(value) {
|
||||
v, err := convertor.ToInt(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaInt(v)
|
||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
||||
func Comma(v any, symbol string) string {
|
||||
s := numString(v)
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
if validator.IsFloat(value) {
|
||||
v, err := convertor.ToFloat(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return symbol + commaFloat(v)
|
||||
}
|
||||
|
||||
if strutil.IsString(value) {
|
||||
v := fmt.Sprintf("%v", value)
|
||||
if validator.IsNumberStr(v) {
|
||||
return symbol + commaStr(v)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Pretty data to JSON string.
|
||||
func Pretty(v interface{}) (string, error) {
|
||||
out, err := json.MarshalIndent(v, "", " ")
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
// PrettyToWriter pretty encode data to writer.
|
||||
func PrettyToWriter(v interface{}, out io.Writer) error {
|
||||
enc := json.NewEncoder(out)
|
||||
enc.SetIndent("", " ")
|
||||
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// http://en.wikipedia.org/wiki/Binary_prefix
|
||||
const (
|
||||
// Decimal
|
||||
UnitB = 1
|
||||
UnitKB = 1000
|
||||
UnitMB = 1000 * UnitKB
|
||||
UnitGB = 1000 * UnitMB
|
||||
UnitTB = 1000 * UnitGB
|
||||
UnitPB = 1000 * UnitTB
|
||||
UnitEB = 1000 * UnitPB
|
||||
|
||||
// Binary
|
||||
UnitBiB = 1
|
||||
UnitKiB = 1024
|
||||
UnitMiB = 1024 * UnitKiB
|
||||
UnitGiB = 1024 * UnitMiB
|
||||
UnitTiB = 1024 * UnitGiB
|
||||
UnitPiB = 1024 * UnitTiB
|
||||
UnitEiB = 1024 * UnitPiB
|
||||
)
|
||||
|
||||
// type byteUnitMap map[byte]int64
|
||||
|
||||
var (
|
||||
decimalByteMap = map[string]uint64{
|
||||
"b": UnitB,
|
||||
"kb": UnitKB,
|
||||
"mb": UnitMB,
|
||||
"gb": UnitGB,
|
||||
"tb": UnitTB,
|
||||
"pb": UnitPB,
|
||||
"eb": UnitEB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitB,
|
||||
"k": UnitKB,
|
||||
"m": UnitMB,
|
||||
"g": UnitGB,
|
||||
"t": UnitTB,
|
||||
"p": UnitPB,
|
||||
"e": UnitEB,
|
||||
}
|
||||
|
||||
binaryByteMap = map[string]uint64{
|
||||
"bi": UnitBiB,
|
||||
"kib": UnitKiB,
|
||||
"mib": UnitMiB,
|
||||
"gib": UnitGiB,
|
||||
"tib": UnitTiB,
|
||||
"pib": UnitPiB,
|
||||
"eib": UnitEiB,
|
||||
|
||||
// Without suffix
|
||||
"": UnitBiB,
|
||||
"ki": UnitKiB,
|
||||
"mi": UnitMiB,
|
||||
"gi": UnitGiB,
|
||||
"ti": UnitTiB,
|
||||
"pi": UnitPiB,
|
||||
"ei": UnitEiB,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
decimalByteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||
binaryByteUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||
)
|
||||
|
||||
// DecimalBytes returns a human readable byte size under decimal standard (base 1000)
|
||||
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||
// Play: https://go.dev/play/p/FPXs1suwRcs
|
||||
func DecimalBytes(size float64, precision ...int) string {
|
||||
p := 5
|
||||
if len(precision) > 0 {
|
||||
p = precision[0] + 1
|
||||
}
|
||||
size, unit := calculateByteSize(size, 1000.0, decimalByteUnits)
|
||||
|
||||
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||
}
|
||||
|
||||
// BinaryBytes returns a human-readable byte size under binary standard (base 1024)
|
||||
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
|
||||
func BinaryBytes(size float64, precision ...int) string {
|
||||
p := 5
|
||||
if len(precision) > 0 {
|
||||
p = precision[0] + 1
|
||||
}
|
||||
size, unit := calculateByteSize(size, 1024.0, binaryByteUnits)
|
||||
|
||||
return fmt.Sprintf("%.*g%s", p, size, unit)
|
||||
}
|
||||
|
||||
func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) {
|
||||
i := 0
|
||||
unitsLimit := len(byteUnits) - 1
|
||||
for size >= base && i < unitsLimit {
|
||||
size = size / base
|
||||
i++
|
||||
}
|
||||
return size, byteUnits[i]
|
||||
}
|
||||
|
||||
// ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000).
|
||||
// ParseDecimalBytes("42 MB") -> 42000000, nil
|
||||
func ParseDecimalBytes(size string) (uint64, error) {
|
||||
return parseBytes(size, "decimal")
|
||||
}
|
||||
|
||||
// ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024).
|
||||
// ParseBinaryBytes("42 mib") -> 44040192, nil
|
||||
func ParseBinaryBytes(size string) (uint64, error) {
|
||||
return parseBytes(size, "binary")
|
||||
return symbol + commaString(s)
|
||||
}
|
||||
|
||||
@@ -1,134 +1,40 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// see https://github.com/dustin/go-humanize/blob/master/comma.go
|
||||
func commaInt(v int64) string {
|
||||
sign := ""
|
||||
|
||||
// Min int64 can't be negated to a usable value, so it has to be special cased.
|
||||
if v == math.MinInt64 {
|
||||
return "-9,223,372,036,854,775,808"
|
||||
}
|
||||
|
||||
if v < 0 {
|
||||
sign = "-"
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
parts := []string{"", "", "", "", "", "", ""}
|
||||
j := len(parts) - 1
|
||||
|
||||
for v > 999 {
|
||||
parts[j] = strconv.FormatInt(v%1000, 10)
|
||||
switch len(parts[j]) {
|
||||
case 2:
|
||||
parts[j] = "0" + parts[j]
|
||||
case 1:
|
||||
parts[j] = "00" + parts[j]
|
||||
}
|
||||
v = v / 1000
|
||||
j--
|
||||
}
|
||||
parts[j] = strconv.Itoa(int(v))
|
||||
return sign + strings.Join(parts[j:], ",")
|
||||
}
|
||||
|
||||
func commaFloat(v float64) string {
|
||||
buf := &bytes.Buffer{}
|
||||
if v < 0 {
|
||||
buf.Write([]byte{'-'})
|
||||
v = 0 - v
|
||||
}
|
||||
|
||||
comma := []byte{','}
|
||||
|
||||
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
|
||||
pos := 0
|
||||
if len(parts[0])%3 != 0 {
|
||||
pos += len(parts[0]) % 3
|
||||
buf.WriteString(parts[0][:pos])
|
||||
buf.Write(comma)
|
||||
}
|
||||
for ; pos < len(parts[0]); pos += 3 {
|
||||
buf.WriteString(parts[0][pos : pos+3])
|
||||
buf.Write(comma)
|
||||
}
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
|
||||
if len(parts) > 1 {
|
||||
buf.Write([]byte{'.'})
|
||||
buf.WriteString(parts[1])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func commaStr(s string) string {
|
||||
dotIndex := strings.Index(s, ".")
|
||||
if dotIndex != -1 {
|
||||
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
|
||||
}
|
||||
|
||||
return commaStrRecursive(s)
|
||||
}
|
||||
|
||||
func commaStrRecursive(s string) string {
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
// see https://github.com/dustin/go-humanize/blob/master/bytes.go
|
||||
func parseBytes(s string, kind string) (uint64, error) {
|
||||
lastDigit := 0
|
||||
hasComma := false
|
||||
for _, r := range s {
|
||||
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
||||
break
|
||||
}
|
||||
if r == ',' {
|
||||
hasComma = true
|
||||
}
|
||||
lastDigit++
|
||||
}
|
||||
|
||||
num := s[:lastDigit]
|
||||
if hasComma {
|
||||
num = strings.Replace(num, ",", "", -1)
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(num, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
|
||||
|
||||
if kind == "decimal" {
|
||||
if m, ok := decimalByteMap[extra]; ok {
|
||||
f *= float64(m)
|
||||
if f >= math.MaxUint64 {
|
||||
return 0, fmt.Errorf("too large: %v", s)
|
||||
func numString(value any) string {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value)
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err == nil {
|
||||
return sv
|
||||
}
|
||||
}
|
||||
return uint64(f), nil
|
||||
}
|
||||
} else {
|
||||
if m, ok := binaryByteMap[extra]; ok {
|
||||
f *= float64(m)
|
||||
if f >= math.MaxUint64 {
|
||||
return 0, fmt.Errorf("too large: %v", s)
|
||||
}
|
||||
return uint64(f), nil
|
||||
}
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("unhandled size name: %v", extra)
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestComma(t *testing.T) {
|
||||
@@ -13,148 +12,12 @@ func TestComma(t *testing.T) {
|
||||
assert.Equal("", Comma("", ""))
|
||||
assert.Equal("", Comma("aa", ""))
|
||||
assert.Equal("", Comma("aa.a", ""))
|
||||
assert.Equal("", Comma([]int{1}, ""))
|
||||
assert.Equal("123", Comma("123", ""))
|
||||
assert.Equal("12,345", Comma("12345", ""))
|
||||
assert.Equal("12,345.6789", Comma("12345.6789", ""))
|
||||
assert.Equal("123,456,789,000", Comma("123456789000", ""))
|
||||
assert.Equal("12,345,678.9", Comma("12345678.9", ""))
|
||||
|
||||
assert.Equal("12,345", Comma(12345, ""))
|
||||
assert.Equal("$12,345", Comma(12345, "$"))
|
||||
assert.Equal("¥12,345", Comma(12345, "¥"))
|
||||
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
||||
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
|
||||
assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||
assert.Equal("123,456,789,000", Comma(123456789000, ""))
|
||||
}
|
||||
|
||||
func TestPretty(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPretty")
|
||||
|
||||
cases := []interface{}{
|
||||
"",
|
||||
"abc",
|
||||
123,
|
||||
[]string{"a", "b", "c"},
|
||||
map[string]int{"a": 1},
|
||||
struct {
|
||||
Abc int `json:"abc"`
|
||||
}{Abc: 123},
|
||||
}
|
||||
|
||||
expects := []string{
|
||||
"\"\"",
|
||||
`"abc"`,
|
||||
"123",
|
||||
"[\n \"a\",\n \"b\",\n \"c\"\n]",
|
||||
"{\n \"a\": 1\n}",
|
||||
"{\n \"abc\": 123\n}",
|
||||
}
|
||||
|
||||
for i, v := range cases {
|
||||
result, err := Pretty(v)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
t.Log("result -> ", result)
|
||||
assert.Equal(expects[i], result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrettyToWriter(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPrettyToWriter")
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Aage uint `json:"age"`
|
||||
}
|
||||
user := User{Name: "King", Aage: 10000}
|
||||
|
||||
expects := "{\n \"name\": \"King\",\n \"age\": 10000\n}\n"
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := PrettyToWriter(user, buf)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(expects, buf.String())
|
||||
}
|
||||
|
||||
func TestDecimalBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDecimalBytes")
|
||||
|
||||
assert.Equal("1KB", DecimalBytes(1000))
|
||||
assert.Equal("1.024KB", DecimalBytes(1024))
|
||||
assert.Equal("1.2346MB", DecimalBytes(1234567))
|
||||
assert.Equal("1.235MB", DecimalBytes(1234567, 3))
|
||||
assert.Equal("1.123GB", DecimalBytes(float64(1.123*UnitGB)))
|
||||
assert.Equal("2.123TB", DecimalBytes(float64(2.123*UnitTB)))
|
||||
assert.Equal("3.123PB", DecimalBytes(float64(3.123*UnitPB)))
|
||||
assert.Equal("4.123EB", DecimalBytes(float64(4.123*UnitEB)))
|
||||
assert.Equal("1EB", DecimalBytes(float64(1000*UnitPB)))
|
||||
}
|
||||
|
||||
func TestBinaryBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBinaryBytes")
|
||||
|
||||
assert.Equal("1KiB", BinaryBytes(1024))
|
||||
assert.Equal("1MiB", BinaryBytes(1024*1024))
|
||||
assert.Equal("1.1774MiB", BinaryBytes(1234567))
|
||||
assert.Equal("1.18MiB", BinaryBytes(1234567, 2))
|
||||
}
|
||||
|
||||
func TestParseDecimalBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestParseDecimalBytes")
|
||||
|
||||
cases := map[string]uint64{
|
||||
"12": uint64(12),
|
||||
"12 k": uint64(12000),
|
||||
"12 kb": uint64(12000),
|
||||
"12kb": uint64(12000),
|
||||
"12k": uint64(12000),
|
||||
"12K": uint64(12000),
|
||||
"12KB": uint64(12000),
|
||||
"12 K": uint64(12000),
|
||||
"12 KB": uint64(12000),
|
||||
"12 Kb": uint64(12000),
|
||||
"12 kB": uint64(12000),
|
||||
"12.2 KB": uint64(12200),
|
||||
}
|
||||
|
||||
for k, v := range cases {
|
||||
result, err := ParseDecimalBytes(k)
|
||||
assert.Equal(v, result)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
_, err := ParseDecimalBytes("12 AB")
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
func TestParseBinaryBytes(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestParseBinaryBytes")
|
||||
|
||||
cases := map[string]uint64{
|
||||
"12": uint64(12),
|
||||
"12 ki": uint64(12288),
|
||||
"12 kib": uint64(12288),
|
||||
"12kib": uint64(12288),
|
||||
"12ki": uint64(12288),
|
||||
"12KI": uint64(12288),
|
||||
"12KIB": uint64(12288),
|
||||
"12KiB": uint64(12288),
|
||||
"12 Ki": uint64(12288),
|
||||
"12 KiB": uint64(12288),
|
||||
"12 Kib": uint64(12288),
|
||||
"12 kiB": uint64(12288),
|
||||
"12.2 KiB": uint64(12492),
|
||||
}
|
||||
|
||||
for k, v := range cases {
|
||||
result, err := ParseBinaryBytes(k)
|
||||
assert.Equal(v, result)
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
_, err := ParseDecimalBytes("12 AB")
|
||||
assert.IsNotNil(err)
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
)
|
||||
|
||||
// After creates a function that invokes func once it's called n or more times
|
||||
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
return func(args ...interface{}) []reflect.Value {
|
||||
return func(args ...any) []reflect.Value {
|
||||
n--
|
||||
if n < 1 {
|
||||
return unsafeInvokeFunc(fn, args...)
|
||||
@@ -24,11 +24,11 @@ func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||
}
|
||||
|
||||
// Before creates a function that invokes func once it's called less than n times
|
||||
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
var res []reflect.Value
|
||||
return func(args ...interface{}) []reflect.Value {
|
||||
return func(args ...any) []reflect.Value {
|
||||
if n > 0 {
|
||||
res = unsafeInvokeFunc(fn, args...)
|
||||
}
|
||||
@@ -40,20 +40,20 @@ func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Fn is for curry function which is func(...interface{}) interface{}
|
||||
type Fn func(...interface{}) interface{}
|
||||
// Fn is for curry function which is func(...any) any
|
||||
type Fn func(...any) any
|
||||
|
||||
// Curry make a curry function
|
||||
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} {
|
||||
return func(values ...interface{}) interface{} {
|
||||
v := append([]interface{}{i}, values...)
|
||||
func (f Fn) Curry(i any) func(...any) any {
|
||||
return func(values ...any) any {
|
||||
v := append([]any{i}, values...)
|
||||
return f(v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Compose compose the functions from right to left
|
||||
func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) interface{} {
|
||||
return func(s ...interface{}) interface{} {
|
||||
func Compose(fnList ...func(...any) any) func(...any) any {
|
||||
return func(s ...any) any {
|
||||
f := fnList[0]
|
||||
restFn := fnList[1:]
|
||||
|
||||
@@ -66,7 +66,7 @@ func Compose(fnList ...func(...interface{}) interface{}) func(...interface{}) in
|
||||
}
|
||||
|
||||
// Delay make the function execution after delayed time
|
||||
func Delay(delay time.Duration, fn interface{}, args ...interface{}) {
|
||||
func Delay(delay time.Duration, fn any, args ...any) {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
@@ -95,7 +95,7 @@ func Debounced(fn func(), duration time.Duration) func() {
|
||||
}
|
||||
|
||||
// Schedule invoke function every duration time, util close the returned bool chan
|
||||
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
@@ -113,15 +113,3 @@ func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
||||
|
||||
return quit
|
||||
}
|
||||
|
||||
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
// the functions one by one.
|
||||
func Pipeline(funcs ...func(interface{}) interface{}) func(interface{}) interface{} {
|
||||
return func(arg interface{}) (result interface{}) {
|
||||
result = arg
|
||||
for _, fn := range funcs {
|
||||
result = fn(result)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||
func invokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := functionValue(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
@@ -14,7 +14,7 @@ func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
@@ -23,7 +23,7 @@ func unsafeInvokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function interface{}) reflect.Value {
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
@@ -31,7 +31,7 @@ func functionValue(function interface{}) reflect.Value {
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function interface{}) {
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user